Initial commit
This commit is contained in:
@@ -0,0 +1,759 @@
|
||||
<html xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office"
|
||||
xmlns:w="urn:schemas-microsoft-com:office:word"
|
||||
xmlns:m="http://schemas.microsoft.com/office/2004/12/omml"
|
||||
xmlns="http://www.w3.org/TR/REC-html40">
|
||||
|
||||
<head>
|
||||
<meta http-equiv=Content-Type content="text/html; charset=windows-1251">
|
||||
<meta name=ProgId content=Word.Document>
|
||||
<meta name=Generator content="Microsoft Word 15">
|
||||
<meta name=Originator content="Microsoft Word 15">
|
||||
<link rel=File-List href="student_dashboard.files/filelist.xml">
|
||||
<!--[if gte mso 9]><xml>
|
||||
<o:DocumentProperties>
|
||||
<o:Author>sgd</o:Author>
|
||||
<o:LastAuthor>sgd</o:LastAuthor>
|
||||
<o:Revision>2</o:Revision>
|
||||
<o:TotalTime>1</o:TotalTime>
|
||||
<o:Created>2026-07-12T08:17:00Z</o:Created>
|
||||
<o:LastSaved>2026-07-12T08:17:00Z</o:LastSaved>
|
||||
<o:Pages>1</o:Pages>
|
||||
<o:Version>16.00</o:Version>
|
||||
</o:DocumentProperties>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml><![endif]-->
|
||||
<link rel=themeData href="student_dashboard.files/themedata.thmx">
|
||||
<link rel=colorSchemeMapping
|
||||
href="student_dashboard.files/colorschememapping.xml">
|
||||
<!--[if gte mso 9]><xml>
|
||||
<w:WordDocument>
|
||||
<w:TrackMoves>false</w:TrackMoves>
|
||||
<w:TrackFormatting/>
|
||||
<w:PunctuationKerning/>
|
||||
<w:ValidateAgainstSchemas/>
|
||||
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
|
||||
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
|
||||
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
|
||||
<w:DoNotPromoteQF/>
|
||||
<w:LidThemeOther>RU</w:LidThemeOther>
|
||||
<w:LidThemeAsian>X-NONE</w:LidThemeAsian>
|
||||
<w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript>
|
||||
<w:Compatibility>
|
||||
<w:BreakWrappedTables/>
|
||||
<w:SnapToGridInCell/>
|
||||
<w:WrapTextWithPunct/>
|
||||
<w:UseAsianBreakRules/>
|
||||
<w:DontGrowAutofit/>
|
||||
<w:SplitPgBreakAndParaMark/>
|
||||
<w:EnableOpenTypeKerning/>
|
||||
<w:DontFlipMirrorIndents/>
|
||||
<w:OverrideTableStyleHps/>
|
||||
</w:Compatibility>
|
||||
<m:mathPr>
|
||||
<m:mathFont m:val="Cambria Math"/>
|
||||
<m:brkBin m:val="before"/>
|
||||
<m:brkBinSub m:val="--"/>
|
||||
<m:smallFrac m:val="off"/>
|
||||
<m:dispDef/>
|
||||
<m:lMargin m:val="0"/>
|
||||
<m:rMargin m:val="0"/>
|
||||
<m:defJc m:val="centerGroup"/>
|
||||
<m:wrapIndent m:val="1440"/>
|
||||
<m:intLim m:val="subSup"/>
|
||||
<m:naryLim m:val="undOvr"/>
|
||||
</m:mathPr></w:WordDocument>
|
||||
</xml><![endif]--><!--[if gte mso 9]><xml>
|
||||
<w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="false"
|
||||
DefSemiHidden="false" DefQFormat="false" DefPriority="99"
|
||||
LatentStyleCount="376">
|
||||
<w:LsdException Locked="false" Priority="0" QFormat="true" Name="Normal"/>
|
||||
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 1"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 2"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 3"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 4"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 5"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 6"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 7"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 8"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 9"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 6"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 7"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 8"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 9"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 1"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 2"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 3"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 4"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 5"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 6"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 7"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 8"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 9"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Normal Indent"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="footnote text"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="annotation text"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="header"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="footer"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index heading"/>
|
||||
<w:LsdException Locked="false" Priority="35" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="caption"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="table of figures"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="envelope address"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="envelope return"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="footnote reference"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="annotation reference"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="line number"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="page number"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="endnote reference"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="endnote text"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="table of authorities"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="macro"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="toa heading"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Bullet"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Number"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Bullet 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Bullet 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Bullet 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Bullet 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Number 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Number 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Number 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Number 5"/>
|
||||
<w:LsdException Locked="false" Priority="10" QFormat="true" Name="Title"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Closing"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Signature"/>
|
||||
<w:LsdException Locked="false" Priority="1" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="Default Paragraph Font"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text Indent"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Continue"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Continue 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Continue 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Continue 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Continue 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Message Header"/>
|
||||
<w:LsdException Locked="false" Priority="11" QFormat="true" Name="Subtitle"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Salutation"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Date"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text First Indent"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text First Indent 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Note Heading"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text Indent 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text Indent 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Block Text"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Hyperlink"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="FollowedHyperlink"/>
|
||||
<w:LsdException Locked="false" Priority="22" QFormat="true" Name="Strong"/>
|
||||
<w:LsdException Locked="false" Priority="20" QFormat="true" Name="Emphasis"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Document Map"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Plain Text"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="E-mail Signature"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Top of Form"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Bottom of Form"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Normal (Web)"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Acronym"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Address"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Cite"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Code"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Definition"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Keyboard"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Preformatted"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Sample"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Typewriter"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Variable"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Normal Table"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="annotation subject"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="No List"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Outline List 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Outline List 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Outline List 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Simple 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Simple 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Simple 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Classic 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Classic 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Classic 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Classic 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Colorful 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Colorful 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Colorful 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Columns 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Columns 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Columns 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Columns 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Columns 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 6"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 7"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 8"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 6"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 7"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 8"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table 3D effects 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table 3D effects 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table 3D effects 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Contemporary"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Elegant"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Professional"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Subtle 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Subtle 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Web 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Web 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Web 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Balloon Text"/>
|
||||
<w:LsdException Locked="false" Priority="39" Name="Table Grid"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Theme"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" Name="Placeholder Text"/>
|
||||
<w:LsdException Locked="false" Priority="1" QFormat="true" Name="No Spacing"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" Name="Revision"/>
|
||||
<w:LsdException Locked="false" Priority="34" QFormat="true"
|
||||
Name="List Paragraph"/>
|
||||
<w:LsdException Locked="false" Priority="29" QFormat="true" Name="Quote"/>
|
||||
<w:LsdException Locked="false" Priority="30" QFormat="true"
|
||||
Name="Intense Quote"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="19" QFormat="true"
|
||||
Name="Subtle Emphasis"/>
|
||||
<w:LsdException Locked="false" Priority="21" QFormat="true"
|
||||
Name="Intense Emphasis"/>
|
||||
<w:LsdException Locked="false" Priority="31" QFormat="true"
|
||||
Name="Subtle Reference"/>
|
||||
<w:LsdException Locked="false" Priority="32" QFormat="true"
|
||||
Name="Intense Reference"/>
|
||||
<w:LsdException Locked="false" Priority="33" QFormat="true" Name="Book Title"/>
|
||||
<w:LsdException Locked="false" Priority="37" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="Bibliography"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="TOC Heading"/>
|
||||
<w:LsdException Locked="false" Priority="41" Name="Plain Table 1"/>
|
||||
<w:LsdException Locked="false" Priority="42" Name="Plain Table 2"/>
|
||||
<w:LsdException Locked="false" Priority="43" Name="Plain Table 3"/>
|
||||
<w:LsdException Locked="false" Priority="44" Name="Plain Table 4"/>
|
||||
<w:LsdException Locked="false" Priority="45" Name="Plain Table 5"/>
|
||||
<w:LsdException Locked="false" Priority="40" Name="Grid Table Light"/>
|
||||
<w:LsdException Locked="false" Priority="46" Name="Grid Table 1 Light"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark"/>
|
||||
<w:LsdException Locked="false" Priority="51" Name="Grid Table 6 Colorful"/>
|
||||
<w:LsdException Locked="false" Priority="52" Name="Grid Table 7 Colorful"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="Grid Table 1 Light Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="Grid Table 6 Colorful Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="Grid Table 7 Colorful Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="Grid Table 1 Light Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="Grid Table 6 Colorful Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="Grid Table 7 Colorful Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="Grid Table 1 Light Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="Grid Table 6 Colorful Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="Grid Table 7 Colorful Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="Grid Table 1 Light Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="Grid Table 6 Colorful Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="Grid Table 7 Colorful Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="Grid Table 1 Light Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="Grid Table 6 Colorful Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="Grid Table 7 Colorful Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="Grid Table 1 Light Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="Grid Table 6 Colorful Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="Grid Table 7 Colorful Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="46" Name="List Table 1 Light"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark"/>
|
||||
<w:LsdException Locked="false" Priority="51" Name="List Table 6 Colorful"/>
|
||||
<w:LsdException Locked="false" Priority="52" Name="List Table 7 Colorful"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="List Table 1 Light Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="List Table 6 Colorful Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="List Table 7 Colorful Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="List Table 1 Light Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="List Table 6 Colorful Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="List Table 7 Colorful Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="List Table 1 Light Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="List Table 6 Colorful Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="List Table 7 Colorful Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="List Table 1 Light Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="List Table 6 Colorful Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="List Table 7 Colorful Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="List Table 1 Light Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="List Table 6 Colorful Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="List Table 7 Colorful Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="List Table 1 Light Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="List Table 6 Colorful Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="List Table 7 Colorful Accent 6"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Mention"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Smart Hyperlink"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Hashtag"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Unresolved Mention"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Smart Link"/>
|
||||
</w:LatentStyles>
|
||||
</xml><![endif]-->
|
||||
<style>
|
||||
<!--
|
||||
/* Font Definitions */
|
||||
@font-face
|
||||
{font-family:"Cambria Math";
|
||||
panose-1:2 4 5 3 5 4 6 3 2 4;
|
||||
mso-font-charset:0;
|
||||
mso-generic-font-family:roman;
|
||||
mso-font-pitch:variable;
|
||||
mso-font-signature:3 0 0 0 1 0;}
|
||||
@font-face
|
||||
{font-family:Calibri;
|
||||
panose-1:2 15 5 2 2 2 4 3 2 4;
|
||||
mso-font-charset:204;
|
||||
mso-generic-font-family:swiss;
|
||||
mso-font-pitch:variable;
|
||||
mso-font-signature:-469750017 -1073732485 9 0 511 0;}
|
||||
/* Style Definitions */
|
||||
p.MsoNormal, li.MsoNormal, div.MsoNormal
|
||||
{mso-style-unhide:no;
|
||||
mso-style-qformat:yes;
|
||||
mso-style-parent:"";
|
||||
margin-top:0cm;
|
||||
margin-right:0cm;
|
||||
margin-bottom:8.0pt;
|
||||
margin-left:0cm;
|
||||
line-height:107%;
|
||||
mso-pagination:widow-orphan;
|
||||
font-size:11.0pt;
|
||||
font-family:"Calibri",sans-serif;
|
||||
mso-ascii-font-family:Calibri;
|
||||
mso-ascii-theme-font:minor-latin;
|
||||
mso-fareast-font-family:Calibri;
|
||||
mso-fareast-theme-font:minor-latin;
|
||||
mso-hansi-font-family:Calibri;
|
||||
mso-hansi-theme-font:minor-latin;
|
||||
mso-bidi-font-family:"Times New Roman";
|
||||
mso-bidi-theme-font:minor-bidi;
|
||||
mso-fareast-language:EN-US;}
|
||||
.MsoChpDefault
|
||||
{mso-style-type:export-only;
|
||||
mso-default-props:yes;
|
||||
font-family:"Calibri",sans-serif;
|
||||
mso-ascii-font-family:Calibri;
|
||||
mso-ascii-theme-font:minor-latin;
|
||||
mso-fareast-font-family:Calibri;
|
||||
mso-fareast-theme-font:minor-latin;
|
||||
mso-hansi-font-family:Calibri;
|
||||
mso-hansi-theme-font:minor-latin;
|
||||
mso-bidi-font-family:"Times New Roman";
|
||||
mso-bidi-theme-font:minor-bidi;
|
||||
mso-fareast-language:EN-US;}
|
||||
.MsoPapDefault
|
||||
{mso-style-type:export-only;
|
||||
margin-bottom:8.0pt;
|
||||
line-height:107%;}
|
||||
@page WordSection1
|
||||
{size:595.3pt 841.9pt;
|
||||
margin:2.0cm 42.5pt 2.0cm 3.0cm;
|
||||
mso-header-margin:35.4pt;
|
||||
mso-footer-margin:35.4pt;
|
||||
mso-paper-source:0;}
|
||||
div.WordSection1
|
||||
{page:WordSection1;}
|
||||
-->
|
||||
</style>
|
||||
<!--[if gte mso 10]>
|
||||
<style>
|
||||
/* Style Definitions */
|
||||
table.MsoNormalTable
|
||||
{mso-style-name:"Îáû÷íàÿ òàáëèöà";
|
||||
mso-tstyle-rowband-size:0;
|
||||
mso-tstyle-colband-size:0;
|
||||
mso-style-noshow:yes;
|
||||
mso-style-priority:99;
|
||||
mso-style-parent:"";
|
||||
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
|
||||
mso-para-margin-top:0cm;
|
||||
mso-para-margin-right:0cm;
|
||||
mso-para-margin-bottom:8.0pt;
|
||||
mso-para-margin-left:0cm;
|
||||
line-height:107%;
|
||||
mso-pagination:widow-orphan;
|
||||
font-size:11.0pt;
|
||||
font-family:"Calibri",sans-serif;
|
||||
mso-ascii-font-family:Calibri;
|
||||
mso-ascii-theme-font:minor-latin;
|
||||
mso-hansi-font-family:Calibri;
|
||||
mso-hansi-theme-font:minor-latin;
|
||||
mso-bidi-font-family:"Times New Roman";
|
||||
mso-bidi-theme-font:minor-bidi;
|
||||
mso-fareast-language:EN-US;}
|
||||
</style>
|
||||
<![endif]--><!--[if gte mso 9]><xml>
|
||||
<o:shapedefaults v:ext="edit" spidmax="1026"/>
|
||||
</xml><![endif]--><!--[if gte mso 9]><xml>
|
||||
<o:shapelayout v:ext="edit">
|
||||
<o:idmap v:ext="edit" data="1"/>
|
||||
</o:shapelayout></xml><![endif]-->
|
||||
</head>
|
||||
|
||||
<body lang=RU style='tab-interval:35.4pt;word-wrap:break-word'>
|
||||
|
||||
<div class=WordSection1>
|
||||
|
||||
<p class=MsoNormal><o:p> </o:p></p>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,3 @@
|
||||
{% load static %}
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>{{ exam_set.title }} | Testpoint</title><link rel="stylesheet" href="{% static 'css/exact-exam.css' %}?v=20260719.1"></head>
|
||||
<body class="exact-exam-page"><header class="exact-exam-bar"><div><a href="{% url 'exam_list' %}" aria-label="Leave test">←</a><span><small>Exact HTML test</small><strong>{{ exam_set.title }}</strong></span></div><div><button id="exact-fullscreen" type="button">Fullscreen</button><form method="post" action="{% url 'complete_exact_exam' attempt.id %}" onsubmit="return confirm('Mark this test as complete?');">{% csrf_token %}<button type="submit" class="exact-finish">Finish test</button></form></div></header><main class="exact-exam-frame-wrap"><iframe title="{{ exam_set.title }}" src="{% url 'exact_exam_content' attempt.id %}" sandbox="allow-scripts allow-forms allow-modals allow-downloads"></iframe></main><script>document.getElementById('exact-fullscreen').addEventListener('click',function(){if(!document.fullscreenElement){document.documentElement.requestFullscreen().catch(function(){});this.textContent='Exit fullscreen';}else{document.exitFullscreen();this.textContent='Fullscreen';}});</script></body></html>
|
||||
@@ -0,0 +1,56 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% block title %}{{ exam_set.title }} | Testpoint{% endblock %}
|
||||
{% block meta_description %}Review the sections, timing, and instructions for {{ exam_set.title }}.{% endblock %}
|
||||
{% block extra_css %}<link rel="stylesheet" href="{% static 'css/exam-catalogue.css' %}?v=20260727.1">{% endblock %}
|
||||
{% block content %}
|
||||
<section class="exam-intro-page">
|
||||
<div class="exam-intro-shell">
|
||||
<a class="exam-back" href="{% url 'exam_list' %}"><i class="bi bi-arrow-left"></i> Back to tests</a>
|
||||
<div class="exam-intro-grid">
|
||||
<main class="exam-intro-card">
|
||||
<span class="exam-intro-label">{% if exam_set.access_level == 'premium' %}<i class="bi bi-stars"></i> Lifetime Premium{% else %}IELTS practice test{% endif %}</span>
|
||||
<h1>{{ exam_set.title }}</h1>
|
||||
<p>{{ exam_set.description|default:"A timed IELTS practice test designed to help you understand your current performance." }}</p>
|
||||
{% if exam_set.delivery_mode == 'exact_html' %}<p><strong>Original HTML test:</strong> this opens with the uploaded design, layout, questions, and controls intact.</p>{% endif %}
|
||||
<div class="exam-intro-stats">
|
||||
{% if exam_set.delivery_mode == 'exact_html' %}
|
||||
<div><i class="bi bi-filetype-html"></i><span><strong>Exact</strong> HTML</span></div>
|
||||
<div><i class="bi bi-aspect-ratio"></i><span><strong>Original</strong> layout</span></div>
|
||||
<div><i class="bi bi-arrows-fullscreen"></i><span><strong>Full</strong> screen</span></div>
|
||||
{% else %}
|
||||
<div><i class="bi bi-layers"></i><span><strong>{{ sections|length }}</strong> sections</span></div>
|
||||
<div><i class="bi bi-question-circle"></i><span><strong>{{ question_count }}</strong> questions</span></div>
|
||||
<div><i class="bi bi-stopwatch"></i><span><strong>{{ total_minutes }}</strong> minutes</span></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if exam_set.delivery_mode != 'exact_html' %}<h2>Test sections</h2>
|
||||
<div class="exam-section-list">
|
||||
{% for section in sections %}
|
||||
<article><span>{{ forloop.counter }}</span><div><strong>{{ section.get_section_type_display }}</strong><small>{{ section.questions.count }} question{{ section.questions.count|pluralize }} · {{ section.time_limit_minutes }} minutes</small></div></article>
|
||||
{% empty %}<p>No sections have been published for this test.</p>{% endfor %}
|
||||
</div>{% endif %}
|
||||
</main>
|
||||
<aside class="exam-rules-card">
|
||||
<span class="exam-rules-icon"><i class="bi bi-info-circle"></i></span>
|
||||
<h2>Before you begin</h2>
|
||||
<ul>
|
||||
<li>The timer continues if you refresh or close the page.</li>
|
||||
<li>Submit each section before its time expires.</li>
|
||||
<li>Objective answers are graded immediately.</li>
|
||||
<li>Writing and speaking responses may require instructor review.</li>
|
||||
</ul>
|
||||
{% if not can_access_exam %}
|
||||
<a class="exam-premium-action" href="{% url 'premium' %}"><i class="bi bi-lock-fill"></i> Unlock with Lifetime Premium</a>
|
||||
<p class="exam-premium-note">One payment unlocks this test and every future Premium test.</p>
|
||||
{% elif is_ready %}
|
||||
<form method="post" action="{% url 'start_exam' exam_set.id %}">{% csrf_token %}<button type="submit">{% if active_attempt %}Continue test{% else %}Begin test{% endif %} <i class="bi bi-arrow-right"></i></button></form>
|
||||
{% else %}
|
||||
<button type="button" disabled>Test unavailable</button>
|
||||
<p class="exam-unavailable">This test still needs content from an administrator.</p>
|
||||
{% endif %}
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,82 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}IELTS Practice Tests | Testpoint{% endblock %}
|
||||
{% block meta_description %}Browse available IELTS mock tests and continue your practice progress.{% endblock %}
|
||||
{% block extra_css %}<link rel="stylesheet" href="{% static 'css/exam-catalogue.css' %}?v=20260727.1"><link rel="stylesheet" href="{% static 'css/catalogue-density.css' %}?v=20260718.2"><link rel="stylesheet" href="{% static 'css/catalogue-compact.css' %}?v=20260727.1"><link rel="stylesheet" href="{% static 'css/catalogue-card-type.css' %}?v=20260719.1">{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="catalogue-hero">
|
||||
<div class="catalogue-hero__content">
|
||||
<span>Practice centre</span>
|
||||
<h1>IELTS Practice Tests</h1>
|
||||
<p>Choose a test, practise under realistic time limits, and review your results.</p>
|
||||
<div class="catalogue-summary" aria-label="Test catalogue summary">
|
||||
<div><strong>{{ total }}</strong><span>Available test{{ total|pluralize }}</span></div>
|
||||
<div><strong>{{ counts.in_progress }}</strong><span>In progress</span></div>
|
||||
<div><strong>{{ counts.completed }}</strong><span>Completed</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="catalogue-page">
|
||||
<div class="catalogue-shell">
|
||||
<nav class="catalogue-filters" aria-label="Filter mock tests">
|
||||
<div class="catalogue-filter-group">
|
||||
<span>Test type</span>
|
||||
<div>
|
||||
<a href="?skill=all&status={{ status_filter }}" {% if skill_filter == 'all' %}class="is-active" aria-current="page"{% endif %}><i class="bi bi-grid"></i>All tests <b>{{ all_total }}</b></a>
|
||||
<a href="?skill=reading&status={{ status_filter }}" {% if skill_filter == 'reading' %}class="is-active" aria-current="page"{% endif %}><i class="bi bi-book"></i>Reading <b>{{ skill_counts.reading }}</b></a>
|
||||
<a href="?skill=listening&status={{ status_filter }}" {% if skill_filter == 'listening' %}class="is-active" aria-current="page"{% endif %}><i class="bi bi-headphones"></i>Listening <b>{{ skill_counts.listening }}</b></a>
|
||||
<a href="?skill=writing&status={{ status_filter }}" {% if skill_filter == 'writing' %}class="is-active" aria-current="page"{% endif %}><i class="bi bi-pencil"></i>Writing <b>{{ skill_counts.writing }}</b></a>
|
||||
<a href="?skill=speaking&status={{ status_filter }}" {% if skill_filter == 'speaking' %}class="is-active" aria-current="page"{% endif %}><i class="bi bi-mic"></i>Speaking <b>{{ skill_counts.speaking }}</b></a>
|
||||
<a href="?skill=full&status={{ status_filter }}" {% if skill_filter == 'full' %}class="is-active" aria-current="page"{% endif %}><i class="bi bi-layers"></i>Full Mock Test <b>{{ skill_counts.full }}</b></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="catalogue-filter-group">
|
||||
<span>Progress</span>
|
||||
<div>
|
||||
<a href="?skill={{ skill_filter }}&status=all" {% if status_filter == 'all' %}class="is-active" aria-current="page"{% endif %}>All <b>{{ total }}</b></a>
|
||||
<a href="?skill={{ skill_filter }}&status=not_started" {% if status_filter == 'not_started' %}class="is-active" aria-current="page"{% endif %}>Not started <b>{{ counts.not_started }}</b></a>
|
||||
<a href="?skill={{ skill_filter }}&status=in_progress" {% if status_filter == 'in_progress' %}class="is-active" aria-current="page"{% endif %}>In progress <b>{{ counts.in_progress }}</b></a>
|
||||
<a href="?skill={{ skill_filter }}&status=completed" {% if status_filter == 'completed' %}class="is-active" aria-current="page"{% endif %}>Completed <b>{{ counts.completed }}</b></a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="catalogue-main">
|
||||
<div class="catalogue-heading">
|
||||
<div><span>Test library</span><h2>{% if skill_filter == 'reading' %}Reading tests{% elif skill_filter == 'listening' %}Listening tests{% elif skill_filter == 'writing' %}Writing tests{% elif skill_filter == 'speaking' %}Speaking tests{% elif skill_filter == 'full' %}Full mock tests{% elif status_filter == 'not_started' %}Tests not started{% elif status_filter == 'in_progress' %}Tests in progress{% elif status_filter == 'completed' %}Completed tests{% else %}All mock tests{% endif %}</h2></div>
|
||||
<a href="{% url 'student_dashboard' %}"><i class="bi bi-grid"></i> Dashboard</a>
|
||||
</div>
|
||||
|
||||
{% if exam_data %}
|
||||
<section class="catalogue-search-panel" aria-label="Search and filter tests">
|
||||
<label class="catalogue-search-box" for="catalogue-search"><i class="bi bi-search"></i><input id="catalogue-search" type="search" placeholder="Search tests by title..." autocomplete="off"></label>
|
||||
<div class="catalogue-part-filters" role="group" aria-label="Filter by passage part"><span>Part:</span><button class="is-active" type="button" data-part="all" aria-pressed="true">All</button><button type="button" data-part="p1" aria-pressed="false">P1</button><button type="button" data-part="p2" aria-pressed="false">P2</button><button type="button" data-part="p3" aria-pressed="false">P3</button></div>
|
||||
</section>
|
||||
<div class="catalogue-grid catalogue-grid--compact" id="catalogue-test-grid">
|
||||
{% for item in exam_data %}
|
||||
<article class="catalogue-compact-card" data-title="{{ item.exam_set.title|lower }}" data-part="{{ item.part }}">
|
||||
{% if item.requires_premium %}<span class="catalogue-premium-mark"><i class="bi bi-stars"></i> Premium</span>{% endif %}
|
||||
<span class="visually-hidden"><strong>{{ item.section_count }}</strong> section{{ item.section_count|pluralize }}; <strong>{{ item.question_count }}</strong> question{{ item.question_count|pluralize }}; <strong>{{ item.total_minutes }}</strong> min{% if item.status == 'in_progress' %}; Continue test{% endif %}</span>
|
||||
<span class="catalogue-compact-icon"><i class="bi {% if item.exam_set.category == 'reading' %}bi-book{% elif item.exam_set.category == 'listening' %}bi-headphones{% elif item.exam_set.category == 'writing' %}bi-pencil{% elif item.exam_set.category == 'speaking' %}bi-mic{% else %}bi-layers{% endif %}"></i></span>
|
||||
<div class="catalogue-compact-body"><h3>{{ item.exam_set.title }}</h3><div class="catalogue-compact-tags"><span>{{ item.exam_set.get_category_display }}</span>{% if item.part != 'all' %}<b>{{ item.part|upper }}</b>{% endif %}{% if item.status == 'completed' %}<em class="is-complete">Completed{% if item.score %} · {{ item.score }}{% endif %}</em>{% elif item.status == 'in_progress' %}<em class="is-progress">In progress</em>{% endif %}</div><p>{% if item.is_exact %}<i class="bi bi-filetype-html"></i> Exact HTML{% else %}<i class="bi bi-stopwatch"></i> {{ item.total_minutes }} min <span>·</span> {{ item.question_count }} question{{ item.question_count|pluralize }}{% endif %}</p></div>
|
||||
{% if item.status == 'completed' %}<a class="catalogue-compact-action" href="{% url 'results' item.attempt.id %}" aria-label="View results for {{ item.exam_set.title }}"><i class="bi bi-arrow-right"></i></a>{% elif item.is_locked %}<a class="catalogue-compact-action is-locked" href="{% url 'premium' %}" aria-label="Unlock {{ item.exam_set.title }} with Lifetime Premium"><i class="bi bi-lock-fill"></i></a>{% else %}<a class="catalogue-compact-action" href="{% url 'exam_detail' item.exam_set.id %}" aria-label="{% if item.status == 'in_progress' %}Continue test{% else %}View test{% endif %}: {{ item.exam_set.title }}"><i class="bi bi-arrow-right"></i></a>{% endif %}
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="catalogue-search-empty" id="catalogue-search-empty" hidden><i class="bi bi-search"></i><strong>No matching tests</strong><span>Try another title or passage part.</span></div>
|
||||
{% else %}
|
||||
<div class="catalogue-empty">
|
||||
<span><i class="bi bi-search"></i></span>
|
||||
<h3>No tests in this category</h3>
|
||||
<p>{% if total %}Try another filter to see the rest of your mock tests.{% else %}Mock tests will appear here after they are published.{% endif %}</p>
|
||||
{% if total %}<a href="?status=all">Show all tests</a>{% else %}<a href="{% url 'student_dashboard' %}">Return to dashboard</a>{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
{% block extra_js %}<script src="{% static 'js/catalogue-search.js' %}?v=20260719.1"></script>{% endblock %}
|
||||
@@ -0,0 +1,62 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static exam_content %}
|
||||
{% block title %}Results | {{ attempt.exam_set.title }}{% endblock %}
|
||||
{% block extra_css %}<link rel="stylesheet" href="{% static 'css/exam-session.css' %}?v=20260719.3"><link rel="stylesheet" href="{% static 'css/review-mode.css' %}?v=20260719.2">{% if use_split_reading_review %}<link rel="stylesheet" href="{% static 'css/reading-review.css' %}?v=20260719.7">{% endif %}<link rel="stylesheet" href="{% static 'css/exam-content-typography.css' %}?v=20260719.10"><link rel="stylesheet" href="{% static 'css/assessment-workspace.css' %}?v=20260727.2">{% endblock %}
|
||||
{% block content %}
|
||||
{% if use_split_reading_review %}
|
||||
<section class="reader-review-page assessment-page assessment-page--review" id="reader-review">
|
||||
<header class="reader-review-head assessment-bar">
|
||||
<div class="reader-review-title assessment-bar__title"><a class="assessment-bar__back" href="{% url 'student_dashboard' %}" aria-label="Back to dashboard"><i class="bi bi-arrow-left"></i></a><span class="reader-head-icon assessment-bar__icon"><i class="bi bi-book"></i></span><div><small>Reading · Review</small><h1>{{ attempt.exam_set.title }}</h1></div></div>
|
||||
<article class="assessment-metric"><span class="reader-head-icon"><i class="bi bi-bullseye"></i></span><div><small>Raw score</small><strong>{{ correct_count }} / {{ total_gradable }}</strong></div></article>
|
||||
<article class="assessment-metric"><span class="reader-head-icon reader-head-icon--green"><i class="bi bi-award"></i></span><div><small>{% if reading_band_estimated %}Estimated band{% else %}Reading band{% endif %}</small><strong>{{ reading_band|floatformat:1 }} / 9</strong>{% if reading_band_estimated %}<em>Equivalent to {{ reading_equivalent }} / 40</em>{% endif %}</div></article>
|
||||
<form class="assessment-bar__action" method="post" action="{% url 'start_exam' attempt.exam_set.id %}">{% csrf_token %}<button type="submit"><i class="bi bi-arrow-repeat"></i> Retake test</button></form>
|
||||
</header>
|
||||
|
||||
<main class="reader-review-workspace">
|
||||
<section class="reader-passage-pane" aria-label="Reading passage">
|
||||
<div class="reader-pane-heading reader-pane-heading--title"><h2>{{ attempt.exam_set.title }}</h2></div>
|
||||
{% for section in reading_passages %}<article class="reader-passage" data-passage-section="{{ section.id }}"{% if not forloop.first %} hidden{% endif %}><div class="reader-passage-content rich-passage-content">{{ section.passage_text|render_rich_text }}</div></article>{% endfor %}
|
||||
</section>
|
||||
<section class="reader-question-pane" aria-label="Answer review">
|
||||
{% for answer in reading_review_answers %}
|
||||
<article class="reader-question-review{% if forloop.first %} is-active{% endif %}" data-review-index="{{ forloop.counter0 }}" data-section-id="{{ answer.question.section_id }}" data-reference="{{ answer.question.passage_reference }}" data-state="{% if answer.is_correct is True %}correct{% elif answer.is_correct is False %}incorrect{% else %}pending{% endif %}">
|
||||
<div class="reader-review-card">
|
||||
<p class="reader-question-count">Question {{ forloop.counter }} of {{ reading_review_answers|length }}</p>
|
||||
<div class="reader-question-prompt rich-question-prompt">{{ answer.question.prompt|render_rich_text }}</div>
|
||||
<div class="reader-answer-content">
|
||||
<div class="reader-answer-grid"><div><small>Your answer</small><strong class="{% if answer.is_correct is True %}is-correct{% elif answer.is_correct is False %}is-wrong{% endif %}">{{ answer.answer_text|default:"No answer submitted" }}</strong></div><div><small>Correct answer</small><strong class="is-correct">{{ answer.question.correct_answer|default:"Instructor reviewed" }}</strong></div></div>
|
||||
</div>
|
||||
<section class="reader-evidence-content">{% if answer.question.passage_reference %}<blockquote>{{ answer.question.passage_reference }}</blockquote><button class="reader-show-evidence" type="button"><i class="bi bi-box-arrow-up-right"></i> Show in passage</button>{% else %}<p>No exact passage sentence has been attached to this question.</p>{% endif %}</section>
|
||||
</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="reader-review-footer reader-review-footer--no-legend">
|
||||
<nav class="reader-question-nav" aria-label="Review questions">{% for answer in reading_review_answers %}<button type="button" data-review-target="{{ forloop.counter0 }}" class="{% if answer.is_correct is True %}is-correct{% elif answer.is_correct is False %}is-incorrect{% else %}is-pending{% endif %}{% if forloop.first %} is-current{% endif %}" aria-label="Review question {{ forloop.counter }}">{{ forloop.counter }}</button>{% endfor %}</nav>
|
||||
<div class="reader-review-pager"><button id="reader-previous" type="button"><i class="bi bi-arrow-left"></i> Previous</button><button id="reader-next" type="button">Next <i class="bi bi-arrow-right"></i></button></div>
|
||||
</footer>
|
||||
</section>
|
||||
<script src="{% static 'js/reading-review.js' %}?v=20260727.1"></script>
|
||||
{% else %}
|
||||
<section class="results-page assessment-page assessment-page--review">
|
||||
<header class="assessment-bar assessment-bar--results">
|
||||
<div class="assessment-bar__title"><a class="assessment-bar__back" href="{% url 'student_dashboard' %}" aria-label="Back to dashboard"><i class="bi bi-arrow-left"></i></a><span class="assessment-bar__icon"><i class="bi bi-clipboard-check"></i></span><div><span>Completed test · Review</span><h1>{{ attempt.exam_set.title }}</h1><p>Review your responses and grading status.</p></div></div>
|
||||
<div class="assessment-bar__summary"><span>{{ answers|length }} responses</span>{% if pending_manual %}<span>{{ pending_manual }} awaiting review</span>{% endif %}</div>
|
||||
<form class="assessment-bar__action" method="post" action="{% url 'start_exam' attempt.exam_set.id %}">{% csrf_token %}<button type="submit"><i class="bi bi-arrow-repeat"></i> Retake test</button></form>
|
||||
</header>
|
||||
<div class="results-shell">
|
||||
<header class="results-header"><span>Performance summary</span><h2>Your test results</h2><p>Objective answers are scored immediately. Instructor-reviewed responses update after grading.</p></header>
|
||||
<div class="results-summary">
|
||||
<article><span class="result-summary-icon result-summary-icon--blue"><i class="bi bi-bullseye"></i></span><div><span>Objective score</span><strong>{% if total_gradable %}{{ correct_count }} / {{ total_gradable }}{% else %}Not applicable{% endif %}</strong></div></article>
|
||||
<article><span class="result-summary-icon result-summary-icon--green"><i class="bi bi-award"></i></span><div><span>Manual band average</span><strong>{% if average_manual_score is not None %}{{ average_manual_score|floatformat:1 }} / 9{% else %}Awaiting review{% endif %}</strong></div></article>
|
||||
<article><span class="result-summary-icon result-summary-icon--orange"><i class="bi bi-hourglass-split"></i></span><div><span>Awaiting review</span><strong>{{ pending_manual }}</strong></div></article>
|
||||
</div>
|
||||
<section class="answer-review"><div class="answer-review-heading"><span>Answer review</span><h2>Your responses</h2></div>
|
||||
{% for answer in answers %}<article class="answer-card"><div class="answer-number">{{ answer.question.order }}</div><div class="answer-body"><div class="rich-question-prompt review-question-prompt">{{ answer.question.prompt|render_rich_text }}</div><div class="answer-response"><span>Your answer</span><p>{{ answer.answer_text|default:"No typed answer submitted"|linebreaksbr }}</p>{% if answer.audio_response %}<audio controls preload="metadata" src="{{ answer.audio_response.url }}">Your browser does not support audio playback.</audio>{% endif %}</div>{% if answer.is_correct is not None %}{% if answer.is_correct %}<span class="answer-status answer-status--correct"><i class="bi bi-check-circle"></i> Correct</span>{% else %}<span class="answer-status answer-status--wrong"><i class="bi bi-x-circle"></i> Incorrect</span>{% endif %}{% elif answer.manual_score is not None %}<span class="answer-status answer-status--graded"><i class="bi bi-award"></i> Band {{ answer.manual_score|floatformat:1 }}</span>{% else %}<span class="answer-status answer-status--pending"><i class="bi bi-hourglass-split"></i> Pending instructor review</span>{% endif %}</div></article>{% empty %}<div class="results-empty">No answers were submitted for this test.</div>{% endfor %}
|
||||
</section>
|
||||
<div class="results-actions"><a href="{% url 'exam_list' %}">Browse more tests</a><a class="results-primary" href="{% url 'student_dashboard' %}">View dashboard</a></div>
|
||||
</div></section>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,448 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static exam_content %}
|
||||
{% block title %}{{ section.get_section_type_display }} | {{ section.exam_set.title }}{% endblock %}
|
||||
{% block extra_css %}<link rel="stylesheet" href="{% static 'css/exam-session.css' %}?v=20260717.4"><link rel="stylesheet" href="{% static 'css/exam-retake.css' %}?v=20260717.1"><link rel="stylesheet" href="{% static 'css/speaking-recorder.css' %}?v=20260718.1"><link rel="stylesheet" href="{% static 'css/exam-layout-polish.css' %}?v=20260719.5"><link rel="stylesheet" href="{% static 'css/grouped-questions.css' %}?v=20260719.1"><link rel="stylesheet" href="{% static 'css/listening-worksheet.css' %}?v=20260726.2"><link rel="stylesheet" href="{% static 'css/selection-annotations.css' %}?v=20260719.2"><link rel="stylesheet" href="{% static 'css/exam-content-typography.css' %}?v=20260719.7"><link rel="stylesheet" href="{% static 'css/ielts-question-paper.css' %}?v=20260726.1"><link rel="stylesheet" href="{% static 'css/listening-real-exam.css' %}?v=20260726.1"><link rel="stylesheet" href="{% static 'css/assessment-workspace.css' %}?v=20260727.2">{% endblock %}
|
||||
{% block content %}
|
||||
<section id="exam-session" class="exam-session assessment-page assessment-page--test{% if section.section_type == 'reading' and section.passage_text %} exam-session--reading{% endif %}{% if section.section_type == 'listening' %} exam-session--listening{% endif %}">
|
||||
<header class="exam-session-header assessment-bar">
|
||||
<div class="exam-session-title assessment-bar__title">
|
||||
<a class="assessment-bar__back" href="{% url 'exam_list' %}" aria-label="Leave test"><i class="bi bi-arrow-left"></i></a>
|
||||
<span class="assessment-bar__icon"><i class="bi {% if section.section_type == 'reading' %}bi-book{% elif section.section_type == 'listening' %}bi-headphones{% elif section.section_type == 'writing' %}bi-pencil{% else %}bi-mic{% endif %}"></i></span>
|
||||
<div><span>Section {{ section_number }} of {{ section_total }} · Live test</span><h1>{{ section.get_section_type_display }}</h1><p>{{ section.exam_set.title }}</p></div>
|
||||
</div>
|
||||
<div class="exam-session-controls">
|
||||
<button id="fullscreen-toggle" class="exam-fullscreen-button" type="button" aria-label="Enter fullscreen"><i class="bi bi-arrows-fullscreen"></i><span>Fullscreen</span></button>
|
||||
<div class="exam-timer-wrap"><span>Time remaining</span><strong id="timer" data-seconds="{{ remaining_seconds }}" role="timer" aria-live="off">--:--</strong></div>
|
||||
<form method="post" action="{% url 'retake_exam' attempt.id %}" onsubmit="return confirm('Start this test again? Your unfinished answers in this attempt will be removed.');">{% csrf_token %}<button class="exam-retake-button" type="submit"><i class="bi bi-arrow-repeat"></i><span>Retake</span></button></form>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<form id="exam-form" method="post" enctype="multipart/form-data" class="exam-session-form" autocomplete="off">
|
||||
{% csrf_token %}
|
||||
{% if section.section_type == 'listening' %}<section class="listening-part-banner" aria-label="Listening section instructions"><strong>Part {{ section.order }}</strong><span>Listen to the audio and answer questions {{ first_question_order }}{% if first_question_order != last_question_order %}–{{ last_question_order }}{% endif %}.</span></section>{% endif %}
|
||||
{% if section.section_type == 'reading' or section.section_type == 'listening' %}
|
||||
<div id="passage-selection-toolbar" class="passage-selection-toolbar" role="toolbar" aria-label="Selected text tools" hidden>
|
||||
<button id="passage-highlight" type="button" title="Highlight selected text"><i class="bi bi-highlighter"></i><span>Highlight</span></button>
|
||||
<button id="passage-add-note" type="button" title="Add a note to selected text"><i class="bi bi-sticky"></i><span>Note</span></button>
|
||||
<button id="passage-clear" type="button" title="Clear all highlights and notes"><i class="bi bi-eraser"></i><span>Clear</span></button>
|
||||
</div>
|
||||
<div id="passage-note-editor" class="passage-note-editor" hidden>
|
||||
<strong>Add note</strong><p id="passage-note-quote"></p><label class="visually-hidden" for="passage-note-text">Your note</label><textarea id="passage-note-text" rows="3" maxlength="500" placeholder="Write a short note about this text..."></textarea><div><button id="passage-note-cancel" type="button">Cancel</button><button id="passage-note-save" type="button">Save note</button></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="exam-workspace{% if section.section_type == 'reading' and section.passage_text %} exam-workspace--split{% else %} exam-workspace--wide{% endif %}{% if section.section_type == 'listening' %} exam-workspace--listening{% endif %}" id="exam-workspace">
|
||||
{% if section.section_type == 'reading' and section.passage_text %}
|
||||
<aside class="exam-passage" aria-label="Reading passage">
|
||||
<div class="exam-pane-heading exam-pane-heading--title"><span>{{ section.exam_set.title }}</span></div>
|
||||
<div class="exam-passage-text rich-passage-content">{{ section.passage_text|render_rich_text }}</div>
|
||||
</aside>
|
||||
<div id="exam-resizer" class="exam-resizer" role="separator" aria-label="Resize passage and questions" aria-orientation="vertical" tabindex="0"></div>
|
||||
{% endif %}
|
||||
|
||||
<main class="exam-questions" id="question-panel">
|
||||
{% if section.audio_file %}<div class="exam-audio"><div><i class="bi bi-headphones"></i><span><strong>Listening audio</strong><small>Use headphones in a quiet place.</small></span></div><audio controls preload="metadata" src="{{ section.audio_file.url }}">Your browser does not support audio playback.</audio></div>{% endif %}
|
||||
{% for block in question_blocks %}
|
||||
{% if block.kind == 'group' %}
|
||||
{{ block.group|render_question_group }}
|
||||
{% else %}
|
||||
{% with question=block.question %}
|
||||
<fieldset class="exam-question-card" id="question-{{ question.id }}" data-question-id="{{ question.id }}" data-question-order="{{ question.order }}" tabindex="-1">
|
||||
<legend><span>{{ question.order }}</span><span class="rich-question-prompt">{{ question.prompt|render_rich_text }}</span></legend>
|
||||
{% if question.question_type == 'mcq' %}
|
||||
<div class="exam-options">{% for option in question.options %}<label><input type="radio" name="q{{ question.id }}" value="{{ option }}"><span>{{ option }}</span></label>{% endfor %}</div>
|
||||
{% elif question.question_type == 'matching' and question.options %}
|
||||
<label class="visually-hidden" for="q{{ question.id }}">Answer for question {{ question.order }}</label><select id="q{{ question.id }}" name="q{{ question.id }}" class="exam-text-input"><option value="">Select an option</option>{% for option in question.options %}<option value="{{ option }}">{{ option }}</option>{% endfor %}</select>
|
||||
{% elif question.question_type == 'gap' or question.question_type == 'matching' %}
|
||||
<label class="visually-hidden" for="q{{ question.id }}">Answer for question {{ question.order }}</label><input id="q{{ question.id }}" type="text" name="q{{ question.id }}" class="exam-text-input" spellcheck="false">
|
||||
{% elif question.question_type == 'speaking' %}
|
||||
<label class="visually-hidden" for="q{{ question.id }}">Notes for question {{ question.order }}</label><textarea id="q{{ question.id }}" name="q{{ question.id }}" rows="5" class="exam-textarea" placeholder="Optional notes or typed response..."></textarea>
|
||||
<div class="speaking-upload" data-speaking-recorder><label for="q{{ question.id }}_audio"><i class="bi bi-mic"></i><span><strong>Record or upload your response</strong><small>Record in your browser, or upload MP3, M4A, WAV, WebM, or OGG · maximum 20 MB</small></span></label><div class="speaking-recorder"><button type="button" class="speaking-record-button" aria-pressed="false" aria-label="Start recording"><i class="bi bi-mic-fill"></i></button><div class="speaking-recorder__center"><div class="speaking-waveform" aria-hidden="true"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div><span class="speaking-record-status" role="status" aria-live="polite">Tap the microphone to record</span></div><time class="speaking-record-time" aria-label="Recording duration">00:00</time></div><audio class="speaking-record-preview" controls hidden></audio><div class="speaking-upload__divider"><span>or upload a file</span></div><input id="q{{ question.id }}_audio" type="file" name="q{{ question.id }}_audio" accept="audio/mpeg,audio/mp4,audio/wav,audio/webm,audio/ogg,.m4a"></div>
|
||||
{% else %}
|
||||
<label class="visually-hidden" for="q{{ question.id }}">Response for question {{ question.order }}</label><textarea id="q{{ question.id }}" name="q{{ question.id }}" rows="8" class="exam-textarea" placeholder="Write your response here..."></textarea>
|
||||
{% endif %}
|
||||
</fieldset>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if section.section_type != 'reading' and section.section_type != 'listening' %}<div class="exam-submit-area"><p><i class="bi bi-shield-check"></i> Your answers are submitted securely when you finish this section.</p><button id="submit-section" type="submit">Submit section <i class="bi bi-arrow-right"></i></button></div>{% endif %}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{% if section.section_type == 'reading' or section.section_type == 'listening' %}
|
||||
<footer class="exam-question-nav" aria-label="Question navigation">
|
||||
<div class="exam-question-numbers">
|
||||
{% for question in section.questions.all %}<button type="button" class="exam-question-number{% if forloop.first %} is-current{% endif %}" data-target="question-{{ question.id }}" aria-label="Go to question {{ question.order }}">{{ question.order }}</button>{% endfor %}
|
||||
</div>
|
||||
<div class="exam-question-actions">
|
||||
<button id="question-prev" type="button" class="exam-nav-button" disabled><i class="bi bi-arrow-left"></i><span>Previous</span></button>
|
||||
<button id="question-next" type="button" class="exam-nav-button"><span>Next</span><i class="bi bi-arrow-right"></i></button>
|
||||
<button id="submit-section" type="submit" class="exam-bottom-submit">Submit section <i class="bi bi-send"></i></button>
|
||||
</div>
|
||||
</footer>
|
||||
{% endif %}
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
(() => {
|
||||
const session = document.getElementById('exam-session');
|
||||
const form = document.getElementById('exam-form');
|
||||
const submitButton = document.getElementById('submit-section');
|
||||
const timer = document.getElementById('timer');
|
||||
let remaining = Math.max(0, Number(timer.dataset.seconds) || 0);
|
||||
let submitted = false;
|
||||
|
||||
const renderTimer = () => {
|
||||
const minutes = Math.floor(remaining / 60);
|
||||
const seconds = remaining % 60;
|
||||
timer.textContent = `${minutes}:${String(seconds).padStart(2, '0')}`;
|
||||
timer.classList.toggle('is-warning', remaining <= 300 && remaining > 0);
|
||||
};
|
||||
const submitAutomatically = () => {
|
||||
if (submitted) return;
|
||||
submitted = true;
|
||||
submitButton.disabled = true;
|
||||
submitButton.textContent = 'Submitting...';
|
||||
form.requestSubmit();
|
||||
};
|
||||
renderTimer();
|
||||
if (remaining === 0) submitAutomatically();
|
||||
const interval = window.setInterval(() => {
|
||||
remaining = Math.max(0, remaining - 1);
|
||||
renderTimer();
|
||||
if (remaining === 0) {
|
||||
window.clearInterval(interval);
|
||||
submitAutomatically();
|
||||
}
|
||||
}, 1000);
|
||||
form.addEventListener('submit', (event) => {
|
||||
if (event.defaultPrevented) return;
|
||||
if (!submitted && !window.confirm('Submit this section? You cannot return to change these answers.')) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
submitted = true;
|
||||
submitButton.disabled = true;
|
||||
});
|
||||
|
||||
const numberButtons = [...document.querySelectorAll('.exam-question-number')];
|
||||
const cards = numberButtons.map((button) => document.getElementById(button.dataset.target));
|
||||
const questionPanel = document.getElementById('question-panel');
|
||||
const previousButton = document.getElementById('question-prev');
|
||||
const nextButton = document.getElementById('question-next');
|
||||
let currentIndex = 0;
|
||||
|
||||
const setCurrent = (index) => {
|
||||
if (!numberButtons.length) return;
|
||||
currentIndex = Math.max(0, Math.min(index, numberButtons.length - 1));
|
||||
numberButtons.forEach((button, buttonIndex) => button.classList.toggle('is-current', buttonIndex === currentIndex));
|
||||
previousButton.disabled = currentIndex === 0;
|
||||
nextButton.disabled = currentIndex === numberButtons.length - 1;
|
||||
};
|
||||
const goToQuestion = (index) => {
|
||||
setCurrent(index);
|
||||
cards[currentIndex].scrollIntoView({behavior: 'smooth', block: 'center'});
|
||||
cards[currentIndex].focus({preventScroll: true});
|
||||
};
|
||||
const updateAnswered = (card, index) => {
|
||||
const radioAnswered = Boolean(card.querySelector('input[type="radio"]:checked'));
|
||||
const textAnswered = [...card.querySelectorAll('input[type="text"], textarea, select')].some((input) => input.value.trim());
|
||||
const fileAnswered = [...card.querySelectorAll('input[type="file"]')].some((input) => input.files.length);
|
||||
const answered = radioAnswered || textAnswered || fileAnswered;
|
||||
numberButtons[index].classList.toggle('is-answered', answered);
|
||||
card.classList.toggle('is-answered', answered);
|
||||
};
|
||||
numberButtons.forEach((button, index) => button.addEventListener('click', () => goToQuestion(index)));
|
||||
cards.forEach((card, index) => {
|
||||
card.querySelectorAll('input, textarea, select').forEach((input) => {
|
||||
input.addEventListener('input', () => updateAnswered(card, index));
|
||||
input.addEventListener('change', () => updateAnswered(card, index));
|
||||
});
|
||||
});
|
||||
if (previousButton) previousButton.addEventListener('click', () => goToQuestion(currentIndex - 1));
|
||||
if (nextButton) nextButton.addEventListener('click', () => goToQuestion(currentIndex + 1));
|
||||
if (numberButtons.length && 'IntersectionObserver' in window) {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
const visible = entries.filter((entry) => entry.isIntersecting).sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
|
||||
if (visible) setCurrent(cards.indexOf(visible.target));
|
||||
}, {root: questionPanel, threshold: [0.45, 0.7]});
|
||||
cards.forEach((card) => observer.observe(card));
|
||||
}
|
||||
|
||||
const fullscreenButton = document.getElementById('fullscreen-toggle');
|
||||
if (fullscreenButton) {
|
||||
fullscreenButton.addEventListener('click', async () => {
|
||||
if (!document.fullscreenElement) await session.requestFullscreen();
|
||||
else await document.exitFullscreen();
|
||||
});
|
||||
document.addEventListener('fullscreenchange', () => {
|
||||
const active = Boolean(document.fullscreenElement);
|
||||
fullscreenButton.querySelector('i').className = active ? 'bi bi-fullscreen-exit' : 'bi bi-arrows-fullscreen';
|
||||
fullscreenButton.querySelector('span').textContent = active ? 'Exit fullscreen' : 'Fullscreen';
|
||||
});
|
||||
}
|
||||
|
||||
const workspace = document.getElementById('exam-workspace');
|
||||
const resizer = document.getElementById('exam-resizer');
|
||||
if (resizer) {
|
||||
let resizing = false;
|
||||
resizer.addEventListener('pointerdown', (event) => {
|
||||
resizing = true;
|
||||
resizer.setPointerCapture(event.pointerId);
|
||||
document.body.classList.add('is-resizing-exam');
|
||||
});
|
||||
resizer.addEventListener('pointermove', (event) => {
|
||||
if (!resizing) return;
|
||||
const bounds = workspace.getBoundingClientRect();
|
||||
const percentage = ((event.clientX - bounds.left) / bounds.width) * 100;
|
||||
workspace.style.setProperty('--passage-width', `${Math.max(30, Math.min(70, percentage))}%`);
|
||||
});
|
||||
const stopResize = () => {
|
||||
resizing = false;
|
||||
document.body.classList.remove('is-resizing-exam');
|
||||
};
|
||||
resizer.addEventListener('pointerup', stopResize);
|
||||
resizer.addEventListener('pointercancel', stopResize);
|
||||
}
|
||||
|
||||
const annotationAreas = [...document.querySelectorAll('.exam-passage-text, .exam-questions')];
|
||||
const selectionToolbar = document.getElementById('passage-selection-toolbar');
|
||||
const highlightButton = document.getElementById('passage-highlight');
|
||||
const addNoteButton = document.getElementById('passage-add-note');
|
||||
const clearPassageButton = document.getElementById('passage-clear');
|
||||
const noteEditor = document.getElementById('passage-note-editor');
|
||||
const noteQuote = document.getElementById('passage-note-quote');
|
||||
const noteText = document.getElementById('passage-note-text');
|
||||
const noteSaveButton = document.getElementById('passage-note-save');
|
||||
const noteCancelButton = document.getElementById('passage-note-cancel');
|
||||
let selectedPassageRange = null;
|
||||
let lastPointer = { x: window.innerWidth / 2, y: window.innerHeight / 2 };
|
||||
const nativeHighlightsSupported = Boolean(window.CSS?.highlights && window.Highlight);
|
||||
const nativePassageHighlights = nativeHighlightsSupported ? new Highlight() : null;
|
||||
if (nativePassageHighlights) CSS.highlights.set('ielts-passage-highlight', nativePassageHighlights);
|
||||
|
||||
const selectionIsInAnnotationArea = (range) => {
|
||||
if (!annotationAreas.length || !range) return false;
|
||||
const container = range.commonAncestorContainer.nodeType === Node.TEXT_NODE
|
||||
? range.commonAncestorContainer.parentElement
|
||||
: range.commonAncestorContainer;
|
||||
return annotationAreas.some((area) => area.contains(container));
|
||||
};
|
||||
const hideSelectionToolbar = () => {
|
||||
if (selectionToolbar) selectionToolbar.hidden = true;
|
||||
};
|
||||
const showSelectionToolbar = (event = null) => {
|
||||
const selection = window.getSelection();
|
||||
if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
|
||||
hideSelectionToolbar();
|
||||
return;
|
||||
}
|
||||
const range = selection.getRangeAt(0);
|
||||
if (!selection.toString().trim() || !selectionIsInAnnotationArea(range)) {
|
||||
hideSelectionToolbar();
|
||||
return;
|
||||
}
|
||||
selectedPassageRange = range.cloneRange();
|
||||
const selectionBox = range.getBoundingClientRect();
|
||||
if (event && Number.isFinite(event.clientX) && Number.isFinite(event.clientY)) {
|
||||
lastPointer = { x: event.clientX, y: event.clientY };
|
||||
} else if (selectionBox.width || selectionBox.height) {
|
||||
lastPointer = { x: selectionBox.right, y: selectionBox.bottom };
|
||||
}
|
||||
const toolbarWidth = 166;
|
||||
selectionToolbar.style.left = `${Math.max(10, Math.min(window.innerWidth - toolbarWidth - 10, lastPointer.x + 12))}px`;
|
||||
selectionToolbar.style.top = `${Math.max(10, Math.min(window.innerHeight - 48, lastPointer.y + 12))}px`;
|
||||
selectionToolbar.hidden = false;
|
||||
};
|
||||
const addHighlight = (range, note = '') => {
|
||||
if (!range || range.collapsed) return null;
|
||||
if (nativePassageHighlights) {
|
||||
const savedRange = range.cloneRange();
|
||||
nativePassageHighlights.add(savedRange);
|
||||
return savedRange;
|
||||
}
|
||||
const mark = document.createElement('mark');
|
||||
mark.className = 'exam-highlight';
|
||||
if (note) {
|
||||
mark.dataset.note = 'true';
|
||||
mark.title = note;
|
||||
}
|
||||
try {
|
||||
range.surroundContents(mark);
|
||||
} catch (error) {
|
||||
const contents = range.extractContents();
|
||||
mark.appendChild(contents);
|
||||
range.insertNode(mark);
|
||||
}
|
||||
return mark;
|
||||
};
|
||||
const clearPassageAnnotations = () => {
|
||||
if (nativePassageHighlights) nativePassageHighlights.clear();
|
||||
annotationAreas.forEach((area) => {
|
||||
area.querySelectorAll('.exam-highlight').forEach((mark) => mark.replaceWith(...mark.childNodes));
|
||||
});
|
||||
noteEditor.hidden = true;
|
||||
hideSelectionToolbar();
|
||||
window.getSelection()?.removeAllRanges();
|
||||
};
|
||||
|
||||
if (selectionToolbar && annotationAreas.length) {
|
||||
annotationAreas.forEach((area) => area.addEventListener('pointermove', (event) => { lastPointer = { x: event.clientX, y: event.clientY }; }));
|
||||
const capturePassageSelection = (event) => {
|
||||
if (event) lastPointer = { x: event.clientX, y: event.clientY };
|
||||
window.setTimeout(() => showSelectionToolbar(event), 0);
|
||||
};
|
||||
document.addEventListener('mouseup', capturePassageSelection);
|
||||
document.addEventListener('touchend', capturePassageSelection, { passive: true });
|
||||
document.addEventListener('keyup', capturePassageSelection);
|
||||
document.addEventListener('selectionchange', () => {
|
||||
const selection = window.getSelection();
|
||||
if (!selection || selection.rangeCount === 0 || selection.isCollapsed || !selection.toString().trim()) {
|
||||
hideSelectionToolbar();
|
||||
return;
|
||||
}
|
||||
const range = selection.getRangeAt(0);
|
||||
if (selectionIsInAnnotationArea(range)) {
|
||||
window.requestAnimationFrame(() => showSelectionToolbar());
|
||||
} else {
|
||||
hideSelectionToolbar();
|
||||
}
|
||||
});
|
||||
document.addEventListener('scroll', hideSelectionToolbar, true);
|
||||
selectionToolbar.addEventListener('mousedown', (event) => event.preventDefault());
|
||||
highlightButton.addEventListener('click', () => {
|
||||
addHighlight(selectedPassageRange);
|
||||
hideSelectionToolbar();
|
||||
window.getSelection()?.removeAllRanges();
|
||||
});
|
||||
addNoteButton.addEventListener('click', () => {
|
||||
if (!selectedPassageRange) return;
|
||||
noteQuote.textContent = `“${selectedPassageRange.toString().trim().slice(0, 160)}”`;
|
||||
noteText.value = '';
|
||||
noteEditor.style.left = `${Math.max(10, Math.min(window.innerWidth - 310, lastPointer.x + 12))}px`;
|
||||
noteEditor.style.top = `${Math.max(10, Math.min(window.innerHeight - 230, lastPointer.y + 16))}px`;
|
||||
noteEditor.hidden = false;
|
||||
hideSelectionToolbar();
|
||||
noteText.focus();
|
||||
});
|
||||
noteCancelButton.addEventListener('click', () => {
|
||||
noteEditor.hidden = true;
|
||||
window.getSelection()?.removeAllRanges();
|
||||
});
|
||||
noteSaveButton.addEventListener('click', () => {
|
||||
const text = noteText.value.trim();
|
||||
if (!text || !selectedPassageRange) return;
|
||||
addHighlight(selectedPassageRange, text);
|
||||
noteEditor.hidden = true;
|
||||
window.getSelection()?.removeAllRanges();
|
||||
});
|
||||
clearPassageButton.addEventListener('click', clearPassageAnnotations);
|
||||
}
|
||||
|
||||
document.querySelectorAll('[data-speaking-recorder]').forEach((container) => {
|
||||
const fileInput = container.querySelector('input[type="file"]');
|
||||
const recordButton = container.querySelector('.speaking-record-button');
|
||||
const status = container.querySelector('.speaking-record-status');
|
||||
const recordTime = container.querySelector('.speaking-record-time');
|
||||
const preview = container.querySelector('.speaking-record-preview');
|
||||
let recorder = null;
|
||||
let stream = null;
|
||||
let chunks = [];
|
||||
let previewUrl = null;
|
||||
let timerInterval = null;
|
||||
let recordingStartedAt = null;
|
||||
|
||||
const setStatus = (message, isRecording = false) => {
|
||||
status.textContent = message;
|
||||
status.classList.toggle('is-recording', isRecording);
|
||||
};
|
||||
const stopTracks = () => {
|
||||
if (stream) stream.getTracks().forEach((track) => track.stop());
|
||||
stream = null;
|
||||
};
|
||||
const renderRecordingTime = () => {
|
||||
const elapsed = Math.max(0, Math.floor((Date.now() - recordingStartedAt) / 1000));
|
||||
recordTime.textContent = `${Math.floor(elapsed / 60)}:${String(elapsed % 60).padStart(2, '0')}`;
|
||||
};
|
||||
const stopTimer = () => {
|
||||
if (timerInterval) window.clearInterval(timerInterval);
|
||||
timerInterval = null;
|
||||
};
|
||||
const finishRecording = () => {
|
||||
const type = recorder?.mimeType || 'audio/webm';
|
||||
const recording = new File([new Blob(chunks, { type })], `speaking-response-${Date.now()}.webm`, { type: 'audio/webm' });
|
||||
const transfer = new DataTransfer();
|
||||
transfer.items.add(recording);
|
||||
fileInput.files = transfer.files;
|
||||
fileInput.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
if (previewUrl) URL.revokeObjectURL(previewUrl);
|
||||
previewUrl = URL.createObjectURL(recording);
|
||||
preview.src = previewUrl;
|
||||
preview.hidden = false;
|
||||
recordButton.classList.remove('is-recording');
|
||||
recordButton.setAttribute('aria-pressed', 'false');
|
||||
recordButton.setAttribute('aria-label', 'Record again');
|
||||
setStatus('Recording ready to submit');
|
||||
stopTimer();
|
||||
stopTracks();
|
||||
recorder = null;
|
||||
chunks = [];
|
||||
};
|
||||
|
||||
if (!navigator.mediaDevices?.getUserMedia || !window.MediaRecorder) {
|
||||
recordButton.disabled = true;
|
||||
recordButton.title = 'Your browser does not support audio recording.';
|
||||
setStatus('Recording is not supported in this browser. You can still upload audio.');
|
||||
return;
|
||||
}
|
||||
|
||||
recordButton.addEventListener('click', async () => {
|
||||
if (recorder?.state === 'recording') {
|
||||
recorder.stop();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
chunks = [];
|
||||
recorder = new MediaRecorder(stream);
|
||||
recorder.addEventListener('dataavailable', (event) => {
|
||||
if (event.data.size) chunks.push(event.data);
|
||||
});
|
||||
recorder.addEventListener('stop', finishRecording, { once: true });
|
||||
recorder.start();
|
||||
recordButton.classList.add('is-recording');
|
||||
recordButton.setAttribute('aria-pressed', 'true');
|
||||
recordButton.setAttribute('aria-label', 'Stop recording');
|
||||
setStatus('Recording… click Stop when you are finished.', true);
|
||||
recordingStartedAt = Date.now();
|
||||
renderRecordingTime();
|
||||
timerInterval = window.setInterval(renderRecordingTime, 1000);
|
||||
} catch (error) {
|
||||
stopTracks();
|
||||
stopTimer();
|
||||
setStatus('Microphone access was not granted. You can still upload an audio file.');
|
||||
}
|
||||
});
|
||||
|
||||
fileInput.addEventListener('change', () => {
|
||||
if (!fileInput.files.length) return;
|
||||
if (recorder?.state === 'recording') recorder.stop();
|
||||
if (previewUrl) URL.revokeObjectURL(previewUrl);
|
||||
previewUrl = URL.createObjectURL(fileInput.files[0]);
|
||||
preview.src = previewUrl;
|
||||
preview.hidden = false;
|
||||
recordButton.setAttribute('aria-label', 'Record again');
|
||||
setStatus('Audio file ready to submit');
|
||||
stopTimer();
|
||||
});
|
||||
form.addEventListener('submit', (event) => {
|
||||
if (recorder?.state !== 'recording') return;
|
||||
event.preventDefault();
|
||||
recorder.stop();
|
||||
setStatus('Recording saved. Submit the section again when ready.');
|
||||
}, true);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user