Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Education
Artikulate
Commits
869f4a16
Commit
869f4a16
authored
Jul 08, 2019
by
Andreas Cord-Landwehr
Browse files
Remove obsolete LanguageResource and ResourceInterface
parent
e9a26bf3
Changes
17
Hide whitespace changes
Inline
Side-by-side
autotests/unittests/courseresource/test_courseresource.cpp
View file @
869f4a16
...
...
@@ -24,7 +24,6 @@
#include "core/unit.h"
#include "core/phrase.h"
#include "core/phonemegroup.h"
#include "core/resources/languageresource.h"
#include "core/resources/courseresource.h"
#include <QTest>
...
...
autotests/unittests/editablecourseresource/test_editablecourseresource.cpp
View file @
869f4a16
...
...
@@ -24,7 +24,6 @@
#include "core/unit.h"
#include "core/phrase.h"
#include "core/resources/courseparser.h"
#include "core/resources/languageresource.h"
#include "core/resources/editablecourseresource.h"
#include <memory>
...
...
autotests/unittests/skeletonresource/test_skeletonresource.cpp
View file @
869f4a16
...
...
@@ -23,7 +23,6 @@
#include "core/language.h"
#include "core/unit.h"
#include "core/phrase.h"
#include "core/resources/languageresource.h"
#include "core/resources/skeletonresource.h"
#include <QTest>
...
...
src/CMakeLists.txt
View file @
869f4a16
...
...
@@ -57,8 +57,6 @@ set(artikulateCore_SRCS
core/trainingaction.cpp
core/trainingactionicon.cpp
core/trainingsession.cpp
core/resources/resourceinterface.cpp
core/resources/languageresource.cpp
core/resources/courseparser.cpp
core/resources/courseresource.cpp
core/resources/editablecourseresource.cpp
...
...
src/core/contributorrepository.cpp
View file @
869f4a16
...
...
@@ -25,7 +25,6 @@
#include "phrase.h"
#include "phoneme.h"
#include "phonemegroup.h"
#include "resources/languageresource.h"
#include "resources/editablecourseresource.h"
#include "resources/skeletonresource.h"
#include "liblearnerprofile/src/profilemanager.h"
...
...
@@ -44,16 +43,7 @@ ContributorRepository::ContributorRepository()
loadLanguageResources
();
}
ContributorRepository
::~
ContributorRepository
()
{
for
(
auto
skeleton
:
m_skeletonResources
)
{
skeleton
->
deleteLater
();
}
m_skeletonResources
.
clear
();
for
(
auto
language
:
m_languageResources
)
{
language
->
deleteLater
();
}
}
ContributorRepository
::~
ContributorRepository
()
=
default
;
void
ContributorRepository
::
loadLanguageResources
()
{
...
...
@@ -107,12 +97,12 @@ void ContributorRepository::addLanguage(const QUrl &languageFile)
return
;
}
std
::
shared_ptr
<
LanguageResource
>
resource
(
new
Language
Resourc
e
(
languageFile
)
)
;
auto
language
=
Language
::
creat
e
(
languageFile
);
emit
languageResourceAboutToBeAdded
(
resource
.
get
()
,
m_language
Resource
s
.
count
());
m_language
Resource
s
.
append
(
resourc
e
);
emit
languageResourceAboutToBeAdded
(
language
,
m_languages
.
count
());
m_languages
.
append
(
languag
e
);
m_loadedResources
.
append
(
languageFile
.
toLocalFile
());
m_courses
.
insert
(
resource
->
identifier
(),
QVector
<
std
::
shared_ptr
<
EditableCourseResource
>>
());
m_courses
.
insert
(
language
->
id
(),
QVector
<
std
::
shared_ptr
<
EditableCourseResource
>>
());
emit
languageResourceAdded
();
}
...
...
@@ -128,17 +118,13 @@ void ContributorRepository::setStorageLocation(const QString &path)
QVector
<
std
::
shared_ptr
<
Language
>>
ContributorRepository
::
languages
()
const
{
QVector
<
std
::
shared_ptr
<
Language
>>
languages
;
for
(
auto
resourse
:
m_languageResources
)
{
languages
.
append
(
resourse
->
language
());
}
return
languages
;
return
m_languages
;
}
std
::
shared_ptr
<
Language
>
ContributorRepository
::
language
(
int
index
)
const
{
Q_ASSERT
(
index
>=
0
&&
index
<
m_language
Resource
s
.
count
());
return
m_language
Resource
s
.
at
(
index
)
->
language
()
;
Q_ASSERT
(
index
>=
0
&&
index
<
m_languages
.
count
());
return
m_languages
.
at
(
index
);
}
Language
*
ContributorRepository
::
language
(
LearnerProfile
::
LearningGoal
*
learningGoal
)
const
...
...
@@ -150,9 +136,9 @@ Language * ContributorRepository::language(LearnerProfile::LearningGoal *learnin
qCritical
()
<<
"Cannot translate non-language learning goal to language"
;
return
nullptr
;
}
for
(
auto
resourc
e
:
m_language
Resource
s
)
{
if
(
resource
->
identifier
()
==
learningGoal
->
identifier
())
{
return
resource
->
language
()
.
get
();
for
(
auto
languag
e
:
m_languages
)
{
if
(
language
->
id
()
==
learningGoal
->
identifier
())
{
return
language
.
get
();
}
}
qCritical
()
<<
"No language registered with identifier "
<<
learningGoal
->
identifier
()
<<
": aborting"
;
...
...
src/core/contributorrepository.h
View file @
869f4a16
...
...
@@ -170,7 +170,7 @@ public:
Q_SIGNALS:
void
languageResourceAdded
();
void
languageResourceAboutToBeAdded
(
LanguageResource
*
,
int
);
void
languageResourceAboutToBeAdded
(
std
::
shared_ptr
<
Language
>
,
int
);
void
languageResourceRemoved
();
void
languageResourceAboutToBeRemoved
(
int
);
void
repositoryChanged
();
...
...
@@ -187,7 +187,7 @@ private:
*/
void
loadLanguageResources
();
QString
m_storageLocation
;
QVector
<
std
::
shared_ptr
<
Language
Resource
>>
m_language
Resource
s
;
QVector
<
std
::
shared_ptr
<
Language
>>
m_languages
;
QMap
<
QString
,
QVector
<
std
::
shared_ptr
<
EditableCourseResource
>>
>
m_courses
;
//!> (language-id, course-resource)
QVector
<
std
::
shared_ptr
<
IEditableCourse
>>
m_skeletonResources
;
QStringList
m_loadedResources
;
...
...
src/core/editorsession.cpp
View file @
869f4a16
...
...
@@ -22,7 +22,6 @@
#include "core/language.h"
#include "core/resources/editablecourseresource.h"
#include "core/resources/skeletonresource.h"
#include "core/resources/languageresource.h"
#include "core/unit.h"
#include "core/phrase.h"
#include "core/contributorrepository.h"
...
...
src/core/language.cpp
View file @
869f4a16
...
...
@@ -25,6 +25,48 @@
#include "artikulate_debug.h"
#include <KLocalizedString>
#include <QQmlEngine>
#include <QXmlSchema>
#include <QDomDocument>
#include "resources/courseparser.h"
std
::
shared_ptr
<
Language
>
Language
::
create
(
QUrl
file
)
{
QXmlSchema
schema
=
CourseParser
::
loadXmlSchema
(
QStringLiteral
(
"language"
));
if
(
!
schema
.
isValid
())
{
return
nullptr
;
}
QDomDocument
document
=
CourseParser
::
loadDomDocument
(
file
,
schema
);
if
(
document
.
isNull
())
{
qCWarning
(
ARTIKULATE_LOG
)
<<
"Could not parse document "
<<
file
.
toLocalFile
()
<<
", aborting."
;
return
nullptr
;
}
QDomElement
root
(
document
.
documentElement
());
auto
language
=
std
::
shared_ptr
<
Language
>
(
new
Language
());
language
->
setFile
(
file
);
language
->
setId
(
root
.
firstChildElement
(
QStringLiteral
(
"id"
)).
text
());
language
->
setTitle
(
root
.
firstChildElement
(
QStringLiteral
(
"title"
)).
text
());
language
->
seti18nTitle
(
root
.
firstChildElement
(
QStringLiteral
(
"i18nTitle"
)).
text
());
// create phoneme groups
for
(
QDomElement
groupNode
=
root
.
firstChildElement
(
QStringLiteral
(
"phonemeGroups"
)).
firstChildElement
();
!
groupNode
.
isNull
();
groupNode
=
groupNode
.
nextSiblingElement
())
{
auto
group
=
language
->
addPhonemeGroup
(
groupNode
.
firstChildElement
(
QStringLiteral
(
"id"
)).
text
(),
groupNode
.
firstChildElement
(
QStringLiteral
(
"title"
)).
text
());
group
->
setDescription
(
groupNode
.
attribute
(
QStringLiteral
(
"description"
)));
// register phonemes
for
(
QDomElement
phonemeNode
=
groupNode
.
firstChildElement
(
QStringLiteral
(
"phonemes"
)).
firstChildElement
();
!
phonemeNode
.
isNull
();
phonemeNode
=
phonemeNode
.
nextSiblingElement
())
{
group
->
addPhoneme
(
phonemeNode
.
firstChildElement
(
QStringLiteral
(
"id"
)).
text
(),
phonemeNode
.
firstChildElement
(
QStringLiteral
(
"title"
)).
text
());
}
}
return
language
;
}
Language
::
Language
()
:
QObject
()
...
...
src/core/language.h
View file @
869f4a16
...
...
@@ -42,6 +42,8 @@ public:
explicit
Language
();
~
Language
();
static
std
::
shared_ptr
<
Language
>
create
(
QUrl
file
);
QString
id
()
const
;
void
setId
(
const
QString
&
id
);
QString
title
()
const
;
...
...
src/core/resourcerepository.cpp
View file @
869f4a16
...
...
@@ -21,7 +21,6 @@
#include "resourcerepository.h"
#include "artikulate_debug.h"
#include "resources/courseresource.h"
#include "resources/languageresource.h"
#include "core/language.h"
#include <QStandardPaths>
#include <QUrl>
...
...
@@ -86,7 +85,7 @@ QVector<std::shared_ptr<Language>> ResourceRepository::languages() const
if
(
language
==
nullptr
)
{
continue
;
}
languages
.
append
(
language
->
language
()
);
languages
.
append
(
language
);
}
return
languages
;
}
...
...
@@ -94,7 +93,7 @@ QVector<std::shared_ptr<Language>> ResourceRepository::languages() const
Language
*
ResourceRepository
::
language
(
const
QString
&
id
)
const
{
if
(
m_languages
.
contains
(
id
))
{
return
m_languages
.
value
(
id
)
->
language
()
.
get
();
return
m_languages
.
value
(
id
).
get
();
}
return
nullptr
;
}
...
...
@@ -146,17 +145,15 @@ bool ResourceRepository::loadCourse(const QString &resourceFile)
bool
ResourceRepository
::
loadLanguage
(
const
QString
&
resourceFile
)
{
std
::
shared_ptr
<
LanguageResource
>
resource
(
new
Language
Resourc
e
(
QUrl
::
fromLocalFile
(
resourceFile
))
)
;
if
(
!
resourc
e
)
{
auto
language
=
Language
::
creat
e
(
QUrl
::
fromLocalFile
(
resourceFile
));
if
(
!
languag
e
)
{
qCWarning
(
ARTIKULATE_CORE
())
<<
"Could not load language"
<<
resourceFile
;
resource
->
deleteLater
();
return
false
;
}
if
(
m_languages
.
contains
(
resource
->
identifier
()))
{
if
(
m_languages
.
contains
(
language
->
id
()))
{
qCWarning
(
ARTIKULATE_CORE
())
<<
"Could not load language"
<<
resourceFile
;
resource
->
deleteLater
();
return
false
;
}
m_languages
.
insert
(
resource
->
identifier
(),
resourc
e
);
m_languages
.
insert
(
language
->
id
(),
languag
e
);
return
true
;
}
src/core/resourcerepository.h
View file @
869f4a16
...
...
@@ -89,7 +89,7 @@ private:
bool
loadCourse
(
const
QString
&
resourceFile
);
bool
loadLanguage
(
const
QString
&
resourceFile
);
QVector
<
std
::
shared_ptr
<
ICourse
>>
m_courses
;
QHash
<
QString
,
std
::
shared_ptr
<
Language
Resource
>>
m_languages
;
///>! (language-identifier, language resource)
QHash
<
QString
,
std
::
shared_ptr
<
Language
>>
m_languages
;
///>! (language-identifier, language resource)
QStringList
m_loadedCourses
;
const
QString
m_storageLocation
;
};
...
...
src/core/resources/languageresource.cpp
deleted
100644 → 0
View file @
e9a26bf3
/*
* Copyright 2013 Andreas Cord-Landwehr <cordlandwehr@kde.org>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include "languageresource.h"
#include "courseparser.h"
#include "core/language.h"
#include "core/phoneme.h"
#include "core/phonemegroup.h"
#include <QXmlSchema>
#include <QXmlStreamReader>
#include <QDomDocument>
#include <QIODevice>
#include <QFile>
#include "artikulate_debug.h"
class
LanguageResourcePrivate
{
public:
LanguageResourcePrivate
()
=
default
;
~
LanguageResourcePrivate
()
=
default
;
std
::
shared_ptr
<
Language
>
m_language
;
QString
m_identifier
;
QUrl
m_path
;
QString
m_title
;
QString
m_i18nTitle
;
};
LanguageResource
::
LanguageResource
(
const
QUrl
&
path
)
:
d
(
new
LanguageResourcePrivate
)
{
d
->
m_path
=
path
;
// load basic information from language file, but does not parse everything
QXmlStreamReader
xml
;
QFile
file
(
path
.
toLocalFile
());
if
(
file
.
open
(
QIODevice
::
ReadOnly
))
{
xml
.
setDevice
(
&
file
);
xml
.
readNextStartElement
();
while
(
xml
.
readNext
()
&&
!
xml
.
atEnd
())
{
if
(
xml
.
name
()
==
"id"
)
{
d
->
m_identifier
=
xml
.
readElementText
();
}
if
(
xml
.
name
()
==
"title"
)
{
d
->
m_title
=
xml
.
readElementText
();
}
if
(
xml
.
name
()
==
"i18nTitle"
)
{
d
->
m_i18nTitle
=
xml
.
readElementText
();
}
// quit reading when basic elements are read
if
(
!
d
->
m_identifier
.
isEmpty
()
&&
!
d
->
m_title
.
isEmpty
()
&&
!
d
->
m_i18nTitle
.
isEmpty
()
)
{
break
;
}
}
if
(
xml
.
hasError
())
{
qCritical
()
<<
"Error occurred when reading Language XML file:"
<<
path
.
toLocalFile
();
}
}
xml
.
clear
();
file
.
close
();
}
LanguageResource
::~
LanguageResource
()
{
}
QString
LanguageResource
::
identifier
()
{
return
d
->
m_identifier
;
}
QString
LanguageResource
::
title
()
{
return
d
->
m_title
;
}
QString
LanguageResource
::
i18nTitle
()
{
return
d
->
m_i18nTitle
;
}
bool
LanguageResource
::
isOpen
()
const
{
return
(
d
->
m_language
!=
nullptr
);
}
QUrl
LanguageResource
::
path
()
const
{
return
d
->
m_path
;
}
std
::
shared_ptr
<
Language
>
LanguageResource
::
language
()
{
if
(
d
->
m_language
)
{
return
d
->
m_language
;
}
if
(
!
d
->
m_path
.
isLocalFile
())
{
qCWarning
(
ARTIKULATE_LOG
)
<<
"Cannot open language file at "
<<
d
->
m_path
.
toLocalFile
()
<<
", aborting."
;
return
nullptr
;
}
QXmlSchema
schema
=
CourseParser
::
loadXmlSchema
(
QStringLiteral
(
"language"
));
if
(
!
schema
.
isValid
())
{
return
nullptr
;
}
QDomDocument
document
=
CourseParser
::
loadDomDocument
(
d
->
m_path
,
schema
);
if
(
document
.
isNull
())
{
qCWarning
(
ARTIKULATE_LOG
)
<<
"Could not parse document "
<<
d
->
m_path
.
toLocalFile
()
<<
", aborting."
;
return
nullptr
;
}
QDomElement
root
(
document
.
documentElement
());
d
->
m_language
=
std
::
shared_ptr
<
Language
>
(
new
Language
());
d
->
m_language
->
setFile
(
d
->
m_path
);
d
->
m_language
->
setId
(
root
.
firstChildElement
(
QStringLiteral
(
"id"
)).
text
());
d
->
m_language
->
setTitle
(
root
.
firstChildElement
(
QStringLiteral
(
"title"
)).
text
());
d
->
m_language
->
seti18nTitle
(
root
.
firstChildElement
(
QStringLiteral
(
"i18nTitle"
)).
text
());
// create phoneme groups
for
(
QDomElement
groupNode
=
root
.
firstChildElement
(
QStringLiteral
(
"phonemeGroups"
)).
firstChildElement
();
!
groupNode
.
isNull
();
groupNode
=
groupNode
.
nextSiblingElement
())
{
auto
group
=
d
->
m_language
->
addPhonemeGroup
(
groupNode
.
firstChildElement
(
QStringLiteral
(
"id"
)).
text
(),
groupNode
.
firstChildElement
(
QStringLiteral
(
"title"
)).
text
());
group
->
setDescription
(
groupNode
.
attribute
(
QStringLiteral
(
"description"
)));
// register phonemes
for
(
QDomElement
phonemeNode
=
groupNode
.
firstChildElement
(
QStringLiteral
(
"phonemes"
)).
firstChildElement
();
!
phonemeNode
.
isNull
();
phonemeNode
=
phonemeNode
.
nextSiblingElement
())
{
group
->
addPhoneme
(
phonemeNode
.
firstChildElement
(
QStringLiteral
(
"id"
)).
text
(),
phonemeNode
.
firstChildElement
(
QStringLiteral
(
"title"
)).
text
());
}
}
return
d
->
m_language
;
}
src/core/resources/languageresource.h
deleted
100644 → 0
View file @
e9a26bf3
/*
* Copyright 2013 Andreas Cord-Landwehr <cordlandwehr@kde.org>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef LANGUAGERESOURCE_H
#define LANGUAGERESOURCE_H
#include "artikulatecore_export.h"
#include <memory>
#include <QObject>
class
LanguageResourcePrivate
;
class
Language
;
class
ARTIKULATECORE_EXPORT
LanguageResource
:
public
QObject
{
Q_OBJECT
public:
explicit
LanguageResource
(
const
QUrl
&
path
);
virtual
~
LanguageResource
();
/**
* \return unique identifier
*/
QString
identifier
();
/**
* \return human readable localized title
*/
QString
title
();
/**
* \return human readable title in English
*/
QString
i18nTitle
();
/**
* \return true if resource is loaded, otherwise false
*/
bool
isOpen
()
const
;
/**
* \return path to resource file
*/
QUrl
path
()
const
;
/**
* \return reference to the loaded resource
* if resource is not open yet, it will be loaded
*/
std
::
shared_ptr
<
Language
>
language
();
private:
const
QScopedPointer
<
LanguageResourcePrivate
>
d
;
};
#endif
src/core/resources/resourceinterface.cpp
deleted
100644 → 0
View file @
e9a26bf3
/*
* Copyright 2013-2015 Andreas Cord-Landwehr <cordlandwehr@kde.org>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include "resourceinterface.h"
#include "artikulate_debug.h"
#include <QUrl>
#include <QIODevice>
#include <QXmlSchema>
#include <QXmlSchemaValidator>
#include <QDomDocument>
#include <QFile>
#include <QStandardPaths>
ResourceInterface
::
ResourceInterface
(
ResourceManager
*
resourceManager
)
:
m_contributorResource
(
false
)
{
Q_UNUSED
(
resourceManager
)
}
ResourceInterface
::~
ResourceInterface
()
{
}
void
ResourceInterface
::
setContributorResource
(
bool
contributorResource
)
{
m_contributorResource
=
contributorResource
;
}
bool
ResourceInterface
::
isContributorResource
()
const
{
return
m_contributorResource
;
}
void
ResourceInterface
::
sync
()
{
qCWarning
(
ARTIKULATE_LOG
)
<<
"Resource does not implement syncing."
;
}
void
ResourceInterface
::
reload
()
{
qCWarning
(
ARTIKULATE_LOG
)
<<
"Resource does not implement reloading."
;
}
QXmlSchema
ResourceInterface
::
loadXmlSchema
(
const
QString
&
schemeName
)
const
{
QString
relPath
=
QStringLiteral
(
":/artikulate/schemes/%1.xsd"
).
arg
(
schemeName
);
QUrl
file
=
QUrl
::
fromLocalFile
(
relPath
);
QXmlSchema
schema
;
if
(
file
.
isEmpty
()
||
schema
.
load
(
file
)
==
false
)
{
qCWarning
(
ARTIKULATE_LOG
)
<<
"Schema at file "
<<
file
.
toLocalFile
()
<<
" is invalid."
;
}
return
schema
;
}
QDomDocument
ResourceInterface
::
loadDomDocument
(
const
QUrl
&
path
,
const
QXmlSchema
&
schema
)
const
{
QDomDocument
document
;
QXmlSchemaValidator
validator
(
schema
);
if
(
!
validator
.
validate
(
path
))
{
qCWarning
(
ARTIKULATE_LOG
)
<<
"Schema is not valid, aborting loading of XML document:"
<<
path
.
toLocalFile
();
return
document
;
}
QString
errorMsg
;
QFile
file
(
path
.
toLocalFile
());
if
(
file
.
open
(
QIODevice
::
ReadOnly
))
{
if
(
!
document
.
setContent
(
&
file
,
&
errorMsg
))
{
qCWarning
(
ARTIKULATE_LOG
)
<<
errorMsg
;
}
}
else
{
qCWarning
(
ARTIKULATE_LOG
)
<<
"Could not open XML document "
<<
path
.
toLocalFile
()
<<
" for reading, aborting."
;
}
return
document
;
}
src/core/resources/resourceinterface.h
deleted
100644 → 0
View file @
e9a26bf3
/*
* Copyright 2013 Andreas Cord-Landwehr <cordlandwehr@kde.org>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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