﻿<?xml version="1.0" encoding="utf-8"?>

<xs:schema
	xmlns:xs="http://www.w3.org/2001/XMLSchema"
	xmlns="https://ulearn.me/schema/v2"
	elementFormDefault="qualified"
	targetNamespace="https://ulearn.me/schema/v2"
>

	<xs:import namespace="http://www.w3.org/XML/1998/namespace"/>

	<!-- #region Course -->

	<xs:element name="course" type="Course"/>

	<xs:complexType name="Course">
		<xs:annotation>
			<xs:documentation xml:lang="en">Information about course</xs:documentation>
			<xs:documentation xml:lang="ru">Информация о курсе</xs:documentation>
		</xs:annotation>

		<xs:all>
			<xs:element name="defaultLanguage" type="NonEmptyString" minOccurs="0"/>
			<xs:element name="videoAnnotationsGoogleDoc" type="NonEmptyString" minOccurs="0">
				<xs:annotation>
					<xs:documentation xml:lang="ru">
						Идентификатор GoogleDocs документа, в котором находятся транскрибция видео. Нужно для импорта
						транскрибции в слайды курса.

						К документу должен быть доступ на чтение по ссылке.

						Документ должен быть в строгом машиночитаемом формате:

						# Заголовок слайда (для редакторов)
						guid слайда
						описание всего видео-эпизода
						* 00:01 О чем рассказывает лектор
						* 01:01 О чем сейчас рассказывает лектор

						# Заголовок следующего слайда
						guid второго слайда
						описание всего видео-эпизода
						* 00:01 О чем рассказывает лектор

						...
					</xs:documentation>
				</xs:annotation>
			</xs:element>
			<xs:element name="preludes" type="CoursePreludes" minOccurs="0"/>
			<xs:element name="enableCodeReviewAndQuizManualCheckForEveryone" type="xs:boolean" minOccurs="0"/>
			<xs:element name="scoring" type="ScoringGroups" minOccurs="0"/>
			<xs:element name="units" type="CourseUnits" minOccurs="0"/>
			<xs:element name="dictionaryFile" type="NonEmptyString" minOccurs="0"/>
		</xs:all>

		<xs:attribute name="title" type="NonEmptyString" use="required"/>
	</xs:complexType>

	<xs:complexType name="CoursePreludes">
		<xs:annotation>
			<xs:documentation xml:lang="en">List of preludes file for each language</xs:documentation>
			<xs:documentation xml:lang="ru">Список файлов-prelude, которые будут добавляться в начале каждого решения на
				данном языке программирования
			</xs:documentation>
		</xs:annotation>

		<xs:sequence>
			<xs:element name="prelude" type="Prelude" minOccurs="0" maxOccurs="unbounded"/>
		</xs:sequence>
	</xs:complexType>

	<xs:complexType name="Prelude">
		<xs:simpleContent>
			<xs:extension base="NonEmptyString">
				<xs:annotation>
					<xs:documentation xml:lang="en">Prelude filename</xs:documentation>
					<xs:documentation xml:lang="ru">Путь до файла-prelude</xs:documentation>
				</xs:annotation>
				<xs:attribute name="language" use="required"/>
			</xs:extension>
		</xs:simpleContent>
	</xs:complexType>

	<xs:complexType name="CourseUnits">
		<xs:annotation>
			<xs:documentation xml:lang="en">List of units in the course</xs:documentation>
			<xs:documentation xml:lang="ru">Список модулей в курсе</xs:documentation>
		</xs:annotation>

		<xs:sequence>
			<xs:element name="add" type="NonEmptyString" minOccurs="0" maxOccurs="unbounded">
				<xs:annotation>
					<xs:documentation xml:lang="en">Unit(s) XML filename. Supports masks with * and ?</xs:documentation>
					<xs:documentation xml:lang="ru">Путь до XML файла с модулем или модулями. Поддерживает маски с * и
						?
					</xs:documentation>
				</xs:annotation>
			</xs:element>
		</xs:sequence>
	</xs:complexType>

	<!-- #endregion Course -->

	<!-- #region Unit -->

	<xs:element name="unit" type="Unit"/>

	<xs:complexType name="Unit">
		<xs:all>
			<xs:element name="scoring" type="ScoringGroups" minOccurs="0"/>
			<xs:element name="defaultIncludeCodeFile" type="NonEmptyString" minOccurs="0"/>
			<xs:element name="slides" type="UnitSlides" minOccurs="0"/>
		</xs:all>

		<xs:attribute name="id" type="NonEmptyString" use="required"/>
		<xs:attribute name="url" type="NonEmptyString"/>
		<xs:attribute name="title" type="NonEmptyString" use="required"/>
		<xs:attribute name="isExtraContent" type="xs:boolean">
			<xs:annotation>
				<xs:documentation xml:lang="en">Unit is extra content</xs:documentation>
				<xs:documentation xml:lang="ru">Модуль является доп. контентом</xs:documentation>
			</xs:annotation>
		</xs:attribute>
	</xs:complexType>

	<xs:complexType name="UnitSlides">
		<xs:annotation>
			<xs:documentation xml:lang="en">List of slides in the unit</xs:documentation>
			<xs:documentation xml:lang="ru">Список слайдов в модуле</xs:documentation>
		</xs:annotation>

		<xs:sequence>
			<xs:element name="add" type="NonEmptyString" minOccurs="0" maxOccurs="unbounded">
				<xs:annotation>
					<xs:documentation xml:lang="en">Slide(s) XML filename. Supports masks with * and ?
					</xs:documentation>
					<xs:documentation xml:lang="ru">Путь до XML файла со слайдом или слайдами. Поддерживает маски с * и
						?
					</xs:documentation>
				</xs:annotation>
			</xs:element>
		</xs:sequence>
	</xs:complexType>

	<!-- #endregion Unit -->

	<!-- #region Slide -->

	<xs:element name="slide" type="Slide"/>
	<xs:element name="slide.quiz" type="QuizSlide"/>
	<xs:element name="slide.exercise" type="ExerciseSlide"/>
	<xs:element name="slide.polygon" type="PolygonSlide"/>
	<xs:element name="slide.flashcards" type="FlashcardSlide"/>

	<xs:complexType name="Slide">
		<xs:group ref="SlideInternals" minOccurs="0" maxOccurs="unbounded"/>

		<xs:attributeGroup ref="SlideAttributes"/>
	</xs:complexType>

	<xs:complexType name="QuizSlide">
		<xs:sequence>
			<xs:element name="scoring" type="QuizScoring" minOccurs="0">
				<xs:annotation>
					<xs:documentation xml:lang="en">Quiz scoring settings</xs:documentation>
					<xs:documentation xml:lang="ru">Настройки оценивания теста: количество попыток, ручная проверка и
						так далее...
					</xs:documentation>
				</xs:annotation>
			</xs:element>
			<xs:group ref="SlideInternals" minOccurs="0" maxOccurs="unbounded"/>
		</xs:sequence>

		<xs:attributeGroup ref="SlideAttributes"/>
	</xs:complexType>

	<xs:complexType name="ExerciseSlide">
		<xs:sequence>
			<xs:element name="scoring" type="ExerciseScoring" minOccurs="0"/>
			<xs:group ref="SlideInternals" minOccurs="0" maxOccurs="unbounded"/>
		</xs:sequence>

		<xs:attributeGroup ref="SlideAttributes"/>
	</xs:complexType>

	<xs:complexType name="PolygonSlide">
		<xs:all>
			<xs:element name="scoring" type="ExerciseScoring" minOccurs="0"/>
			<xs:element name="polygonPath" type="xs:string"/>
			<xs:element name="markdown" type="MarkdownBlock" minOccurs="0"/>
			<xs:element name="exercise.polygon" type="PolygonExercise"/>
		</xs:all>

		<xs:attribute name="id" type="NonEmptyString" use="required">
			<xs:annotation>
				<xs:documentation xml:lang="en">Slide's id, should be guid</xs:documentation>
				<xs:documentation xml:lang="ru">Идентификатор слайда, должен быть гуидом</xs:documentation>
			</xs:annotation>
		</xs:attribute>
		<xs:attribute name="hide" type="xs:boolean">
			<xs:annotation>
				<xs:documentation xml:lang="en">Side is shown to instructors only</xs:documentation>
				<xs:documentation xml:lang="ru">Слайд показывается только преподавателям</xs:documentation>
			</xs:annotation>
		</xs:attribute>
	</xs:complexType>

	<xs:complexType name="FlashcardSlide">
		<xs:sequence>
			<xs:element name="flashcard" type="Flashcard" minOccurs="0" maxOccurs="unbounded"/>
		</xs:sequence>

		<xs:attribute name="id" type="NonEmptyString" use="required">
			<xs:annotation>
				<xs:documentation xml:lang="en">Slide's id, should be guid</xs:documentation>
				<xs:documentation xml:lang="ru">Идентификатор слайда, должен быть гуидом</xs:documentation>
			</xs:annotation>
		</xs:attribute>
	</xs:complexType>

	<xs:complexType name="Flashcard">
		<xs:sequence>
			<xs:element name="theorySlideId" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
			<xs:element name="question" type="FlashcardBlocks"/>
			<xs:element name="answer" type="FlashcardBlocks"/>
		</xs:sequence>

		<xs:attribute name="id" type="NonEmptyString" use="required">
			<xs:annotation>
				<xs:documentation xml:lang="en">Flashcard's id, should be course-unique string</xs:documentation>
				<xs:documentation xml:lang="ru">
					Идентификатор флеш-карты, должен быть уникальной для курса строкой
				</xs:documentation>
			</xs:annotation>
		</xs:attribute>
	</xs:complexType>

	<xs:complexType name="FlashcardBlocks">
		<xs:choice minOccurs="0" maxOccurs="unbounded">
			<xs:element name="tex" type="Tex"/>
			<xs:element name="markdown" type="MarkdownBlock"/>
			<xs:element name="code" type="Code"/>
		</xs:choice>
	</xs:complexType>

	<xs:group name="SlideInternals">
		<xs:choice>
			<xs:element name="meta" type="SlideMeta">
				<xs:annotation>
					<xs:documentation xml:lang="en">Slide's meta: keywords, description, image</xs:documentation>
					<xs:documentation xml:lang="ru">
						Мета-информация о слайде, попадёт на итоговую страницу в виде тегов
						keywords, description, image
					</xs:documentation>
				</xs:annotation>
			</xs:element>
			<xs:element name="defaultIncludeCodeFile" type="NonEmptyString">
				<xs:annotation>
					<xs:documentation xml:lang="en">Default path for &lt;includeCode&gt;, &lt;exercise.file&gt;,
						&lt;exercise.csproj&gt;
					</xs:documentation>
					<xs:documentation xml:lang="ru">
						Путь по умолчанию для блоков &lt;includeCode&gt;, &lt;exercise.file&gt;,
						&lt;exercise.csproj&gt;
					</xs:documentation>
				</xs:annotation>
			</xs:element>
			<xs:group ref="Blocks" minOccurs="0" maxOccurs="unbounded"/>
		</xs:choice>
	</xs:group>

	<xs:complexType name="SlideMeta">
		<xs:all>
			<xs:element name="image" type="NonEmptyString" minOccurs="0">
				<xs:annotation>
					<xs:documentation xml:lang="en">
						Image for slide. Will be used i.e. on social network posting
					</xs:documentation>
					<xs:documentation xml:lang="ru">
						Изображение для слайда. Будет использовано, например, при постинге в
						соцсети
					</xs:documentation>
				</xs:annotation>
			</xs:element>
			<xs:element name="keywords" type="NonEmptyString" minOccurs="0">
				<xs:annotation>
					<xs:documentation xml:lang="en">Keywords for slide. Used by search engines</xs:documentation>
					<xs:documentation xml:lang="ru">
						Ключевые слова для слайда. Используются, например, поисковыми
						роботами
					</xs:documentation>
				</xs:annotation>
			</xs:element>
			<xs:element name="description" type="NonEmptyString" minOccurs="0">
				<xs:annotation>
					<xs:documentation xml:lang="en">Description for slide. Used by search engines</xs:documentation>
					<xs:documentation xml:lang="ru">
						Описание для слайда. Используются, например, поисковыми роботами,
						выводится в результатах поиска
					</xs:documentation>
				</xs:annotation>
			</xs:element>
		</xs:all>
	</xs:complexType>

	<xs:attributeGroup name="SlideAttributes">
		<xs:attribute name="id" type="NonEmptyString" use="required">
			<xs:annotation>
				<xs:documentation xml:lang="en">Slide's id, should be guid</xs:documentation>
				<xs:documentation xml:lang="ru">Идентификатор слайда, должен быть гуидом</xs:documentation>
			</xs:annotation>
		</xs:attribute>
		<xs:attribute name="title" type="NonEmptyString" use="required">
			<xs:annotation>
				<xs:documentation xml:lang="en">Slide's title</xs:documentation>
				<xs:documentation xml:lang="ru">Заголовок слайда</xs:documentation>
			</xs:annotation>
		</xs:attribute>
		<xs:attribute name="hide" type="xs:boolean">
			<xs:annotation>
				<xs:documentation xml:lang="en">Side is shown to instructors only</xs:documentation>
				<xs:documentation xml:lang="ru">Слайд показывается только преподавателям</xs:documentation>
			</xs:annotation>
		</xs:attribute>
		<xs:attribute name="isExtraContent" type="xs:boolean">
			<xs:annotation>
				<xs:documentation xml:lang="en">Side is extra content</xs:documentation>
				<xs:documentation xml:lang="ru">Слайд является доп. контентом</xs:documentation>
			</xs:annotation>
		</xs:attribute>
	</xs:attributeGroup>

	<!-- #endregion Slide -->

	<!-- #region Blocks -->

	<xs:group name="Blocks">
		<xs:choice>
			<xs:group ref="CommonBlocks"/>
			<xs:group ref="QuizBlocks"/>
			<xs:group ref="ExerciseBlocks"/>
		</xs:choice>
	</xs:group>

	<!-- #region Common blocks -->

	<xs:group name="CommonBlocks">
		<xs:choice>
			<xs:element name="galleryImages" type="GalleryImages"/>
			<xs:element name="tex" type="Tex"/>
			<xs:element name="code" type="Code"/>
			<xs:element name="includeBlocks" type="Include"/>
			<xs:element name="includeMarkdown" type="Include"/>
			<xs:element name="html" type="Html"/>
			<xs:element name="spoiler" type="Spoiler"/>
			<xs:element name="selfCheckups" type="SelfCheckups"/>
			<xs:element name="markdown" type="MarkdownBlock"/>
			<xs:element name="includeCode" type="IncludeCodeBlock"/>
			<xs:element name="youtube" type="YoutubeBlock"/>
			<xs:element name="gallery" type="NonEmptyString"/>
		</xs:choice>
	</xs:group>

	<xs:complexType name="GalleryImages">
		<xs:sequence maxOccurs="unbounded">
			<xs:element name="image" type="NonEmptyString">
				<xs:annotation>
					<xs:documentation xml:lang="en">Image filename. Supports masks with * and ?</xs:documentation>
					<xs:documentation xml:lang="ru">Путь до изображения. Поддерживает маски с * и ?</xs:documentation>
				</xs:annotation>
			</xs:element>
		</xs:sequence>
	</xs:complexType>

	<xs:complexType name="Tex">
		<xs:sequence maxOccurs="unbounded">
			<xs:element name="line" type="NonEmptyString"/>
		</xs:sequence>
	</xs:complexType>

	<xs:complexType name="Code">
		<xs:simpleContent>
			<xs:extension base="StringWithXmlSpaces">
				<xs:attribute name="language" type="NonEmptyString"/>
				<xs:attribute name="hide" type="xs:boolean"/>
			</xs:extension>
		</xs:simpleContent>
	</xs:complexType>

	<xs:complexType name="Include">
		<xs:attribute name="file" type="NonEmptyString"/>
		<xs:attributeGroup ref="IncludeAttributes"/>
	</xs:complexType>

	<xs:complexType name="Html" mixed="true">
		<xs:sequence>
			<xs:any processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
		</xs:sequence>

		<xs:attribute name="hide" type="xs:boolean"/>
	</xs:complexType>

	<xs:complexType name="Spoiler">
		<xs:sequence>
			<xs:group ref="CommonBlocks" minOccurs="0" maxOccurs="unbounded"/>
		</xs:sequence>

		<xs:attribute name="text" type="NonEmptyString" use="required"/>
		<xs:attribute name="hideQuizButton" type="xs:boolean"/>
		<xs:attribute name="closable" type="xs:boolean">
			<xs:annotation>
				<xs:documentation>
					Атрибут устарел. Все спойлеры можно закрыть.
				</xs:documentation>
			</xs:annotation>
		</xs:attribute>
		<xs:attribute name="hide" type="xs:boolean"/>
	</xs:complexType>

	<xs:complexType name="SelfCheckups">
		<xs:sequence maxOccurs="unbounded">
			<xs:element name="checkup" type="NonEmptyString"/>
		</xs:sequence>
	</xs:complexType>

	<xs:complexType name="MarkdownBlock" mixed="true">
		<xs:sequence minOccurs="0" maxOccurs="unbounded">
			<xs:choice>
				<xs:element name="note" type="NonEmptyString"/>
				<xs:element name="code" type="Code"/>
			</xs:choice>
		</xs:sequence>
		<xs:attribute ref="xml:space"/>
		<xs:attribute name="hide" type="xs:boolean"/>
	</xs:complexType>

	<xs:complexType name="YoutubeBlock" mixed="true">
		<xs:simpleContent>
			<xs:extension base="xs:string">
				<xs:attribute name="vkId" type="NonEmptyString"/>
				<xs:attribute name="vkOid" type="NonEmptyString"/>
				<xs:attribute name="vkHash" type="NonEmptyString"/>
			</xs:extension>
		</xs:simpleContent>
	</xs:complexType>

	<xs:complexType name="IncludeCodeBlock">
		<xs:sequence minOccurs="0" maxOccurs="unbounded">
			<xs:element name="display" type="Label"/>
		</xs:sequence>

		<xs:attribute name="file" type="NonEmptyString"/>
		<xs:attributeGroup ref="IncludeCodeAttributes"/>
	</xs:complexType>

	<!-- #endregion Common blocks -->

	<!-- #region Quiz blocks -->

	<xs:group name="QuizBlocks">
		<xs:choice>
			<xs:element name="question.isTrue" type="IsTrueBlock"/>
			<xs:element name="question.choice" type="ChoiceBlock">
				<xs:unique name="UniqueChoiceItemId">
					<xs:selector xpath="*"/>
					<xs:field xpath="@id"/>
				</xs:unique>
			</xs:element>
			<xs:element name="question.order" type="OrderingBlock">
				<xs:unique name="UniqueOrderingItemId">
					<xs:selector xpath="*"/>
					<xs:field xpath="@id"/>
				</xs:unique>
			</xs:element>
			<xs:element name="question.match" type="MatchingBlock">
				<xs:unique name="UniqueMatchingItemId">
					<xs:selector xpath="*"/>
					<xs:field xpath="@id"/>
				</xs:unique>
			</xs:element>
			<xs:element name="question.text" type="FillInBlock"/>
		</xs:choice>
	</xs:group>

	<xs:complexType name="IsTrueBlock">
		<xs:group ref="QuestionInternals"/>

		<xs:attributeGroup ref="QuestionAttributes"/>
		<xs:attribute name="answer" type="xs:boolean"/>
		<xs:attribute name="explanation" type="xs:string"/>
		<xs:attribute name="maxScore" type="xs:int"/>
	</xs:complexType>

	<xs:complexType name="ChoiceBlock">
		<xs:sequence>
			<xs:group ref="QuestionInternals"/>
			<xs:choice minOccurs="0" maxOccurs="unbounded">
				<xs:element name="item" type="QuizChoiceItem"/>
				<xs:element name="allowedMistakes" type="AllowedMistakes"/>
			</xs:choice>
		</xs:sequence>

		<xs:attributeGroup ref="QuestionAttributes"/>
		<xs:attribute name="multiple" type="xs:boolean"/>
		<xs:attribute name="shuffle" type="xs:boolean"/>
		<xs:attribute name="maxScore" type="xs:int"/>
	</xs:complexType>

	<xs:complexType name="QuizChoiceItem">
		<xs:simpleContent>
			<xs:extension base="NonEmptyString">
				<xs:attribute name="id" type="NonEmptyString" use="required"/>
				<xs:attribute name="isCorrect" use="required">
					<xs:simpleType>
						<xs:restriction base="NonEmptyString">
							<xs:enumeration value="true"/>
							<xs:enumeration value="false"/>
							<xs:enumeration value="maybe"/>
						</xs:restriction>
					</xs:simpleType>
				</xs:attribute>
				<xs:attribute name="explanation" type="xs:string"/>
			</xs:extension>
		</xs:simpleContent>
	</xs:complexType>

	<xs:complexType name="OrderingBlock">
		<xs:sequence>
			<xs:group ref="QuestionInternals"/>
			<xs:choice minOccurs="0" maxOccurs="unbounded">
				<xs:element name="explanation" type="xs:string"/>
				<xs:element name="item" type="QuizOrderItem"/>
			</xs:choice>
		</xs:sequence>

		<xs:attributeGroup ref="QuestionAttributes"/>
		<xs:attribute name="maxScore" type="xs:int"/>
	</xs:complexType>

	<xs:complexType name="QuizOrderItem">
		<xs:simpleContent>
			<xs:extension base="NonEmptyString">
				<xs:attribute name="id" type="NonEmptyString" use="required"/>
			</xs:extension>
		</xs:simpleContent>
	</xs:complexType>

	<xs:complexType name="MatchingBlock">
		<xs:sequence>
			<xs:group ref="QuestionInternals"/>
			<xs:choice minOccurs="0" maxOccurs="unbounded">
				<xs:element name="explanation" type="xs:string"/>
				<xs:element name="match" type="QuizMatchingMatch"/>
			</xs:choice>
		</xs:sequence>

		<xs:attributeGroup ref="QuestionAttributes"/>
		<xs:attribute name="shuffleFixed" type="xs:boolean"/>
		<xs:attribute name="maxScore" type="xs:int"/>
	</xs:complexType>

	<xs:complexType name="QuizMatchingMatch">
		<xs:sequence>
			<xs:element name="fixed" type="NonEmptyString"/>
			<xs:element name="movable" type="NonEmptyString"/>
		</xs:sequence>
		<xs:attribute name="id" type="NonEmptyString" use="required"/>
	</xs:complexType>

	<xs:complexType name="FillInBlock">
		<xs:sequence>
			<xs:group ref="QuestionInternals"/>
			<xs:choice minOccurs="0" maxOccurs="unbounded">
				<xs:element name="sample" type="xs:string">
					<xs:annotation>
						<xs:documentation xml:lang="en">Example of answer. Should match with at least of one regex
						</xs:documentation>
						<xs:documentation xml:lang="ru">Пример ответа. Показывается студенту после использования
							всех попыток. Должен подходить хотя бы под одно регулярное выражение из &lt;regex&gt;
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="regex" type="Regex">
					<xs:annotation>
						<xs:documentation xml:lang="en">Regular expression for correct answers</xs:documentation>
						<xs:documentation xml:lang="ru">Регулярное выражение для проверки правильности ответа
						</xs:documentation>
					</xs:annotation>
				</xs:element>
			</xs:choice>
		</xs:sequence>

		<xs:attributeGroup ref="QuestionAttributes"/>
		<xs:attribute name="explanation" type="xs:string"/>
		<xs:attribute name="maxScore" type="xs:int"/>
		<xs:attribute name="multiline" type="xs:boolean"/>
	</xs:complexType>

	<xs:complexType name="Regex">
		<xs:simpleContent>
			<xs:extension base="xs:string">
				<xs:attribute name="ignoreCase" type="xs:boolean" default="false"/>
			</xs:extension>
		</xs:simpleContent>
	</xs:complexType>

	<xs:group name="QuestionInternals">
		<xs:choice>
			<xs:element name="text" type="NonEmptyString">
				<xs:annotation>
					<xs:documentation xml:lang="en">Question</xs:documentation>
					<xs:documentation xml:lang="ru">Текст вопроса</xs:documentation>
				</xs:annotation>
			</xs:element>
		</xs:choice>
	</xs:group>

	<xs:attributeGroup name="QuestionAttributes">
		<xs:attribute name="id" type="NonEmptyString" use="required">
			<xs:annotation>
				<xs:documentation xml:lang="en">Identifier of the question. Should be unique in the slide.
				</xs:documentation>
				<xs:documentation xml:lang="ru">Идентификатор вопроса. Должен быть уникальным в рамках слайда.
				</xs:documentation>
			</xs:annotation>
		</xs:attribute>
	</xs:attributeGroup>

	<!-- #endregion Quiz blocks -->

	<!-- #region Exercise blocks -->

	<xs:group name="ExerciseBlocks">
		<xs:choice>
			<xs:element name="exercise.file" type="SingleFileExercise"/>
			<xs:element name="exercise.csproj" type="ProjectExercise"/>
			<xs:element name="exercise.polygon" type="PolygonExercise"/>
			<xs:element name="exercise.universal" type="UniversalExercise"/>
		</xs:choice>
	</xs:group>

	<xs:complexType name="SingleFileExercise">
		<xs:sequence>
			<xs:choice minOccurs="0" maxOccurs="unbounded">
				<xs:element name="solution" type="Label"/>
				<xs:element name="remove" type="Label"/>
				<xs:element name="prelude" type="NonEmptyString"/>
				<xs:group ref="ExericesInternals"/>
			</xs:choice>
		</xs:sequence>
		<xs:attribute name="file" type="NonEmptyString"/>
		<xs:attributeGroup ref="ExerciseAttributes"/>
	</xs:complexType>

	<xs:complexType name="ProjectExercise">
		<xs:sequence>
			<xs:choice minOccurs="0" maxOccurs="unbounded">
				<xs:element name="userCodeFile" type="NonEmptyString">
					<xs:annotation>
						<xs:documentation>
							Путь относительно директории, в котором лежит csproj.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="solutionFile" type="NonEmptyString">
					<xs:annotation>
						<xs:documentation>
							Обычно авторское решение задачи находится в userCodeFile.Solution.cs. Но бывают серии
							задач,
							где студент пишет код в одном файле поэтапно. В этом теге в задачах промежуточных этапов
							указывают путь до решения. Файл с решением должен подходить под маску *.Solution.*
							Для полного решения должен использоваться userCodeFile.Solution.cs.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="excludePathForChecker" type="NonEmptyString">
					<xs:annotation>
						<xs:documentation>
							Путь относительно директории, в котором лежит csproj. Этот файл будет исключён из
							проекта при сборке для проверки.
							Обычно это файл с эталонным решением.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="excludePathForStudent" type="NonEmptyString">
					<xs:annotation>
						<xs:documentation>
							Путь относительно директории, в котором лежит csproj. Этот файл будет исключён из
							проекта при сборке для студента.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="studentZipIsCompilable" type="xs:boolean">
					<xs:annotation>
						<xs:documentation>
							Должен ли по задумке автора zip с проектом для студента успешно собираться без
							изменений? По умолчанию true.
							Если false, то валидатор не выдает ошибку на несобирающийся проект из zip-а для
							студентов.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="startupObject" type="xs:string">
					<xs:annotation>
						<xs:documentation>
							Полное имя класса, содержащего точку входа.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="nunitTestClass" type="xs:string">
					<xs:annotation>
						<xs:documentation>
							Имя класса с Nunit тестами, которые будут запущенны тест раннером.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:group ref="ExericesInternals"/>
			</xs:choice>
		</xs:sequence>

		<xs:attributeGroup ref="ExerciseAttributes"/>
		<xs:attribute name="csproj" type="NonEmptyString" use="required">
			<xs:annotation>
				<xs:documentation>
					Путь до csproj-файла относительно директории с xml-файлом описания слайда.
				</xs:documentation>
			</xs:annotation>
		</xs:attribute>
	</xs:complexType>

	<xs:complexType name="UniversalExercise">
		<xs:sequence>
			<xs:choice minOccurs="0" maxOccurs="unbounded">
				<xs:element name="hasAutomaticChecking" type="xs:boolean">
					<xs:annotation>
						<xs:documentation>
							Нужно ли запускать автоматическую проверку.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="userCodeFile" type="NonEmptyString">
					<xs:annotation>
						<xs:documentation>
							Путь относительно директории, в которой лежит задача.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="solutionFile" type="NonEmptyString">
					<xs:annotation>
						<xs:documentation>
							Обычно авторское решение задачи находится в userCodeFile. Но бывают серии задач,
							где студент пишет код в одном файле поэтапно. В этом теге в задачах промежуточных этапов
							указывают путь до решения. Файл с решением должен подходить под маску *.Solution.*
							Полное решение должно находиться в userCodeFile.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="excludePathForChecker" type="NonEmptyString">
					<xs:annotation>
						<xs:documentation>
							Путь относительно директории с задачей. Файлы по этому шаблону будут исключены из
							проекта при сборке для проверки.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="includePathForChecker" type="NonEmptyString">
					<xs:annotation>
						<xs:documentation>
							Путь относительно директории c xml-файлом описания юнита до директории, содержимое
							которой нужно включить в архив при сборке для проверки.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="excludePathForStudent" type="NonEmptyString">
					<xs:annotation>
						<xs:documentation>
							Путь относительно директори с задачей. Этот файл будет исключён из проекта при сборке
							для студента.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="interpretNonJsonOutputAs" type="InterpretNonJsonOutputAs">
					<xs:annotation>
						<xs:documentation>
							Как интерпретировать вывод, если не удалось распарсить вывод в JSON
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="checkInitialSolution" type="xs:boolean">
					<xs:annotation>
						<xs:documentation>
							Нужно ли проверять, что initial-решение при отправке в чеккер для type="check-output"
							возвращает Ok, но output не пуст,
							а для "check-exit-code" возвращает не Ok. По умолчанию true.
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="dockerImageName" type="NonEmptyString">
					<xs:annotation>
						<xs:documentation>
							Имя docker-контейнера
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="run" type="NonEmptyString">
					<xs:annotation>
						<xs:documentation>
							Команда, выполняемая в docker-контейнере
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:element name="region" type="NonEmptyString">
					<xs:annotation>
						<xs:documentation>
							Метка региона файла, с которым работает студент. [prefix]region [label] ...
							[prefix]endregion [label] Разрешен только при noStudentZip=true
						</xs:documentation>
					</xs:annotation>
				</xs:element>
				<xs:group ref="ExericesInternals"/>
			</xs:choice>
		</xs:sequence>

		<xs:attributeGroup ref="ExerciseAttributes"/>
		<xs:attribute name="exerciseDirName" type="NonEmptyString" use="required">
			<xs:annotation>
				<xs:documentation>
					Путь до папки с задачей относительно директории с xml-файлом описания юнита.
				</xs:documentation>
			</xs:annotation>
		</xs:attribute>
		<xs:attribute name="noStudentZip" type="xs:boolean">
			<xs:annotation>
				<xs:documentation>
					Не отдавать zip-файл проекта студенту
				</xs:documentation>
			</xs:annotation>
		</xs:attribute>
	</xs:complexType>

	<xs:complexType name="PolygonExercise">
		<xs:sequence>
			<xs:choice minOccurs="0" maxOccurs="unbounded">
				<xs:element name="hint" type="StringWithXmlSpaces"/>
				<xs:element name="hideSolutions" type="xs:boolean"/>
				<xs:element name="checkForPlagiarism" type="xs:boolean" minOccurs="0"/>
				<xs:element name="showTestDescription" type="xs:boolean" minOccurs="0"/>
				<xs:element name="pythonVisualizerEnabled" type="xs:boolean" minOccurs="0"/>
			</xs:choice>
		</xs:sequence>

		<xs:attributeGroup ref="IncludeAttributes"/>
	</xs:complexType>

	<xs:group name="ExericesInternals">
		<xs:choice>
			<xs:element name="initialCode" type="StringWithXmlSpaces"/>
			<xs:element name="hint" type="StringWithXmlSpaces"/>
			<xs:element name="comment" type="NonEmptyString"/>
			<xs:element name="expected" type="StringWithXmlSpaces"/>
			<xs:element name="passingPoints" type="xs:float"/>
			<xs:element name="smallPointsIsBetter" type="xs:boolean"/>
			<xs:element name="hideSolutions" type="xs:boolean"/>
			<xs:element name="timeLimit" type="xs:int"/>
			<xs:element name="checkForPlagiarism" type="xs:boolean"/>
			<xs:element name="hideExpectedOutput" type="xs:boolean"/>
			<xs:element name="validator" type="Validator"/>
			<xs:element name="texts" type="Texts"/>
			<xs:element name="checkup" type="NonEmptyString"/>
		</xs:choice>
	</xs:group>

	<xs:complexType name="Validator">
		<xs:simpleContent>
			<xs:extension base="xs:string">
				<xs:attribute name="removeDefaults" type="xs:boolean"/>
			</xs:extension>
		</xs:simpleContent>
	</xs:complexType>

	<xs:complexType name="Texts">
		<xs:sequence minOccurs="0" maxOccurs="unbounded">
			<xs:choice>
				<xs:element name="allTestsPassed" type="xs:string"/>
				<xs:element name="allTestsPassedWithoutReview" type="xs:string"/>
				<xs:element name="codeReviewPassed" type="xs:string"/>
				<xs:element name="codeReviewPassedInstructorView" type="xs:string"/>
				<xs:element name="waitingForCodeReview" type="xs:string"/>
				<xs:element name="waitingForCodeReviewInstructorView" type="xs:string"/>
			</xs:choice>
		</xs:sequence>
	</xs:complexType>

	<xs:attributeGroup name="ExerciseAttributes">
		<xs:attributeGroup ref="IncludeCodeAttributes"/>
		<xs:attribute name="type">
			<xs:simpleType>
				<xs:restriction base="xs:string">
					<xs:enumeration value="check-output"/>
					<xs:enumeration value="check-exit-code"/>
					<xs:enumeration value="check-points"/>
				</xs:restriction>
			</xs:simpleType>
		</xs:attribute>
	</xs:attributeGroup>

	<xs:attributeGroup name="IncludeCodeAttributes">
		<xs:attributeGroup ref="IncludeAttributes"/>
		<xs:attribute name="language" type="NonEmptyString"/>
	</xs:attributeGroup>

	<xs:attributeGroup name="IncludeAttributes">
		<xs:attribute name="hide" type="xs:boolean"/>
	</xs:attributeGroup>

	<!-- #endregion Exercise blocks -->

	<!-- #endregion Blocks -->

	<!-- #region Types -->

	<xs:simpleType name="NonEmptyString">
		<xs:annotation>
			<xs:documentation xml:lang="en">Non-empty string</xs:documentation>
			<xs:documentation xml:lang="ru">Непустая строка</xs:documentation>
		</xs:annotation>
		<xs:restriction base="xs:string">
			<xs:minLength value="1"/>
		</xs:restriction>
	</xs:simpleType>

	<xs:complexType name="Label">
		<xs:simpleContent>
			<xs:extension base="NonEmptyString">
				<xs:attribute name="onlyBody" type="xs:boolean"/>
			</xs:extension>
		</xs:simpleContent>
	</xs:complexType>

	<xs:simpleType name="InterpretNonJsonOutputAs">
		<xs:restriction base="xs:string">
			<xs:enumeration value="CE">
				<xs:annotation>
					<xs:documentation xml:lang="en">Compilation Error</xs:documentation>
					<xs:documentation xml:lang="ru">Ошибка компиляции</xs:documentation>
				</xs:annotation>
			</xs:enumeration>
			<xs:enumeration value="WA">
				<xs:annotation>
					<xs:documentation xml:lang="en">Wrong Answer</xs:documentation>
					<xs:documentation xml:lang="ru">Неверный ответ</xs:documentation>
				</xs:annotation>
			</xs:enumeration>
			<xs:enumeration value="SE">
				<xs:annotation>
					<xs:documentation xml:lang="en">Sandbox Error</xs:documentation>
					<xs:documentation xml:lang="ru">Ошибка sandbox-а</xs:documentation>
				</xs:annotation>
			</xs:enumeration>
		</xs:restriction>
	</xs:simpleType>

	<xs:complexType name="StringWithXmlSpaces">
		<xs:simpleContent>
			<xs:extension base="xs:string">
				<xs:attribute ref="xml:space"/>
			</xs:extension>
		</xs:simpleContent>
	</xs:complexType>

	<xs:complexType name="AllowedMistakes">
		<xs:annotation>
			<xs:documentation xml:lang="en">Allowed mistakes count</xs:documentation>
			<xs:documentation xml:lang="ru">Разрешённое количество ошибок</xs:documentation>
		</xs:annotation>

		<xs:attribute name="checkedUnnecessary" type="xs:int">
			<xs:annotation>
				<xs:documentation xml:lang="en">Allowed count of unnecessary checked items</xs:documentation>
				<xs:documentation xml:lang="ru">Разрешённое количество пунктов, которые были отмечены пользователем, но
					НЕ должны были быть отмечены
				</xs:documentation>
			</xs:annotation>
		</xs:attribute>
		<xs:attribute name="notCheckedNecessary" type="xs:int">
			<xs:annotation>
				<xs:documentation xml:lang="en">Allowed count of necessary not-checked items</xs:documentation>
				<xs:documentation xml:lang="ru">Разрешённое количество пунктов, которые НЕ были отмечены пользователем,
					но должны были быть отмечены
				</xs:documentation>
			</xs:annotation>
		</xs:attribute>
	</xs:complexType>

	<xs:complexType name="QuizScoring">
		<xs:attribute name="tries" type="xs:int">
			<xs:annotation>
				<xs:documentation xml:lang="en">Maximum tries count</xs:documentation>
				<xs:documentation xml:lang="ru">Максимальное количество попыток</xs:documentation>
			</xs:annotation>
		</xs:attribute>
		<xs:attribute name="manualCheck" type="xs:boolean">
			<xs:annotation>
				<xs:documentation xml:lang="en">Is manual checking enabled</xs:documentation>
				<xs:documentation xml:lang="ru">Включена ли ручная проверка этого теста</xs:documentation>
			</xs:annotation>
		</xs:attribute>
		<xs:attribute name="group" type="NonEmptyString">
			<xs:annotation>
				<xs:documentation xml:lang="en">Scoring group for this quiz</xs:documentation>
				<xs:documentation xml:lang="ru">К какой группе баллов относится этот тест</xs:documentation>
			</xs:annotation>
		</xs:attribute>
	</xs:complexType>

	<xs:complexType name="ExerciseScoring">
		<xs:attribute name="passedTestsScore" type="xs:int">
			<xs:annotation>
				<xs:documentation xml:lang="en">Score for correct solution (if all tests passed)</xs:documentation>
				<xs:documentation xml:lang="ru">Количество баллов, автоматически выдающееся за верное решение (если
					прошли все тесты). Эти баллы могут быть отобраны на ревью преподавателем
				</xs:documentation>
			</xs:annotation>
		</xs:attribute>
		<xs:attribute name="codeReviewScore" type="xs:int">
			<xs:annotation>
				<xs:documentation xml:lang="en">Maximum score for code review</xs:documentation>
				<xs:documentation xml:lang="ru">Максимальное количество баллов, которое преподаватель может добавить к
					баллам за верное решение, на код ревью
				</xs:documentation>
			</xs:annotation>
		</xs:attribute>
		<xs:attribute name="group" type="NonEmptyString">
			<xs:annotation>
				<xs:documentation xml:lang="en">Scoring group for this quiz</xs:documentation>
				<xs:documentation xml:lang="ru">К какой группе баллов относится этот тест</xs:documentation>
			</xs:annotation>
		</xs:attribute>
	</xs:complexType>

	<xs:complexType name="ScoringGroups">
		<xs:sequence>
			<xs:element name="group" type="ScoringGroup" minOccurs="0" maxOccurs="unbounded"/>
		</xs:sequence>

		<xs:attribute name="defaultQuiz" type="NonEmptyString"/>
		<xs:attribute name="defaultExercise" type="NonEmptyString"/>
		<xs:attribute name="default" type="NonEmptyString"/>
	</xs:complexType>

	<xs:complexType name="ScoringGroup">
		<xs:simpleContent>
			<xs:extension base="NonEmptyString">
				<xs:attribute name="id" type="NonEmptyString" use="required"/>
				<xs:attribute name="abbr" type="NonEmptyString" use="required"/>
				<xs:attribute name="description" type="NonEmptyString"/>
				<xs:attribute name="maxAdditionalScore" type="xs:integer"/>
				<xs:attribute name="enableForEveryone" type="xs:boolean"/>
				<xs:attribute name="weight" type="xs:decimal">
					<xs:annotation>
						<xs:documentation xml:lang="en">The weight with which different ScoringGroups are summed into a
							number showing the overall progress. The default is 1
						</xs:documentation>
						<xs:documentation xml:lang="ru">Вес, с которым разные ScoringGroup суммируются в единое число,
							показывающее общий прогресс. По умолчанию 1
						</xs:documentation>
					</xs:annotation>
				</xs:attribute>
			</xs:extension>
		</xs:simpleContent>
	</xs:complexType>

	<!-- #endregion Types -->
</xs:schema>