Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial import

  • Loading branch information...
commit 8a9da2157384da89dad6c75e2172f3faaaa62344 0 parents
Tim Baumann authored
53 README.md
@@ -0,0 +1,53 @@
+Features
+========
+
+* works offline
+* works on the iPhone
+* works offline on the iPhone
+* can play for you if you're too lazy too think
+* highly customizable (How many rows and columns do you want? How many colors?)
+
+
+API
+===
+
+ var mh = new Meisterhirn({
+ // options for the model: specifying these
+ // properties will overwrite the default properties
+ colors: 2, // binary!
+ multiple: true, // each color may appear multiple times in the solution
+ cols: 10,
+ rows: 4
+ }, {
+ // options for the view
+ messageWon: 'w00t!',
+ colors: ['#f00', '#00f'] // red and blue
+ // have a look at the source code for more options!
+ });
+ mh.inject(document.getElementById('wrapper');
+
+
+License
+=======
+
+(The MIT License)
+
+Copyright (c) 2010 Tim Baumann
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
46 assets/app.js
@@ -0,0 +1,46 @@
+//document.addEventListener('DOMContentLoaded', function() { // Der Code in der folgenden Funktion wird erst ausgeführt, wenn das Dokument selber (nicht evt. enthaltene Bilder etc.) fertig geladen ist.
+
+ var isIphone = navigator.userAgent.toLowerCase().indexOf('iphone') != -1;
+
+ var mm = new Meisterhirn({ // Einstellungen zum Spiel selber:
+ rows: 8, // Anzahl Zeilen
+ colors: 6, // Anzahl Farben
+ cols: 4, // Anzahl Spalten
+ multiple: true // Darf das Ergebnis mehrfach eine Farbe beinhalten?
+ }, { // Einstellungen zur Anzeige des Spiels#
+ gridWidth: (isIphone) ? 59 : 69, // auf dem iPhone sind die Felder nur 59 Pixel, ansonsten 69 Pixel groß
+ selectGridWidth: (isIphone) ? 43: 50 // s.o., nur für die Farbwahl
+ // ein paar Nachrichten:
+ //messageWon: 'Wir haben einen Gewinner',
+ //messageLost: 'Du Loser!',
+ //messageGaveUp: 'Du hast aufgegeben'
+ //leftBackgroundColor: '#000'
+ });
+ mm.inject(document.getElementById('game')); // Spiel mittels der inject-Methode ins Dokument einfügen
+
+ // Knöpfe unter dem Feld
+ (function(doc) { // Anonyme Funktion, die sofort ausgeführt wird, "document" ist intern auch kürzer als "doc" verfügbar
+ if(mm.autosolver) { // Nur wenn das Spiel automatisch gelöst werden kann (Worker werden unterstützt)
+ var el = doc.getElementById('controls'); // Element, in das die Buttons eingefügt werden (wird per id aus dem Dokument geholt)
+
+ //var propose = doc.createElement('button'); // Neues HTML-Element vom Typ "button"
+ //propose.appendChild(doc.createTextNode('Tipp vorschlagen')); // Text im Element => auf dem Button
+ //propose.addEventListener('click', function() { // Funktion, die ausgeführt wird, wenn Benutzer auf den Button klickt
+ //mm.propose(); // Vorschlag machen
+ //}, false); // false bitte ignorieren, hängt damit zusammen, ob ein Event zuerst auf dem umgebenden oder dem inneren Element gefeuert werden soll
+ //el.appendChild(propose); // Element ins Dokument einfügen
+
+ // Analog wird mit dem "Lösen"-Knopf verfahren
+ var solve = doc.createElement('button');
+ solve.appendChild(doc.createTextNode('Autopilot!'));
+ solve.addEventListener('click', function() {
+ mm.solve(); // Eigenständig lösen
+ }, false);
+ el.appendChild(solve);
+ } // Ende if
+ })(document); // Ende anonyme Funktion
+
+ //alert(applicationCache.status);
+ //applicationCache.swapCache();
+
+//}, false); // Ende "Funktion, die direkt nach dem Laden des Dokuments ausgeführt wird"
BIN  assets/apple-touch-icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  assets/apple-touch-startup.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 assets/cache.manifest
@@ -0,0 +1,16 @@
+CACHE MANIFEST
+
+# Diese Zahl bitte bei jeder Änderung einer Datei hochzählen, das bewirkt, dass alle Dateien aktualisiert werden:
+# 18
+
+# Diese Dateien sollen für den Offline-Betrieb gespeichert werden:
+../index.html
+../lib/meisterhirn.js
+../lib/autosolver.js
+app.js
+style.css
+wood.jpg
+lobster.otf
+# Diese Datei funktioniert nicht mit einem Manifest, vielleicht wird Apple mal seine Font-Unterstützung verbessern, dann kann ich die nächste Zeile wieder einkommentieren:
+#fonts/lobster.svg
+http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png
BIN  assets/favicon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  assets/lobster.otf
Binary file not shown
376 assets/lobster.svg
@@ -0,0 +1,376 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs >
+<font id="Lobster" horiz-adv-x="384" ><font-face
+ font-family="Lobster"
+ units-per-em="1000"
+ panose-1="2 0 6 3 0 0 0 0 0 0"
+ ascent="1000"
+ descent="-250"
+ alphabetic="0" />
+<glyph unicode=" " glyph-name="space" horiz-adv-x="217" />
+<glyph unicode="!" glyph-name="exclam" horiz-adv-x="224" d="M150 231H65L136 700H280L150 231ZM160 113T160 80T137 24T81 0T25 23T1 80T24 136T81 159T137 136Z" />
+<glyph unicode="&quot;" glyph-name="quotedbl" horiz-adv-x="420" d="M62 561L123 750H228L137 561H62ZM219 561L280 750H385L294 561H219Z" />
+<glyph unicode="#" glyph-name="numbersign" horiz-adv-x="659" d="M307 -27L332 111H214L184 -27H127L152 111H45L66 213H170L191 326H89L110 428H209L261 718H349L284 428H389L441 718H529L464 428H568L548 326H442L417 213H524L504 111H394L364 -27H307ZM262
+326L237 213H350L371 326H262Z" />
+<glyph unicode="$" glyph-name="dollar" horiz-adv-x="403" d="M110 -27L134 108Q24 117 24 222Q24 260 45 284T91 308T127 301T139 283Q99 276 99 209Q99 167 141 148L177 344Q170 350 149 367T118 392T96 416Q71 444 71 481Q71 534 118 572T225 612L244 718H302L277
+609Q364 595 364 526Q364 491 351 471T317 450T277 473Q301 487 301 521T269 569L233 408Q320 352 337 308Q346 284 346 255Q346 186 297 148T166 107L137 -27H110ZM175 144Q241 152 241 236Q241 274 212 310L175 144ZM166 500Q166 467 194 439L218 574Q166 563
+166 500Z" />
+<glyph unicode="%" glyph-name="percent" horiz-adv-x="644" d="M579 750L193 0H121L507 750H579ZM269 702Q351 702 351 589Q351 515 310 445T203 374Q148 374 128 402T107 488Q107 579 151 640T269 702ZM291 667T266 667T210 622T179 476Q179 411 206 411Q244
+411 267 468T291 596ZM517 328Q561 328 585 299T609 225T600 146T574 76T524 21T444 0T376 28T355 114Q355 205 399 266T517 328ZM503 291Q479 291 451 245T422 102Q422 37 449 37Q487 37 509 90T531 217T503 291Z" />
+<glyph unicode="&amp;" glyph-name="ampersand" horiz-adv-x="682" d="M505 375L581 370Q652 370 676 413H682Q682 371 636 328T530 274Q484 112 406 49Q379 28 359 18T309 2Q269 -6 218 -6Q120 -6 66 53T11 193T58 336T192 417Q93 471 93 569Q93 642 153 696T315
+750Q393 750 446 717T499 616Q499 524 429 524Q394 524 372 550Q389 555 402 583T416 632Q416 706 350 706Q296 706 262 670T228 585T260 492T360 418Q271 381 229 328T186 218T220 123T309 84T413 128T484 273L413 278Q347 278 319 233L312 234Q327 297 378 336T505
+375Z" />
+<glyph unicode="&apos;" glyph-name="quotesingle" horiz-adv-x="197" d="M15 561L76 750H181L90 561H15Z" />
+<glyph unicode="(" glyph-name="parenleft" horiz-adv-x="437" d="M464 750L477 710Q405 674 343 572T246 336T211 73Q211 -114 284 -221L251 -250Q138 -125 138 100Q138 231 177 362T292 598T464 750Z" />
+<glyph unicode=")" glyph-name="parenright" horiz-adv-x="413" d="M-16 -250L-29 -210Q81 -155 159 36T237 420T164 721L197 750Q310 625 310 400Q310 268 271 138T156 -98T-16 -250Z" />
+<glyph unicode="*" glyph-name="asterisk" horiz-adv-x="515" d="M223 752H287V617L394 679L424 627L315 564L424 501L394 449L287 511V376H223V511L116 449L86 501L195 564L86 627L116 679L223 617V752Z" />
+<glyph unicode="+" glyph-name="plus" horiz-adv-x="515" d="M345 439L318 317H445L422 205H294L267 82H154L181 205H53L77 317H205L232 439H345Z" />
+<glyph unicode="," glyph-name="comma" horiz-adv-x="216" d="M71 2Q24 33 24 70T47 131T102 155T153 134T171 73T136 -26T41 -126Q32 -120 32 -106T58 -64T84 -22T71 2Z" />
+<glyph unicode="-" glyph-name="hyphen" horiz-adv-x="290" d="M237 301L220 222H19L37 301H237Z" />
+<glyph unicode="." glyph-name="period" horiz-adv-x="263" d="M31 42T31 75T54 131T110 155T166 132T190 75T167 19T110 -4T54 19Z" />
+<glyph unicode="/" glyph-name="slash" horiz-adv-x="311" d="M295 750L83 -250H11L223 750H295Z" />
+<glyph unicode="0" glyph-name="zero" horiz-adv-x="546" d="M377 750Q555 750 555 489Q555 412 534 327T474 166T373 41T237 -9Q116 -9 73 54T30 254T71 503T192 682T377 750ZM188 325Q183 257 183 226Q183 75 242 75Q297 75 339 147T403 326T424 529T413 661T370
+698Q319 698 260 590T188 325Z" />
+<glyph unicode="1" glyph-name="one" horiz-adv-x="317" d="M324 748L165 0H21L153 624H58L70 670Q193 670 324 748Z" />
+<glyph unicode="2" glyph-name="two" horiz-adv-x="492" d="M286 114Q338 114 364 127T436 183Q437 167 437 139Q437 59 413 24T326 -11T192 7T70 25Q52 25 25 12T-9 -3Q-12 13 -12 43T6 116T53 194T118 266L188 341Q223 379 252 419Q318 508 318 613Q318 648
+299 671T257 695Q210 695 193 675T176 624Q176 556 214 546Q176 512 141 512T86 536T66 602Q66 661 117 705T272 749Q462 749 462 588Q462 525 434 469T360 369T268 288T175 209T106 132Q127 132 186 124T286 114Z" />
+<glyph unicode="3" glyph-name="three" horiz-adv-x="514" d="M205 257Q167 254 147 234T122 192T117 131T139 75T210 58T293 110T328 228T296 345T199 418Q280 440 324 498T369 616Q369 651 353 673T306 695Q215 695 215 614Q215 593 224 572T253 546Q215 512
+180 512T125 536T105 602Q105 660 160 704T309 749T450 707T497 607T462 500T361 417Q423 398 454 355T485 255Q485 159 410 77T227 -5Q117 -5 60 36Q38 53 22 84T6 156Q6 227 36 267T124 308Q194 308 205 257Z" />
+<glyph unicode="4" glyph-name="four" horiz-adv-x="476" d="M252 275H8Q20 311 59 392T126 549T154 690Q154 722 147 750Q193 750 225 725T258 656T242 566T205 491Q205 491 156 418Q126 375 112 349H268L349 730L497 750L411 349H475L455 275H395L337 0H193L252 275Z" />
+<glyph unicode="5" glyph-name="five" horiz-adv-x="517" d="M500 749Q502 727 502 716Q502 663 475 632T401 600T292 612T220 625L180 444Q245 475 304 475Q391 475 436 417T481 258T408 76T204 -5Q126 -5 76 19Q15 48 15 145Q15 210 54 245T141 281Q205 281
+216 230Q126 218 126 128Q126 87 152 69T216 50Q274 50 304 112T335 260Q335 312 307 351T222 391T76 335L158 734Q307 717 338 717Q419 717 500 749Z" />
+<glyph unicode="6" glyph-name="six" horiz-adv-x="497" d="M225 305Q205 334 205 363Q205 406 246 434T350 463T446 414T481 298Q481 171 402 83T211 -5Q96 -5 54 55Q16 108 16 193Q16 217 17 230Q33 467 123 608T374 750Q427 750 458 725T489 671T466 622T400
+600Q416 615 416 636T402 673T370 690T338 686T293 657T240 591T191 462T159 291T150 180Q150 110 171 86T236 61T323 132T366 284Q366 381 314 381T225 305Z" />
+<glyph unicode="7" glyph-name="seven" horiz-adv-x="464" d="M184 750H512Q512 750 342 487Q229 308 211 265Q179 192 179 136T228 39Q213 0 136 0Q86 0 60 27T33 113T51 225T94 325T166 434T250 542L348 657Q304 663 264 663Q120 663 56 592Q48 626 48 650Q48
+700 80 725T184 750Z" />
+<glyph unicode="8" glyph-name="eight" horiz-adv-x="499" d="M208 58Q257 58 290 110T323 232Q323 329 260 383Q201 344 169 281T137 166T155 86T208 58ZM203 -5Q105 -5 49 54T-8 191T38 331T172 417Q87 466 87 547T151 689T307 749T449 708T499 609T463 501T359
+417Q420 398 450 357T480 261Q480 164 399 80T203 -5ZM271 451Q319 482 345 533T372 625Q372 704 320 704Q273 704 246 665T218 572Q218 495 271 451Z" />
+<glyph unicode="9" glyph-name="nine" horiz-adv-x="489" d="M288 424Q309 399 309 374Q309 336 270 309T168 282T70 335T34 457Q34 581 109 665T293 750Q486 750 486 515Q486 364 446 247T328 63T147 -5Q93 -5 60 21T27 76T49 124T114 145Q100 131 100 110T114
+72T144 55T169 57T198 68T235 94T273 142T310 219Q349 323 361 487Q363 525 363 539Q363 625 342 654T274 684T188 615T148 467Q148 426 160 395T204 364Q265 364 288 424Z" />
+<glyph unicode=":" glyph-name="colon" horiz-adv-x="267" d="M41 102T41 135T64 191T120 215T176 192T200 135T177 79T120 56T64 79ZM91 342T91 375T114 431T170 455T226 432T250 375T227 319T170 296T114 319Z" />
+<glyph unicode=";" glyph-name="semicolon" horiz-adv-x="276" d="M94 298T94 331T117 387T173 411T229 388T253 331T230 275T173 252T117 275ZM93 18Q46 49 46 86T69 147T124 171T175 150T193 89T158 -10T63 -110Q54 -104 54 -90T80 -48T106 -6T93 18Z" />
+<glyph unicode="&lt;" glyph-name="less" horiz-adv-x="359" d="M336 429L326 374L85 254L279 158L267 101L20 238L29 279L336 429Z" />
+<glyph unicode="=" glyph-name="equal" horiz-adv-x="515" d="M468 428L445 316H76L100 428H468ZM424 213L401 101H32L56 213H424Z" />
+<glyph unicode="&gt;" glyph-name="greater" horiz-adv-x="344" d="M75 374L84 429L330 279L319 225L15 101L29 158L269 254L75 374Z" />
+<glyph unicode="?" glyph-name="question" horiz-adv-x="441" d="M359 700T392 669T425 581T405 484T354 416T291 364Q208 301 185 232H119Q119 304 183 372L237 430Q301 499 301 577Q301 612 286 629T243 646T191 623T166 570Q166 507 204 497Q178 455 131 455Q100
+455 78 477T55 539Q55 599 108 649T260 700ZM207 113T207 80T184 24T128 0T72 23T48 80T71 136T128 159T184 136Z" />
+<glyph unicode="@" glyph-name="at" horiz-adv-x="562" d="M347 98Q360 111 369 111T393 100T407 84T402 71Q365 15 302 -11T169 -38T46 9T-8 154T26 333T111 461T214 532T312 557Q491 557 491 412Q491 301 438 219T319 136Q298 136 285 144Q260 121 207 121Q185
+121 170 146T154 195T162 255T186 332T230 402T284 432T323 415L327 430L383 424L338 232Q334 216 334 209Q334 190 347 190Q375 190 399 275T424 406T404 472T324 493Q238 493 170 397T102 163Q102 113 129 83T204 52Q301 52 347 98ZM270 185V195Q270 208 273
+216L315 383Q308 390 294 390Q263 390 241 326T219 212Q219 194 225 187T247 180T270 185Z" />
+<glyph unicode="A" glyph-name="A" horiz-adv-x="668" d="M535 0H391L468 363Q394 395 333 399Q277 277 241 149T204 -57Q204 -91 208 -98Q208 -98 216 -108Q218 -111 218 -113Q189 -111 177 -110T142 -103T110 -85Q84 -54 84 4T124 174T231 399Q132 392 114 347Q118
+347 122 337T127 313T112 288T70 277T26 292T9 340Q9 386 68 420T204 455Q230 455 263 452Q345 584 437 667T612 751Q656 751 692 736L535 0ZM477 407L535 679Q449 632 353 441Q424 428 477 407Z" />
+<glyph unicode="B" glyph-name="B" horiz-adv-x="635" d="M230 636L378 656L330 434H337Q396 434 437 486T479 591T452 674T369 704Q246 704 173 639T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T349 750T526 704T584 590Q584 545 558 502T484
+432Q542 421 570 377T599 269Q599 167 539 75T400 -17Q364 -17 342 -14T301 6T282 50T295 115Q317 79 359 79T431 137T461 256T439 351T370 386Q347 386 320 383L238 0H94L230 636Z" />
+<glyph unicode="C" glyph-name="C" horiz-adv-x="497" d="M500 180L523 170Q504 118 471 82T398 27Q323 -6 243 -6Q157 -6 96 44Q63 71 44 123T24 247T33 385T66 519T127 637T224 718T360 750T486 717T535 616Q535 524 465 524Q430 524 408 550Q425 555 438 583T452
+628T449 658T429 687T383 703Q325 703 277 631T205 462T181 266T208 126T304 84Q445 84 500 180Z" />
+<glyph unicode="D" glyph-name="D" horiz-adv-x="663" d="M230 636L378 656L258 95Q285 75 315 75Q371 75 416 144T484 311T507 509T479 657T369 704Q246 704 173 639T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q645 750 645 480Q645
+353 607 239T505 56T374 -13T246 40L238 0H94L230 636Z" />
+<glyph unicode="E" glyph-name="E" horiz-adv-x="459" d="M461 180L484 170Q420 -6 218 -6Q120 -6 66 53T11 193T58 336T192 417Q93 471 93 569Q93 642 153 696T315 750Q393 750 446 717T499 616Q499 524 429 524Q394 524 372 550Q389 555 402 583T416 632Q416
+706 350 706Q296 706 262 670T228 585T260 492T360 418Q271 381 229 328T186 218T220 123T307 84T395 107T461 180Z" />
+<glyph unicode="F" glyph-name="F" horiz-adv-x="495" d="M322 419H476L456 345H306L232 0H88L232 668Q169 665 136 619T102 461Q102 420 109 408T116 393Q62 393 36 415T9 490T28 587T86 669T193 728T350 750Q367 750 424 744T525 738T606 750Q604 745 599 724T589
+694T574 668Q557 641 511 630Q460 630 371 649L322 419Z" />
+<glyph unicode="G" glyph-name="G" horiz-adv-x="578" d="M417 418H546L464 42Q437 -83 381 -145T208 -207Q141 -207 105 -167T69 -70T102 27T191 68Q262 68 280 38Q289 24 289 4T283 -39Q252 -13 221 -13T172 -36T153 -88T169 -137T219 -157T276 -132T316 -34L356
+145Q289 109 234 109Q120 109 70 179T19 356T60 549T183 693T373 750Q451 750 505 717T559 616Q559 524 489 524Q442 524 420 550Q437 555 450 583T464 628T461 658T441 687T395 703Q342 703 290 650T205 516T173 360T201 239T288 192T374 229L417 418Z" />
+<glyph unicode="H" glyph-name="H" horiz-adv-x="631" d="M397 748L332 444Q406 457 426 457T454 456L516 748H660L501 0H357L436 371Q409 381 380 381T318 377L238 0H94L239 680Q172 652 136 596T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118
+669T357 750Q371 750 397 748Z" />
+<glyph unicode="I" glyph-name="I" horiz-adv-x="375" d="M397 748L238 0H94L239 679Q173 651 136 596T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q371 750 397 748Z" />
+<glyph unicode="J" glyph-name="J" horiz-adv-x="536" d="M538 750H578L428 40Q402 -83 342 -145T165 -207Q95 -207 56 -169T17 -71T50 28T139 68Q210 68 228 38Q237 24 237 4T231 -39Q200 -13 169 -13T120 -35T101 -89T122 -139T174 -157T226 -132T264 -34L421
+680Q354 652 317 596T280 461Q280 420 287 408T294 393Q240 393 214 415T187 490Q187 588 299 669T538 750Z" />
+<glyph unicode="K" glyph-name="K" horiz-adv-x="601" d="M397 748L331 442Q331 442 559 745H664L385 424Q398 426 421 426Q545 426 545 319Q545 276 521 186T496 66Q496 15 535 0Q476 -17 436 -17Q358 -17 358 50Q358 82 384 178T411 313Q411 380 351 380Q335
+380 318 376L238 0H94L239 680Q172 652 136 596T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q371 750 397 748Z" />
+<glyph unicode="L" glyph-name="L" horiz-adv-x="392" d="M397 738L243 20Q283 11 343 -22T463 -82T574 -109T663 -93Q655 -165 627 -207T560 -250T476 -227T390 -170L306 -103Q202 -23 113 -23Q98 -23 90 -24L239 669Q173 641 136 586T99 451Q99 410 106 398T113
+383Q59 383 33 405T6 480Q6 578 118 659T357 740Q371 740 397 738Z" />
+<glyph unicode="M" glyph-name="M" horiz-adv-x="785" d="M650 0H506L606 473L416 0H279V427L147 0H67L291 687Q215 663 173 605T130 461Q130 420 137 408T144 393Q90 393 64 415T37 494T85 610T210 708T362 746Q400 746 431 736V160L650 736H807L650 0Z" />
+<glyph unicode="N" glyph-name="N" horiz-adv-x="702" d="M448 564L437 231Q437 156 447 122L580 748H724L565 0H421Q363 0 363 204L370 523Q370 584 368 612L238 0H94L239 680Q172 652 136 596T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118
+669T357 750Q417 750 432 714T448 564Z" />
+<glyph unicode="O" glyph-name="O" horiz-adv-x="658" d="M388 656Q253 478 253 237Q253 167 273 121T333 75T417 142T487 308T515 500Q515 589 490 642Q460 704 369 704Q246 704 173 639T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T365
+750T566 682T631 479Q631 405 609 321T549 162T454 40T332 -9Q232 -9 180 44T127 217Q127 371 178 510Q203 578 245 621T341 664Q361 664 388 656Z" />
+<glyph unicode="P" glyph-name="P" horiz-adv-x="573" d="M230 636L378 656L307 322Q379 328 430 406T482 568Q482 628 451 666T358 704Q236 704 168 640T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T351 750T533 694T593 553Q593 451 513
+368T304 285H299L238 0H94L230 636Z" />
+<glyph unicode="Q" glyph-name="Q" horiz-adv-x="658" d="M378 656Q243 478 243 238Q243 189 254 148Q287 157 314 157Q363 157 398 127Q446 189 480 295T515 500Q515 589 490 642Q460 704 369 704Q246 704 173 639T99 461Q99 420 106 408T113 393Q59 393 33 415T6
+490Q6 588 118 669T365 750T566 682T631 479Q631 367 585 242T463 48Q490 10 516 -9T584 -29Q590 -29 606 -27Q588 -76 563 -94T503 -113Q447 -113 421 -84T378 -2Q352 -9 332 -9Q117 -9 117 222Q117 372 172 512Q198 579 240 621T333 664Q352 664 378 656ZM289
+120Q278 120 265 117Q286 75 322 75Q335 75 348 82Q327 120 289 120Z" />
+<glyph unicode="R" glyph-name="R" horiz-adv-x="601" d="M230 636L378 656L328 424H337Q396 424 437 480T479 590T452 674T369 704Q246 704 173 639T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T349 750T526 704T584 590Q584 543 555 496T476
+419Q545 399 545 319Q545 275 521 185T496 66Q496 15 535 0Q476 -17 436 -17Q358 -17 358 50Q358 82 384 178T410 313Q410 381 350 381Q334 381 318 377L238 0H94L230 636Z" />
+<glyph unicode="S" glyph-name="S" horiz-adv-x="570" d="M544 630Q544 586 522 558T467 529T416 550Q436 562 448 586T461 638T443 684T386 703T321 680T295 619T311 549T353 495L408 446Q437 419 462 392T503 322T520 227Q520 121 448 58T255 -5Q145 -5 88 36Q66
+53 50 84T34 156Q34 223 77 261T185 300T262 249Q201 244 173 218T145 142T175 68T244 43Q300 43 327 84T354 177T338 269T298 334L246 390L194 442Q138 496 138 568T211 695T376 750Q544 750 544 630Z" />
+<glyph unicode="T" glyph-name="T" horiz-adv-x="481" d="M679 635T663 627T616 618T439 644L301 0H157L299 661Q203 661 151 619T99 460Q99 418 106 406T113 392Q59 392 33 414T6 489T25 586T83 668T190 727T347 749Q360 749 454 741T615 732T719 747Q716 739
+712 718T702 683T688 652Z" />
+<glyph unicode="U" glyph-name="U" horiz-adv-x="678" d="M557 748H700L541 0H397L408 52Q352 1 311 1Q220 1 173 49T126 214T168 475T285 695Q198 674 149 614T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q414 750 432 745Q365
+657 309 504T253 237Q253 167 273 121T332 75Q386 75 429 152L557 748Z" />
+<glyph unicode="V" glyph-name="V" horiz-adv-x="615" d="M397 748L406 133L616 745H686L408 0H264V683Q183 658 141 601T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q371 750 397 748Z" />
+<glyph unicode="W" glyph-name="W" horiz-adv-x="970" d="M397 748L406 133L616 745H743V133L962 745H1032L754 0H610V509L408 0H264V683Q183 658 141 601T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q371 750 397 748Z" />
+<glyph unicode="X" glyph-name="X" horiz-adv-x="620" d="M552 0H393L340 250L195 0H134L322 332L248 683Q177 657 138 600T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q371 750 397 748L440 540L556 745H626L458 454L552 0Z" />
+<glyph unicode="Y" glyph-name="Y" horiz-adv-x="620" d="M438 0H278L344 308L248 683Q177 657 138 600T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q371 750 397 748L484 390L632 745H698L504 308L438 0Z" />
+<glyph unicode="Z" glyph-name="Z" horiz-adv-x="530" d="M404 78Q397 78 392 86T386 106Q386 167 450 167Q471 167 484 150T497 109Q497 67 463 34T372 0H11L367 708Q321 710 267 710Q185 710 185 688Q192 688 197 680T202 659Q202 599 139 599Q118 599 105 616T92
+657Q92 698 122 724T209 750H552L204 58Q250 56 349 56Q404 56 404 78Z" />
+<glyph unicode="[" glyph-name="bracketleft" horiz-adv-x="400" d="M182 -188L169 -250H-24L188 750H381L368 689H247L61 -188H182Z" />
+<glyph unicode="\" glyph-name="backslash" horiz-adv-x="362" d="M254 -250L42 750H114L326 -250H254Z" />
+<glyph unicode="]" glyph-name="bracketright" horiz-adv-x="400" d="M175 688L188 750H381L169 -250H-24L-11 -189H110L296 688H175Z" />
+<glyph unicode="^" glyph-name="asciicircum" horiz-adv-x="421" d="M343 561H311L251 641L94 561H50L262 750H283L343 561Z" />
+<glyph unicode="_" glyph-name="underscore" horiz-adv-x="444" d="M404 79L387 0H36L54 79H404Z" />
+<glyph unicode="`" glyph-name="grave" horiz-adv-x="201" d="M83 561L24 750H129L158 561H83Z" />
+<glyph unicode="a" glyph-name="a" horiz-adv-x="503" d="M317 500H461L389 160Q385 138 385 129Q385 91 435 91Q461 91 500 122Q514 133 536 152T567 179H601Q601 179 568 144Q469 41 412 13Q386 0 364 0Q261 0 242 76Q182 -6 111 -6T11 31T-18 122T-10 226T17
+328T65 416T140 476T244 499Q281 499 311 474L317 500ZM252 443Q198 443 158 349T117 148Q117 77 175 77Q205 77 239 127Q240 142 245 160L301 425Q280 443 252 443Z" />
+<glyph unicode="b" glyph-name="b" horiz-adv-x="430" d="M99 680L247 700L199 473Q238 502 285 502Q351 502 381 465T412 371T395 250T347 128T264 34T147 -3Q-18 -3 -18 111Q-18 133 -12 160L99 680ZM270 191T285 258T300 367T283 425T250 442T215 438T189 428L132
+160Q124 122 124 103T134 76T168 68Q206 68 238 129Z" />
+<glyph unicode="c" glyph-name="c" horiz-adv-x="360" d="M292 401Q297 419 297 429Q297 463 260 463Q202 463 162 373T122 192Q122 141 137 113T195 85Q286 85 369 179H403Q395 170 374 141T334 92T286 48Q225 0 124 0Q-13 0 -13 164Q-13 263 22 346Q62 443 143
+482Q188 503 244 503Q354 503 354 434Q354 417 349 401Q339 407 326 407T292 401Z" />
+<glyph unicode="d" glyph-name="d" horiz-adv-x="510" d="M355 680L503 700L389 160Q384 133 384 128Q384 91 434 91Q460 91 499 122Q513 133 535 152T566 179H600Q600 179 566 144Q468 41 412 13Q385 0 363 0Q261 0 242 76Q182 -6 111 -6T11 31T-18 122T-10 226T17
+328T65 416T140 476T244 499Q281 499 311 474L355 680ZM252 443Q198 443 158 349T117 148Q117 77 175 77Q205 77 239 127Q240 142 245 160L301 425Q280 443 252 443Z" />
+<glyph unicode="e" glyph-name="e" horiz-adv-x="355" d="M117 158Q117 113 141 93T201 72T290 111T367 204H412Q363 116 291 58T130 0Q61 0 22 45T-18 151T-6 268T31 380T105 473T218 509Q346 509 346 405Q346 321 275 267T120 201Q117 177 117 158ZM286 400Q286
+456 251 456Q225 456 200 423Q152 362 128 249Q194 250 239 297T286 400Z" />
+<glyph unicode="f" glyph-name="f" horiz-adv-x="271" d="M388 600H341Q343 620 343 631T332 652T303 661T264 643T235 579L218 500H291L284 460H210L95 -80Q58 -250 -84 -250Q-132 -250 -167 -220T-202 -149T-190 -85T-150 -43Q-108 -15 -30 8L91 579Q127 749
+273 749Q321 749 356 719T391 641Q391 618 388 600ZM-147 -128Q-147 -139 -135 -150T-107 -161Q-67 -161 -50 -83L-37 -25Q-90 -43 -118 -66T-147 -128Z" />
+<glyph unicode="g" glyph-name="g" horiz-adv-x="495" d="M312 500H456L362 57Q474 115 516 210L512 131Q503 86 461 56T350 0L333 -80Q297 -250 153 -250Q105 -250 73 -225T41 -149T81 -66T204 -5L214 40Q161 -8 98 -8T5 35T-25 127T-18 223T6 320T51 410T122
+474T221 499T301 452L312 500ZM233 443Q188 443 156 386Q98 285 98 151Q98 88 171 88Q198 88 231 123L290 400Q267 443 233 443ZM96 -139Q96 -151 105 -161T130 -172T162 -149T188 -83L194 -53Q96 -91 96 -139Z" />
+<glyph unicode="h" glyph-name="h" horiz-adv-x="515" d="M438 351L397 160Q392 140 392 128Q392 91 442 91Q468 91 507 122Q521 133 543 152T574 179H608Q608 179 574 144Q476 41 420 13Q393 0 371 0Q247 0 247 109Q247 132 253 160L291 340Q294 354 294 373T281
+409T242 425T186 404L100 0H-44L101 680L249 700L195 447Q270 500 318 500T403 462T440 375Q440 359 438 351Z" />
+<glyph unicode="i" glyph-name="i" horiz-adv-x="269" d="M64 500H208L136 160Q132 138 132 129Q132 91 182 91Q208 91 247 122Q261 133 283 152T314 179H348Q348 179 314 144Q216 41 160 13Q133 0 111 0Q-14 0 -14 109Q-14 132 -8 160L64 500ZM83 599T83 632T106
+688T162 712T218 689T242 632T219 576T162 553T106 576Z" />
+<glyph unicode="j" glyph-name="j" horiz-adv-x="221" d="M54 500H198L105 62Q214 115 258 210L254 131Q245 88 204 62T95 16L75 -80Q39 -250 -105 -250Q-153 -250 -188 -220T-223 -135T-180 -49T-51 8L54 500ZM65 601T65 634T88 690T144 714T200 691T224 634T201
+578T144 555T88 578ZM-168 -128Q-168 -139 -156 -150T-128 -161T-95 -143T-70 -83L-58 -25Q-111 -43 -139 -66T-168 -128Z" />
+<glyph unicode="k" glyph-name="k" horiz-adv-x="489" d="M370 500H478L275 363Q288 366 301 366Q343 366 380 328T417 242Q417 229 414 217L400 160Q395 142 395 128Q395 91 445 91Q463 91 481 105T523 144T560 179H594Q585 170 552 133L495 71Q471 46 436 23T374
+0Q315 0 282 27T249 107Q249 133 256 160L267 206Q270 219 270 239T257 275T219 291T160 269L103 0H-41L104 680L252 700L177 350L338 476Q370 501 370 500Z" />
+<glyph unicode="l" glyph-name="l" horiz-adv-x="286" d="M111 680L259 700L144 160Q139 135 139 128Q139 91 189 91Q215 91 254 122Q268 133 290 152T321 179H355Q355 179 322 144Q223 41 166 13Q140 0 118 0Q-6 0 -6 109Q-6 132 0 160L111 680Z" />
+<glyph unicode="m" glyph-name="m" horiz-adv-x="744" d="M683 351L642 160Q637 140 637 123Q637 82 678 82Q728 82 783 184H830Q830 184 798 146Q711 37 662 12Q638 0 616 0Q492 0 492 109Q492 132 498 160L536 340Q539 353 539 373T526 409T488 425T435 407Q440
+387 440 376T438 351L364 0H219L291 340Q294 354 294 373T281 409T243 425T187 404L101 0H-43L63 500H207L196 447Q269 500 325 500Q353 500 380 482T424 434Q507 500 570 500Q612 500 648 462T685 374Q685 367 683 351Z" />
+<glyph unicode="n" glyph-name="n" horiz-adv-x="503" d="M446 351L405 160Q400 142 400 128Q400 91 450 91Q468 91 481 98T514 125T545 154H579Q571 146 541 112T490 58T438 19T379 0Q255 0 255 109Q255 132 261 160L299 340Q302 354 302 373T289 409T250 425T193
+404L108 0H-36L70 500H214L202 446Q276 500 333 500Q375 500 411 462T448 375Q448 359 446 351Z" />
+<glyph unicode="o" glyph-name="o" horiz-adv-x="418" d="M256 510Q373 510 377 363Q386 354 410 354T468 377T511 403L515 382Q465 319 374 294Q361 152 294 73T146 -6T29 32T-7 158Q-7 332 68 421T256 510ZM192 91Q222 91 245 120Q287 173 300 284Q279 284 269
+297T258 330T270 371T302 399Q297 451 260 451Q227 451 200 419T158 338Q126 242 126 167T192 91Z" />
+<glyph unicode="p" glyph-name="p" horiz-adv-x="455" d="M63 500H207L203 481Q237 499 273 499Q353 499 389 467T426 359Q426 328 420 289Q378 1 201 1Q154 1 107 31L55 -214L-96 -250L63 500ZM120 93Q144 75 183 75T245 117T286 250T305 380T291 435T250 450T192
+429L120 93Z" />
+<glyph unicode="q" glyph-name="q" horiz-adv-x="476" d="M325 500H469L317 -214L166 -250L245 122Q174 4 97 4Q45 4 16 30T-14 110Q-14 281 60 390T241 499Q301 499 319 472L325 500ZM302 413Q302 455 264 455T191 407T134 287T112 161T118 92T145 75Q185 75
+258 184L293 350Q302 395 302 413Z" />
+<glyph unicode="r" glyph-name="r" horiz-adv-x="393" d="M74 500H218L207 450Q271 500 325 500Q358 500 377 483T397 436T377 383T322 358Q303 358 294 368T283 391Q280 424 264 424Q230 424 195 392L112 0H-32L74 500Z" />
+<glyph unicode="s" glyph-name="s" horiz-adv-x="406" d="M143 490L288 520V506Q288 436 305 378T339 270T356 191T355 153Q395 188 420 218L446 184L338 93Q294 0 162 0Q73 0 32 29T-9 123T13 223T67 260Q108 334 143 490ZM144 199Q144 171 125 153T83 135T42
+144Q42 59 127 59Q156 59 183 92T210 178Q210 202 187 275T163 418Q162 413 143 349T111 255Q144 244 144 199Z" />
+<glyph unicode="t" glyph-name="t" horiz-adv-x="292" d="M106 638L254 658L220 500H280L272 460H212Q144 149 144 129Q144 91 194 91Q220 91 259 122Q273 133 295 152T326 179H360Q360 179 326 144Q228 41 172 13Q145 0 123 0Q-1 0 -1 109Q-1 145 31 290T68 460H35L43
+500H76L106 638Z" />
+<glyph unicode="u" glyph-name="u" horiz-adv-x="520" d="M331 500H475L403 160Q399 138 399 129Q399 91 449 91Q475 91 514 122Q528 133 550 152T581 179H615Q615 179 582 144Q483 41 426 13Q400 0 378 0Q268 0 255 84Q165 0 111 0Q-14 0 -14 109Q-14 132 -8
+160L64 500H208L136 160Q132 138 132 129Q132 91 182 91Q208 91 253 127Q254 142 259 160L331 500Z" />
+<glyph unicode="v" glyph-name="v" horiz-adv-x="416" d="M271 488T288 504T332 520T375 496T392 419T376 297T328 158T240 45T111 0Q-13 0 -13 109Q-13 136 -8 160L64 500H208L136 160Q131 137 131 123Q131 91 173 91T254 151T314 286T334 419Q322 415 308 415T282
+431T271 468Z" />
+<glyph unicode="w" glyph-name="w" horiz-adv-x="671" d="M535 488T552 504T596 520T639 496T656 419T640 297T592 158T504 45T375 0Q268 0 253 83Q162 0 110 0Q-15 0 -15 109Q-15 132 -9 160L63 500H207L135 160Q131 138 131 129Q131 91 181 91Q209 91 251 126Q251
+140 256 160L328 500H472L400 160Q395 137 395 123Q395 91 437 91T518 151T578 286T598 419Q586 415 572 415T546 431T535 468Z" />
+<glyph unicode="x" glyph-name="x" horiz-adv-x="365" d="M-34 58L-53 88Q0 124 75 201L10 500H154L205 265Q245 301 273 344T302 421Q290 419 285 419Q238 419 238 475Q238 499 257 511T304 524T347 500T362 440Q362 362 216 213L229 155Q235 130 238 119Q247
+91 288 91Q314 91 353 122Q367 133 389 152T420 179H454L420 144Q322 41 266 13Q239 0 217 0Q152 0 129 27T85 155L84 158L-34 58Z" />
+<glyph unicode="y" glyph-name="y" horiz-adv-x="510" d="M336 500H480L387 62Q496 115 540 210L536 131Q527 88 486 62T377 16L357 -80Q321 -250 177 -250Q129 -250 94 -220T59 -149T71 -85T110 -42Q153 -14 231 8L245 76Q162 0 111 0Q-14 0 -14 109Q-14 132
+-8 160L64 500H208L136 160Q132 138 132 129Q132 91 182 91Q211 91 257 130L336 500ZM114 -128Q114 -139 126 -150T154 -161T187 -143T212 -83L224 -25Q171 -43 143 -66T114 -128Z" />
+<glyph unicode="z" glyph-name="z" horiz-adv-x="383" d="M246 62Q239 62 234 70T228 90Q228 151 292 151Q313 151 326 134T339 93Q339 52 309 26T222 0H-47L216 458Q170 460 143 460Q88 460 88 438Q95 438 100 430T105 409Q105 349 42 349Q21 349 8 366T-5 407Q-5
+448 25 474T112 500H381L118 42Q164 40 191 40Q246 40 246 62Z" />
+<glyph unicode="{" glyph-name="braceleft" horiz-adv-x="352" d="M187 390L180 549Q180 653 246 714Q285 750 340 750H383L374 700Q338 700 318 696T283 674Q239 625 237 536L243 365Q240 285 203 254Q215 240 215 218Q215 175 156 51T96 -124Q96 -204 181 -204L172
+-249H163Q112 -249 90 -242T49 -207T30 -134T83 18Q150 154 150 197Q150 228 109 228Q96 228 77 225L89 282Q107 279 125 279T157 289T178 318Q187 346 187 390Z" />
+<glyph unicode="|" glyph-name="bar" horiz-adv-x="532" d="M312 751V-250H219V751H312Z" />
+<glyph unicode="}" glyph-name="braceright" horiz-adv-x="352" d="M226 111L233 -48Q233 -152 166 -214Q128 -249 73 -249H30L39 -199Q75 -199 95 -195T130 -173Q174 -124 176 -35L170 136Q173 216 210 247Q198 261 198 283Q198 326 257 450T317 625Q317 705
+232 705L241 750H250Q301 750 323 743T364 707T383 634T330 482Q263 347 263 304Q263 273 304 273Q316 273 336 276L324 219Q306 222 288 222T256 212T235 183Q226 154 226 111Z" />
+<glyph unicode="~" glyph-name="asciitilde" horiz-adv-x="431" d="M444 670L450 669Q441 632 393 601T300 569T201 587T115 606T55 580L49 582Q98 680 216 680Q254 680 304 664T388 647T444 670Z" />
+<glyph unicode="&#xa1;" glyph-name="exclamdown" horiz-adv-x="219" d="M69 221H154L83 -248H-61L69 221ZM59 339T59 372T82 428T138 452T194 429T218 372T195 316T138 293T82 316Z" />
+<glyph unicode="&#xa2;" glyph-name="cent" horiz-adv-x="403" d="M127 -27L158 146Q103 154 67 198T31 316Q31 422 86 502T239 595L261 718H319L292 596Q382 590 382 528Q382 511 377 495H320Q325 513 325 523Q325 557 288 557H283L207 214Q212 213 229 213T272
+224T313 247T354 281Q332 151 192 145L154 -27H127ZM188 503T162 442T136 319T173 229L228 534Q188 503 162 442Z" />
+<glyph unicode="&#xa3;" glyph-name="sterling" horiz-adv-x="465" d="M420 423L426 422Q417 385 369 354T265 322H249L193 91Q209 93 242 94T297 97T353 115T427 158Q419 86 391 43T323 0H28L114 358Q109 359 97 359Q59 359 31 333L25 335Q58 402 130 424L202
+719L352 750L272 419Q331 400 365 400T420 423Z" />
+<glyph unicode="&#xa4;" glyph-name="currency" horiz-adv-x="500" d="M68 492L106 528L162 472Q203 502 252 502T342 473L398 529L434 493L379 438Q409 397 409 347T379 255L434 200L398 164L343 219Q303 190 253 190T161 220L105 164L69 200L125 256Q96 296
+96 345T125 435L68 492ZM294 446T253 446T183 417T153 346T182 276T253 246T323 275T353 346T324 416Z" />
+<glyph unicode="&#xa5;" glyph-name="yen" horiz-adv-x="474" d="M314 307H445L431 257H303L289 192H420L406 142H278L248 0H88L118 142H19L33 192H129L143 257H44L58 307H154L42 750H206L294 389L444 750H510L314 307Z" />
+<glyph unicode="&#xa6;" glyph-name="brokenbar" horiz-adv-x="532" d="M312 222V-250H219V222H312ZM312 301H219V751H312V301Z" />
+<glyph unicode="&#xa7;" glyph-name="section" horiz-adv-x="542" d="M525 654Q525 619 507 597T463 574T422 590Q438 600 448 619T458 660T444 697T396 713T336 681T308 612T328 545T378 491L436 444Q465 421 485 387T506 298T475 195T390 136V132Q390 47 332
+-3T178 -54Q8 -54 8 75Q8 131 35 165T104 200T183 150Q135 146 119 128T102 67Q102 -4 178 -4Q226 -4 245 22T264 95T246 175T200 233L148 280Q84 335 84 402Q84 446 113 481T188 535Q183 560 183 583Q183 659 247 704T390 750Q525 750 525 654ZM384 183Q403 207
+403 243T389 306T351 355T303 395Q233 448 209 488Q190 469 190 445T216 393T274 340T340 273T384 183Z" />
+<glyph unicode="&#xa8;" glyph-name="dieresis" horiz-adv-x="392" d="M92 573T74 590T56 633T74 677T117 695T160 677T178 634T160 591T117 573ZM272 573T254 590T236 633T254 677T297 695T340 677T358 634T340 591T297 573Z" />
+<glyph unicode="&#xa9;" glyph-name="copyright" horiz-adv-x="587" d="M372 369Q367 374 367 390Q360 410 341 421T292 432T235 409T207 341T234 265T307 234T377 279L421 250Q376 182 298 182Q238 182 195 227T152 336T195 441T300 484L299 481Q346 481 380
+455T424 389L372 369ZM535 225T464 151T294 76T123 150T51 331T122 512T293 587T464 513T535 332ZM97 420T97 331T155 180T294 118T434 180T492 331T434 482T295 544T155 482Z" />
+<glyph unicode="&#xaa;" glyph-name="ordfeminine" horiz-adv-x="345" d="M320 740L278 556L275 538Q275 518 296 518Q306 518 311 520Q294 470 249 470T193 511Q159 467 118 467T60 487T43 535Q43 617 79 678T195 739Q215 739 234 725L237 740H320ZM195 556L228
+699Q217 709 199 709Q168 709 145 658T121 550Q121 512 155 512Q180 512 195 556Z" />
+<glyph unicode="&#xab;" glyph-name="guillemotleft" horiz-adv-x="589" d="M336 429L326 374L85 254L279 158L267 101L20 238L29 279L336 429ZM546 429L536 374L295 254L489 158L477 101L230 238L239 279L546 429Z" />
+<glyph unicode="&#xac;" glyph-name="logicalnot" horiz-adv-x="444" d="M399 301L348 51H235L270 222H19L37 301H399Z" />
+<glyph unicode="&#xad;" glyph-name="uni00AD" horiz-adv-x="290" d="M237 301L220 222H19L37 301H237Z" />
+<glyph unicode="&#xae;" glyph-name="registered" horiz-adv-x="553" d="M518 228T447 154T277 79T106 153T34 334T105 515T276 590T447 516T518 335ZM80 423T80 334T138 183T277 121T417 183T475 334T417 485T278 547T138 485ZM176 192L177 483H271Q325 483 358
+461T391 398Q391 372 375 351T332 322L397 197L350 190L288 315H222V192H176ZM222 442V353H274Q345 353 345 397T272 442H222Z" />
+<glyph unicode="&#xb0;" glyph-name="degree" horiz-adv-x="314" d="M199 702Q281 702 281 589Q281 515 240 445T133 374Q78 374 58 402T37 488Q37 579 81 640T199 702ZM221 667T196 667T140 622T109 476Q109 411 136 411Q174 411 197 468T221 596Z" />
+<glyph unicode="&#xb1;" glyph-name="plusminus" horiz-adv-x="533" d="M375 543L348 421H475L452 309H324L297 186H184L211 309H83L107 421H235L262 543H375ZM416 147L399 68H31L49 147H416Z" />
+<glyph unicode="&#xb2;" glyph-name="uni00B2" horiz-adv-x="300" d="M71 416L176 407Q203 407 221 414T263 444Q263 369 248 356Q228 339 195 339T121 349T63 359T37 356T18 349T5 343Q3 355 3 371T17 415T52 463L144 556Q194 608 194 676Q194 695 183 707T152
+720Q112 720 112 677Q112 646 134 640Q112 621 92 621T60 634T48 674T77 725T168 749Q278 749 278 663Q278 597 218 544Q192 521 165 500L111 458Q84 435 71 416Z" />
+<glyph unicode="&#xb3;" glyph-name="uni00B3" horiz-adv-x="316" d="M129 484Q78 480 78 420Q78 395 91 386T132 376T180 404T200 468T182 531T125 571Q172 582 198 614T224 672Q224 720 187 720Q135 720 135 677Q135 646 157 640Q135 621 115 621T83 634T71
+674T103 725T189 749T271 726T298 670Q298 607 219 570Q291 549 291 482Q291 430 248 386T142 342Q13 342 13 429Q13 468 31 489T85 511T129 484Z" />
+<glyph unicode="&#xb4;" glyph-name="acute" horiz-adv-x="201" d="M83 561L174 750H279L158 561H83Z" />
+<glyph unicode="&#xb5;" glyph-name="uni00B5" horiz-adv-x="520" d="M64 500H208L136 160Q132 138 132 129Q132 91 182 91Q208 91 253 127Q254 142 259 160L331 500H475L403 160Q399 138 399 129Q399 91 449 91Q475 91 514 122Q528 133 550 152T581 179H615Q615
+179 582 144Q483 41 426 13Q400 0 378 0Q268 0 255 84Q165 0 111 0H102L74 -131L-77 -167L64 500Z" />
+<glyph unicode="&#xb6;" glyph-name="paragraph" horiz-adv-x="542" d="M239 -81H145L222 288Q150 302 111 359T72 492Q72 594 139 671T322 749Q404 749 455 709T507 584Q507 554 499 512L372 -81H278L359 299Q344 294 316 288L239 -81ZM327 339H333Q353 339 368
+343L416 570Q422 598 422 619Q422 661 399 682L327 339Z" />
+<glyph unicode="&#xb7;" glyph-name="middot" horiz-adv-x="434" d="M120 227T120 267T148 335T216 364T284 336T313 267T285 199T216 171T148 199Z" />
+<glyph unicode="&#xb8;" glyph-name="cedilla" horiz-adv-x="833" d="M238 -58Q300 -58 300 -108T264 -188T177 -218T73 -190Q91 -158 113 -158T155 -171T187 -185T208 -172T217 -144T208 -118T175 -107T126 -119L179 29L214 6L185 -66Q217 -58 238 -58Z" />
+<glyph unicode="&#xb9;" glyph-name="uni00B9" horiz-adv-x="217" d="M198 749L106 345H22L99 682H44L51 707Q123 707 198 749Z" />
+<glyph unicode="&#xba;" glyph-name="ordmasculine" horiz-adv-x="329" d="M262 676V671Q269 675 295 703L301 692Q288 649 262 635Q258 557 218 512T132 466T64 487T42 555Q42 648 86 696T194 745Q216 745 232 738T249 721Q249 704 223 695Q215 714 193 714T152
+684Q119 631 119 560Q119 519 160 519Q183 519 199 552T220 627Q204 630 204 646T216 676T245 690T262 676Z" />
+<glyph unicode="&#xbb;" glyph-name="guillemotright" horiz-adv-x="586" d="M75 374L84 429L330 279L319 225L15 101L29 158L269 254L75 374ZM297 374L306 429L552 279L541 225L237 101L251 158L491 254L297 374Z" />
+<glyph unicode="&#xbc;" glyph-name="onequarter" horiz-adv-x="689" d="M475 750L211 -165H139L403 750H475ZM515 150H374Q381 170 404 213Q458 317 458 373Q458 391 454 406Q481 406 500 393T519 352T506 296T467 236T434 189H524L571 395L657 406L607 189H645L633
+150H598L564 1H481L515 150ZM246 629L154 225H70L147 562H92L99 587Q171 587 246 629Z" />
+<glyph unicode="&#xbd;" glyph-name="onehalf" horiz-adv-x="675" d="M470 750L206 -165H134L398 750H470ZM434 76L539 67Q566 67 584 74T626 104Q626 29 610 16Q577 -14 484 9Q443 19 426 19T400 16T381 9T368 3Q366 15 366 21Q366 80 434 142L490 196Q557 262
+557 336Q557 355 546 367T514 380Q475 380 475 337Q475 306 497 300Q475 281 455 281T423 294T411 334T440 385T531 409Q641 409 641 323Q641 257 582 204Q555 181 528 160L474 118Q447 95 434 76ZM246 629L154 225H70L147 562H92L99 587Q171 587 246 629Z" />
+<glyph unicode="&#xbe;" glyph-name="threequarters" horiz-adv-x="819" d="M591 750L327 -165H255L519 750H591ZM177 364Q126 360 126 300Q126 275 139 266T180 256T228 284T248 348T230 411T173 451Q220 462 246 494T272 552Q272 600 235 600Q183 600 183 557Q183
+526 205 520Q183 501 163 501T131 514T119 554T151 605T237 629T319 606T346 550Q346 487 267 450Q339 429 339 362Q339 310 296 266T190 222Q61 222 61 309Q61 348 79 369T133 391T177 364ZM634 150H493Q500 170 522 213Q577 317 577 373Q577 391 573 406Q600
+406 619 393T638 352T625 296T586 236T553 189H643L690 395L776 406L726 189H764L752 150H717L683 1H600L634 150Z" />
+<glyph unicode="&#xbf;" glyph-name="questiondown" horiz-adv-x="439" d="M12 -128Q12 -31 79 32Q109 60 140 85Q224 151 253 221H319Q319 149 255 82Q255 82 201 24Q137 -46 137 -124Q137 -159 152 -176T195 -193T247 -170T272 -118Q272 -54 234 -44Q260 -2
+307 -2Q338 -2 360 -24T383 -86Q383 -146 330 -196T173 -247Q12 -247 12 -128ZM277 293T254 316T231 372T254 429T310 453T366 430T390 373T367 316T310 293Z" />
+<glyph unicode="&#xc0;" glyph-name="Agrave" horiz-adv-x="668" d="M535 0H391L468 363Q394 395 333 399Q277 277 241 149T204 -57Q204 -91 208 -98Q208 -98 216 -108Q218 -111 218 -113Q189 -111 177 -110T142 -103T110 -85Q84 -54 84 4T124 174T231 399Q132
+392 114 347Q118 347 122 337T127 313T112 288T70 277T26 292T9 340Q9 386 68 420T204 455Q230 455 263 452Q345 584 437 667T612 751Q656 751 692 736L535 0ZM477 407L535 679Q449 632 353 441Q424 428 477 407ZM546 811L487 1000H592L621 811H546Z" />
+<glyph unicode="&#xc1;" glyph-name="Aacute" horiz-adv-x="668" d="M535 0H391L468 363Q394 395 333 399Q277 277 241 149T204 -57Q204 -91 208 -98Q208 -98 216 -108Q218 -111 218 -113Q189 -111 177 -110T142 -103T110 -85Q84 -54 84 4T124 174T231 399Q132
+392 114 347Q118 347 122 337T127 313T112 288T70 277T26 292T9 340Q9 386 68 420T204 455Q230 455 263 452Q345 584 437 667T612 751Q656 751 692 736L535 0ZM477 407L535 679Q449 632 353 441Q424 428 477 407ZM506 811L597 1000H702L581 811H506Z" />
+<glyph unicode="&#xc2;" glyph-name="Acircumflex" horiz-adv-x="668" d="M535 0H391L468 363Q394 395 333 399Q277 277 241 149T204 -57Q204 -91 208 -98Q208 -98 216 -108Q218 -111 218 -113Q189 -111 177 -110T142 -103T110 -85Q84 -54 84 4T124 174T231 399Q132
+392 114 347Q118 347 122 337T127 313T112 288T70 277T26 292T9 340Q9 386 68 420T204 455Q230 455 263 452Q345 584 437 667T612 751Q656 751 692 736L535 0ZM477 407L535 679Q449 632 353 441Q424 428 477 407ZM710 811H678L618 891L461 811H417L629 1000H650L710
+811Z" />
+<glyph unicode="&#xc3;" glyph-name="Atilde" horiz-adv-x="668" d="M535 0H391L468 363Q394 395 333 399Q277 277 241 149T204 -57Q204 -91 208 -98Q208 -98 216 -108Q218 -111 218 -113Q189 -111 177 -110T142 -103T110 -85Q84 -54 84 4T124 174T231 399Q132
+392 114 347Q118 347 122 337T127 313T112 288T70 277T26 292T9 340Q9 386 68 420T204 455Q230 455 263 452Q345 584 437 667T612 751Q656 751 692 736L535 0ZM775 920L781 919Q772 882 724 851T631 819T532 837T446 856T386 830L380 832Q429 930 547 930Q585 930
+635 914T719 897T775 920ZM477 407L535 679Q449 632 353 441Q424 428 477 407Z" />
+<glyph unicode="&#xc4;" glyph-name="Adieresis" horiz-adv-x="668" d="M535 0H391L468 363Q394 395 333 399Q277 277 241 149T204 -57Q204 -91 208 -98Q208 -98 216 -108Q218 -111 218 -113Q189 -111 177 -110T142 -103T110 -85Q84 -54 84 4T124 174T231 399Q132
+392 114 347Q118 347 122 337T127 313T112 288T70 277T26 292T9 340Q9 386 68 420T204 455Q230 455 263 452Q345 584 437 667T612 751Q656 751 692 736L535 0ZM477 407L535 679Q449 632 353 441Q424 428 477 407ZM646 823T628 840T610 883T628 927T671 945T714
+927T732 884T714 841T671 823ZM466 823T448 840T430 883T448 927T491 945T534 927T552 884T534 841T491 823Z" />
+<glyph unicode="&#xc5;" glyph-name="Aring" horiz-adv-x="668" d="M535 0H391L468 363Q394 395 333 399Q277 277 241 149T204 -57Q204 -91 208 -98Q208 -98 216 -108Q218 -111 218 -113Q189 -111 177 -110T142 -103T110 -85Q84 -54 84 4T124 174T231 399Q132
+392 114 347Q118 347 122 337T127 313T112 288T70 277T26 292T9 340Q9 386 68 420T204 455Q230 455 263 452Q345 584 437 667T612 751Q656 751 692 736L535 0ZM477 407L535 679Q449 632 353 441Q424 428 477 407ZM536 904T558 933T618 963T674 942T693 885T672
+826T613 802T556 822T536 873ZM610 837Q656 837 656 883T623 930Q599 930 588 913T576 874Q576 837 610 837Z" />
+<glyph unicode="&#xc6;" glyph-name="AE" horiz-adv-x="764" d="M760 0H391L468 363Q394 395 333 399Q277 277 241 149T204 -57Q204 -91 208 -98Q208 -98 216 -108Q218 -111 218 -113Q189 -111 177 -110T142 -103T110 -85Q84 -54 84 4T124 174T231 399Q132 392
+114 347Q118 347 122 337T127 313T112 288T70 277T26 292T9 340Q9 386 68 420T204 455Q230 455 263 452Q345 584 437 667T612 751Q638 751 696 741T802 731T909 750Q908 748 902 728T893 701T881 680T863 658Q836 640 801 640T744 648L716 656Q712 658 697 664T678
+672L624 419H779L759 345H608L557 106H781L760 0ZM477 407L535 679Q449 632 353 441Q424 428 477 407Z" />
+<glyph unicode="&#xc7;" glyph-name="Ccedilla" horiz-adv-x="497" d="M300 -58Q362 -58 362 -108T326 -188T239 -218T135 -190Q153 -158 175 -158T217 -171T249 -185T270 -172T279 -144T270 -118T237 -107T188 -119L228 -5Q145 -1 90 50Q24 109 24 249Q24 400
+66 519Q90 587 127 637T224 718T360 750T486 717T535 616Q535 524 465 524Q430 524 408 550Q425 555 438 583T452 628T449 658T429 687T383 703Q325 703 277 631T205 462T181 266T208 126T304 84Q445 84 500 180L523 170Q464 8 271 -5L247 -66Q279 -58 300 -58Z"
+/>
+<glyph unicode="&#xc8;" glyph-name="Egrave" horiz-adv-x="459" d="M461 180L484 170Q420 -6 218 -6Q120 -6 66 53T11 193T58 336T192 417Q93 471 93 569Q93 642 153 696T315 750Q393 750 446 717T499 616Q499 524 429 524Q394 524 372 550Q389 555 402 583T416
+632Q416 706 350 706Q296 706 262 670T228 585T260 492T360 418Q271 381 229 328T186 218T220 123T307 84T395 107T461 180ZM321 811L262 1000H367L396 811H321Z" />
+<glyph unicode="&#xc9;" glyph-name="Eacute" horiz-adv-x="459" d="M461 180L484 170Q420 -6 218 -6Q120 -6 66 53T11 193T58 336T192 417Q93 471 93 569Q93 642 153 696T315 750Q393 750 446 717T499 616Q499 524 429 524Q394 524 372 550Q389 555 402 583T416
+632Q416 706 350 706Q296 706 262 670T228 585T260 492T360 418Q271 381 229 328T186 218T220 123T307 84T395 107T461 180ZM291 811L382 1000H487L366 811H291Z" />
+<glyph unicode="&#xca;" glyph-name="Ecircumflex" horiz-adv-x="459" d="M461 180L484 170Q420 -6 218 -6Q120 -6 66 53T11 193T58 336T192 417Q93 471 93 569Q93 642 153 696T315 750Q393 750 446 717T499 616Q499 524 429 524Q394 524 372 550Q389 555 402
+583T416 632Q416 706 350 706Q296 706 262 670T228 585T260 492T360 418Q271 381 229 328T186 218T220 123T307 84T395 107T461 180ZM496 811H464L404 891L247 811H203L415 1000H436L496 811Z" />
+<glyph unicode="&#xcb;" glyph-name="Edieresis" horiz-adv-x="459" d="M461 180L484 170Q420 -6 218 -6Q120 -6 66 53T11 193T58 336T192 417Q93 471 93 569Q93 642 153 696T315 750Q393 750 446 717T499 616Q499 524 429 524Q394 524 372 550Q389 555 402 583T416
+632Q416 706 350 706Q296 706 262 670T228 585T260 492T360 418Q271 381 229 328T186 218T220 123T307 84T395 107T461 180ZM224 823T206 840T188 883T206 927T249 945T292 927T310 884T292 841T249 823ZM404 823T386 840T368 883T386 927T429 945T472 927T490
+884T472 841T429 823Z" />
+<glyph unicode="&#xcc;" glyph-name="Igrave" horiz-adv-x="375" d="M397 748L238 0H94L239 679Q173 651 136 596T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q371 750 397 748ZM289 811L230 1000H335L364 811H289Z" />
+<glyph unicode="&#xcd;" glyph-name="Iacute" horiz-adv-x="375" d="M397 748L238 0H94L239 679Q173 651 136 596T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q371 750 397 748ZM301 811L392 1000H497L376 811H301Z" />
+<glyph unicode="&#xce;" glyph-name="Icircumflex" horiz-adv-x="375" d="M397 748L238 0H94L239 679Q173 651 136 596T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q371 750 397 748ZM444 811H412L352 891L195 811H151L363 1000H384L444
+811Z" />
+<glyph unicode="&#xcf;" glyph-name="Idieresis" horiz-adv-x="375" d="M397 748L238 0H94L239 679Q173 651 136 596T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q371 750 397 748ZM382 823T365 840T347 883T365 927T408 945T451
+927T469 884T451 841T408 823ZM202 823T185 840T167 883T185 927T228 945T271 927T289 884T271 841T228 823Z" />
+<glyph unicode="&#xd0;" glyph-name="Eth" horiz-adv-x="663" d="M230 636L378 656L327 419H406L386 345H311L258 95Q285 75 315 75Q371 75 416 144T484 311T507 509T479 657T369 704Q246 704 173 639T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588
+118 669T357 750Q645 750 645 480Q645 353 607 239T505 56T374 -13T246 40L238 0H94L168 345H129L149 419H184L230 636Z" />
+<glyph unicode="&#xd1;" glyph-name="Ntilde" horiz-adv-x="702" d="M448 564L437 231Q437 156 447 122L580 748H724L565 0H421Q363 0 363 204L370 523Q370 584 368 612L238 0H94L239 680Q172 652 136 596T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6
+588 118 669T357 750Q417 750 432 714T448 564ZM685 920L691 919Q682 882 634 851T541 819T442 837T356 856T296 830L290 832Q339 930 457 930Q495 930 545 914T629 897T685 920Z" />
+<glyph unicode="&#xd2;" glyph-name="Ograve" horiz-adv-x="658" d="M388 656Q253 478 253 237Q253 167 273 121T333 75T417 142T487 308T515 500Q515 589 490 642Q460 704 369 704Q246 704 173 639T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588
+118 669T365 750T566 682T631 479Q631 405 609 321T549 162T454 40T332 -9Q232 -9 180 44T127 217Q127 371 178 510Q203 578 245 621T341 664Q361 664 388 656ZM401 811L342 1000H447L476 811H401Z" />
+<glyph unicode="&#xd3;" glyph-name="Oacute" horiz-adv-x="658" d="M388 656Q253 478 253 237Q253 167 273 121T333 75T417 142T487 308T515 500Q515 589 490 642Q460 704 369 704Q246 704 173 639T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588
+118 669T365 750T566 682T631 479Q631 405 609 321T549 162T454 40T332 -9Q232 -9 180 44T127 217Q127 371 178 510Q203 578 245 621T341 664Q361 664 388 656ZM431 811L522 1000H627L506 811H431Z" />
+<glyph unicode="&#xd4;" glyph-name="Ocircumflex" horiz-adv-x="658" d="M388 656Q253 478 253 237Q253 167 273 121T333 75T417 142T487 308T515 500Q515 589 490 642Q460 704 369 704Q246 704 173 639T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6
+588 118 669T365 750T566 682T631 479Q631 405 609 321T549 162T454 40T332 -9Q232 -9 180 44T127 217Q127 371 178 510Q203 578 245 621T341 664Q361 664 388 656ZM595 811H563L503 891L346 811H302L514 1000H535L595 811Z" />
+<glyph unicode="&#xd5;" glyph-name="Otilde" horiz-adv-x="658" d="M388 656Q253 478 253 237Q253 167 273 121T333 75T417 142T487 308T515 500Q515 589 490 642Q460 704 369 704Q246 704 173 639T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588
+118 669T365 750T566 682T631 479Q631 405 609 321T549 162T454 40T332 -9Q232 -9 180 44T127 217Q127 371 178 510Q203 578 245 621T341 664Q361 664 388 656ZM633 920L639 919Q630 882 582 851T489 819T390 837T304 856T244 830L238 832Q287 930 405 930Q443
+930 493 914T577 897T633 920Z" />
+<glyph unicode="&#xd6;" glyph-name="Odieresis" horiz-adv-x="658" d="M388 656Q253 478 253 237Q253 167 273 121T333 75T417 142T487 308T515 500Q515 589 490 642Q460 704 369 704Q246 704 173 639T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588
+118 669T365 750T566 682T631 479Q631 405 609 321T549 162T454 40T332 -9Q232 -9 180 44T127 217Q127 371 178 510Q203 578 245 621T341 664Q361 664 388 656ZM344 823T326 840T308 883T326 927T369 945T412 927T430 884T412 841T369 823ZM524 823T506 840T488
+883T506 927T549 945T592 927T610 884T592 841T549 823Z" />
+<glyph unicode="&#xd7;" glyph-name="multiply" horiz-adv-x="515" d="M98 355L163 419L257 324L353 420L417 355L322 260L417 165L353 100L257 195L163 101L98 165L193 260L98 355Z" />
+<glyph unicode="&#xd8;" glyph-name="Oslash" horiz-adv-x="658" d="M330 -9L279 -250H227L278 -7Q201 -2 164 34T127 155T140 315T178 458T246 569T341 612Q361 612 388 604Q253 426 253 185Q253 99 297 81L417 645Q393 652 369 652Q246 652 173 587T99 409Q99
+368 106 356T113 341Q59 341 33 363T6 438Q6 536 118 617T357 698Q394 698 427 692L439 750H491L476 680Q631 626 631 413Q631 306 595 211T488 53T330 -9ZM411 91T463 196T515 436T463 619L348 76Q411 91 463 196Z" />
+<glyph unicode="&#xd9;" glyph-name="Ugrave" horiz-adv-x="678" d="M557 748H700L541 0H397L408 52Q352 1 311 1Q220 1 173 49T126 214T168 475T285 695Q198 674 149 614T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q414 750 432
+745Q365 657 309 504T253 237Q253 167 273 121T332 75Q386 75 429 152L557 748ZM451 811L392 1000H497L526 811H451Z" />
+<glyph unicode="&#xda;" glyph-name="Uacute" horiz-adv-x="678" d="M557 748H700L541 0H397L408 52Q352 1 311 1Q220 1 173 49T126 214T168 475T285 695Q198 674 149 614T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q414 750 432
+745Q365 657 309 504T253 237Q253 167 273 121T332 75Q386 75 429 152L557 748ZM431 811L522 1000H627L506 811H431Z" />
+<glyph unicode="&#xdb;" glyph-name="Ucircumflex" horiz-adv-x="678" d="M557 748H700L541 0H397L408 52Q352 1 311 1Q220 1 173 49T126 214T168 475T285 695Q198 674 149 614T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q414
+750 432 745Q365 657 309 504T253 237Q253 167 273 121T332 75Q386 75 429 152L557 748ZM635 811H603L543 891L386 811H342L554 1000H575L635 811Z" />
+<glyph unicode="&#xdc;" glyph-name="Udieresis" horiz-adv-x="678" d="M557 748H700L541 0H397L408 52Q352 1 311 1Q220 1 173 49T126 214T168 475T285 695Q198 674 149 614T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q414 750
+432 745Q365 657 309 504T253 237Q253 167 273 121T332 75Q386 75 429 152L557 748ZM414 823T396 840T378 883T396 927T439 945T482 927T500 884T482 841T439 823ZM594 823T576 840T558 883T576 927T619 945T662 927T680 884T662 841T619 823Z" />
+<glyph unicode="&#xdd;" glyph-name="Yacute" horiz-adv-x="620" d="M438 0H278L344 308L248 683Q177 657 138 600T99 461Q99 420 106 408T113 393Q59 393 33 415T6 490Q6 588 118 669T357 750Q371 750 397 748L484 390L632 745H698L504 308L438 0ZM467 811L558
+1000H663L542 811H467Z" />
+<glyph unicode="&#xde;" glyph-name="Thorn" horiz-adv-x="583" d="M250 730L398 750L374 639Q481 634 536 579T592 443Q592 341 512 258T304 175H275L238 0H94L214 562Q99 501 99 351Q99 310 106 298T113 283Q59 283 33 305T6 380Q6 451 69 517T225 616L250 730ZM288
+212H297Q372 212 427 291T482 458Q482 516 453 554T364 594L281 204Q283 207 288 212Z" />
+<glyph unicode="&#xdf;" glyph-name="germandbls" horiz-adv-x="450" d="M225 530L66 -214L-85 -250L81 530Q117 700 263 700Q329 700 364 663T400 577T376 488T308 427Q405 394 405 285Q405 265 395 216T366 118T322 44T273 10T226 0T182 2L195 61Q218 66 232
+77Q268 104 294 232Q304 279 304 310Q304 375 232 393L250 451Q333 485 333 562Q333 590 324 601T295 612T254 594T225 530Z" />
+<glyph unicode="&#xe0;" glyph-name="agrave" horiz-adv-x="503" d="M317 500H461L389 160Q385 138 385 129Q385 91 435 91Q461 91 500 122Q514 133 536 152T567 179H601Q601 179 568 144Q469 41 412 13Q386 0 364 0Q261 0 242 76Q182 -6 111 -6T11 31T-18 122T-10
+226T17 328T65 416T140 476T244 499Q281 499 311 474L317 500ZM252 443Q198 443 158 349T117 148Q117 77 175 77Q205 77 239 127Q240 142 245 160L301 425Q280 443 252 443ZM243 561L184 750H289L318 561H243Z" />
+<glyph unicode="&#xe1;" glyph-name="aacute" horiz-adv-x="489" d="M317 500H461L389 160Q385 138 385 129Q385 91 435 91Q461 91 500 122Q514 133 536 152T567 179H601Q601 179 568 144Q469 41 412 13Q386 0 364 0Q261 0 242 76Q182 -6 111 -6T11 31T-18 122T-10
+226T17 328T65 416T140 476T244 499Q281 499 311 474L317 500ZM252 443Q198 443 158 349T117 148Q117 77 175 77Q205 77 239 127Q240 142 245 160L301 425Q280 443 252 443ZM247 561L338 750H443L322 561H247Z" />
+<glyph unicode="&#xe2;" glyph-name="acircumflex" horiz-adv-x="503" d="M317 500H461L389 160Q385 138 385 129Q385 91 435 91Q461 91 500 122Q514 133 536 152T567 179H601Q601 179 568 144Q469 41 412 13Q386 0 364 0Q261 0 242 76Q182 -6 111 -6T11 31T-18
+122T-10 226T17 328T65 416T140 476T244 499Q281 499 311 474L317 500ZM252 443Q198 443 158 349T117 148Q117 77 175 77Q205 77 239 127Q240 142 245 160L301 425Q280 443 252 443ZM442 561H410L350 641L193 561H149L361 750H382L442 561Z" />
+<glyph unicode="&#xe3;" glyph-name="atilde" horiz-adv-x="503" d="M317 500H461L389 160Q385 138 385 129Q385 91 435 91Q461 91 500 122Q514 133 536 152T567 179H601Q601 179 568 144Q469 41 412 13Q386 0 364 0Q261 0 242 76Q182 -6 111 -6T11 31T-18 122T-10
+226T17 328T65 416T140 476T244 499Q281 499 311 474L317 500ZM252 443Q198 443 158 349T117 148Q117 77 175 77Q205 77 239 127Q240 142 245 160L301 425Q280 443 252 443ZM480 670L486 669Q477 632 429 601T336 569T237 587T151 606T91 580L85 582Q134 680 252
+680Q290 680 340 664T424 647T480 670Z" />
+<glyph unicode="&#xe4;" glyph-name="adieresis" horiz-adv-x="503" d="M317 500H461L389 160Q385 138 385 129Q385 91 435 91Q461 91 500 122Q514 133 536 152T567 179H601Q601 179 568 144Q469 41 412 13Q386 0 364 0Q261 0 242 76Q182 -6 111 -6T11 31T-18
+122T-10 226T17 328T65 416T140 476T244 499Q281 499 311 474L317 500ZM252 443Q198 443 158 349T117 148Q117 77 175 77Q205 77 239 127Q240 142 245 160L301 425Q280 443 252 443ZM182 573T164 590T146 633T164 677T207 695T250 677T268 634T250 591T207 573ZM362
+573T344 590T326 633T344 677T387 695T430 677T448 634T430 591T387 573Z" />
+<glyph unicode="&#xe5;" glyph-name="aring" horiz-adv-x="503" d="M317 500H461L389 160Q385 138 385 129Q385 91 435 91Q461 91 500 122Q514 133 536 152T567 179H601Q601 179 568 144Q469 41 412 13Q386 0 364 0Q261 0 242 76Q182 -6 111 -6T11 31T-18 122T-10
+226T17 328T65 416T140 476T244 499Q281 499 311 474L317 500ZM252 443Q198 443 158 349T117 148Q117 77 175 77Q205 77 239 127Q240 142 245 160L301 425Q280 443 252 443ZM239 659T261 688T321 718T377 697T396 640T375 581T316 557T259 577T239 628ZM313 592Q359
+592 359 638T326 685Q302 685 291 668T279 629Q279 592 313 592Z" />
+<glyph unicode="&#xe6;" glyph-name="ae" horiz-adv-x="625" d="M106 -6Q40 -6 11 31T-18 122T-10 226T17 328T65 416T140 476T244 499Q276 499 305 479T335 433Q396 509 488 509Q616 509 616 405Q616 321 545 267T390 201Q387 177 387 158Q387 113 411 93T471
+72T560 111T637 204H682Q633 116 561 58T400 0Q346 0 310 28T260 102Q193 -6 106 -6ZM252 443Q198 443 158 349T117 148Q117 77 175 77Q207 77 252 147V159Q252 305 316 407Q295 443 252 443ZM556 400Q556 456 521 456Q495 456 470 423Q422 362 398 249Q464 250
+509 297T556 400Z" />
+<glyph unicode="&#xe7;" glyph-name="ccedilla" horiz-adv-x="360" d="M93 -119L136 0Q58 0 23 44T-13 164Q-13 263 22 346Q62 443 143 482Q188 503 244 503Q354 503 354 434Q354 417 349 401Q339 407 326 407T292 401Q297 419 297 429Q297 463 260 463Q202 463
+162 373T122 192Q122 141 137 113T195 85Q286 85 369 179H403Q354 103 294 54T179 0L152 -66Q184 -58 205 -58Q267 -58 267 -108T231 -188T144 -218T40 -190Q58 -158 80 -158T122 -171T154 -185T175 -172T184 -143Q184 -107 145 -107Q119 -107 93 -119Z" />
+<glyph unicode="&#xe8;" glyph-name="egrave" horiz-adv-x="355" d="M117 158Q117 113 141 93T201 72T290 111T367 204H412Q363 116 291 58T130 0Q61 0 22 45T-18 151T-6 268T31 380T105 473T218 509Q346 509 346 405Q346 321 275 267T120 201Q117 177 117 158ZM286
+400Q286 456 251 456Q225 456 200 423Q152 362 128 249Q194 250 239 297T286 400ZM169 561L110 750H215L244 561H169Z" />
+<glyph unicode="&#xe9;" glyph-name="eacute" horiz-adv-x="362" d="M117 158Q117 113 141 93T201 72T290 111T367 204H412Q363 116 291 58T130 0Q61 0 22 45T-18 151T-6 268T31 380T105 473T218 509Q346 509 346 405Q346 321 275 267T120 201Q117 177 117 158ZM286
+400Q286 456 251 456Q225 456 200 423Q152 362 128 249Q194 250 239 297T286 400ZM204 561L295 750H400L279 561H204Z" />
+<glyph unicode="&#xea;" glyph-name="ecircumflex" horiz-adv-x="355" d="M117 158Q117 113 141 93T201 72T290 111T367 204H412Q363 116 291 58T130 0Q61 0 22 45T-18 151T-6 268T31 380T105 473T218 509Q346 509 346 405Q346 321 275 267T120 201Q117 177 117
+158ZM374 561H342L282 641L125 561H81L293 750H314L374 561ZM286 400Q286 456 251 456Q225 456 200 423Q152 362 128 249Q194 250 239 297T286 400Z" />
+<glyph unicode="&#xeb;" glyph-name="edieresis" horiz-adv-x="355" d="M117 158Q117 113 141 93T201 72T290 111T367 204H412Q363 116 291 58T130 0Q61 0 22 45T-18 151T-6 268T31 380T105 473T218 509Q346 509 346 405Q346 321 275 267T120 201Q117 177 117
+158ZM286 400Q286 456 251 456Q225 456 200 423Q152 362 128 249Q194 250 239 297T286 400ZM108 573T90 590T72 633T90 677T133 695T176 677T194 634T176 591T133 573ZM288 573T270 590T252 633T270 677T313 695T356 677T374 634T356 591T313 573Z" />
+<glyph unicode="&#xec;" glyph-name="igrave" horiz-adv-x="269" d="M71 500H216L144 160Q139 142 139 128Q139 91 189 91Q215 91 254 122Q268 133 290 152T321 179H355Q355 179 322 144Q223 41 166 13Q140 0 118 0Q-6 0 -6 109Q-6 132 0 160L71 500ZM126 561L67
+750H172L201 561H126Z" />
+<glyph unicode="&#xed;" glyph-name="iacute" horiz-adv-x="255" d="M71 500H216L144 160Q139 142 139 128Q139 91 189 91Q215 91 254 122Q268 133 290 152T321 179H355Q355 179 322 144Q223 41 166 13Q140 0 118 0Q-6 0 -6 109Q-6 132 0 160L71 500ZM115 561L206
+750H311L190 561H115Z" />
+<glyph unicode="&#xee;" glyph-name="icircumflex" horiz-adv-x="269" d="M71 500H216L144 160Q139 142 139 128Q139 91 189 91Q215 91 254 122Q268 133 290 152T321 179H355Q355 179 322 144Q223 41 166 13Q140 0 118 0Q-6 0 -6 109Q-6 132 0 160L71 500ZM286
+561H254L194 641L37 561H-7L205 750H226L286 561Z" />
+<glyph unicode="&#xef;" glyph-name="idieresis" horiz-adv-x="269" d="M71 500H216L144 160Q139 142 139 128Q139 91 189 91Q215 91 254 122Q268 133 290 152T321 179H355Q355 179 322 144Q223 41 166 13Q140 0 118 0Q-6 0 -6 109Q-6 132 0 160L71 500ZM56 573T38
+590T20 633T38 677T81 695T124 677T142 634T124 591T81 573ZM236 573T218 590T200 633T218 677T261 695T304 677T322 634T304 591T261 573Z" />
+<glyph unicode="&#xf0;" glyph-name="eth" horiz-adv-x="510" d="M283 700H328Q409 655 435 601H509L501 561H448Q453 534 453 499T443 415L389 160Q384 133 384 128Q384 91 434 91Q460 91 499 122Q513 133 535 152T566 179H600L566 144Q468 41 412 13Q385 0 363
+0Q261 0 242 76Q182 -6 111 -6T11 31T-18 122T-10 226T17 328T65 416T140 476T244 499Q280 499 311 473L314 485Q324 530 325 561H259L267 601H325Q319 652 283 700ZM252 443Q198 443 158 349T117 148Q117 77 175 77Q205 77 239 127Q240 142 245 160L301 425Q280
+443 252 443Z" />
+<glyph unicode="&#xf1;" glyph-name="ntilde" horiz-adv-x="503" d="M446 351L405 160Q400 142 400 128Q400 91 450 91Q468 91 481 98T514 125T545 154H579Q571 146 541 112T490 58T438 19T379 0Q255 0 255 109Q255 132 261 160L299 340Q302 354 302 373T289 409T250
+425T193 404L108 0H-36L70 500H214L202 446Q276 500 333 500Q375 500 411 462T448 375Q448 359 446 351ZM480 670L486 669Q477 632 429 601T336 569T237 587T151 606T91 580L85 582Q134 680 252 680Q290 680 340 664T424 647T480 670Z" />
+<glyph unicode="&#xf2;" glyph-name="ograve" horiz-adv-x="418" d="M256 510Q373 510 377 363Q386 354 410 354T468 377T511 403L515 382Q465 319 374 294Q361 152 294 73T146 -6T29 32T-7 158Q-7 332 68 421T256 510ZM192 91Q222 91 245 120Q287 173 300 284Q279
+284 269 297T258 330T270 371T302 399Q297 451 260 451Q227 451 200 419T158 338Q126 242 126 167T192 91ZM201 561L142 750H247L276 561H201Z" />
+<glyph unicode="&#xf3;" glyph-name="oacute" horiz-adv-x="433" d="M261 510Q378 510 382 363Q391 354 415 354T473 377T516 403L520 382Q470 319 379 294Q366 152 299 73T151 -6T34 32T-2 158Q-2 332 73 421T261 510ZM196 91Q227 91 250 120Q292 173 305 284Q284
+284 274 297T263 330T275 371T307 399Q302 451 265 451Q232 451 205 419T162 338Q131 242 131 167T196 91ZM216 561L307 750H412L291 561H216Z" />
+<glyph unicode="&#xf4;" glyph-name="ocircumflex" horiz-adv-x="418" d="M256 510Q373 510 377 363Q386 354 410 354T468 377T511 403L515 382Q465 319 374 294Q361 152 294 73T146 -6T29 32T-7 158Q-7 332 68 421T256 510ZM192 91Q222 91 245 120Q287 173 300
+284Q279 284 269 297T258 330T270 371T302 399Q297 451 260 451Q227 451 200 419T158 338Q126 242 126 167T192 91ZM395 561H363L303 641L146 561H102L314 750H335L395 561Z" />
+<glyph unicode="&#xf5;" glyph-name="otilde" horiz-adv-x="418" d="M256 510Q373 510 377 363Q386 354 410 354T468 377T511 403L515 382Q465 319 374 294Q361 152 294 73T146 -6T29 32T-7 158Q-7 332 68 421T256 510ZM192 91Q222 91 245 120Q287 173 300 284Q279
+284 269 297T258 330T270 371T302 399Q297 451 260 451Q227 451 200 419T158 338Q126 242 126 167T192 91ZM451 670L457 669Q448 632 400 601T307 569T208 587T122 606T62 580L56 582Q105 680 223 680Q261 680 311 664T395 647T451 670Z" />
+<glyph unicode="&#xf6;" glyph-name="odieresis" horiz-adv-x="418" d="M256 510Q373 510 377 363Q386 354 410 354T468 377T511 403L515 382Q465 319 374 294Q361 152 294 73T146 -6T29 32T-7 158Q-7 332 68 421T256 510ZM192 91Q222 91 245 120Q287 173 300
+284Q279 284 269 297T258 330T270 371T302 399Q297 451 260 451Q227 451 200 419T158 338Q126 242 126 167T192 91ZM140 573T122 590T104 633T122 677T165 695T208 677T226 634T208 591T165 573ZM320 573T302 590T284 633T302 677T345 695T388 677T406 634T388
+591T345 573Z" />
+<glyph unicode="&#xf7;" glyph-name="divide" horiz-adv-x="472" d="M147 47T147 80T170 136T226 160T282 137T306 80T283 24T226 1T170 24ZM207 382T207 415T230 471T286 495T342 472T366 415T343 359T286 336T230 359ZM419 285L402 206H51L69 285H419Z" />
+<glyph unicode="&#xf8;" glyph-name="oslash" horiz-adv-x="418" d="M181 -2L129 -250H77L129 -5Q57 -1 25 36T-7 158Q-7 325 62 413T238 509L289 750H341L289 506Q375 487 377 363Q386 354 410 354T468 377T511 403L515 382Q465 319 374 294Q362 168 308 91T181
+-2ZM177 410T152 322T126 175T151 101L223 439Q177 410 152 322ZM279 284T269 297T258 330T270 371T302 399Q299 438 277 448L201 92Q240 98 265 152T300 284Q279 284 269 297Z" />
+<glyph unicode="&#xf9;" glyph-name="ugrave" horiz-adv-x="520" d="M331 500H475L403 160Q399 138 399 129Q399 91 449 91Q475 91 514 122Q528 133 550 152T581 179H615Q615 179 582 144Q483 41 426 13Q400 0 378 0Q268 0 255 84Q165 0 111 0Q-14 0 -14 109Q-14
+132 -8 160L64 500H208L136 160Q132 138 132 129Q132 91 182 91Q208 91 253 127Q254 142 259 160L331 500ZM252 561L193 750H298L327 561H252Z" />
+<glyph unicode="&#xfa;" glyph-name="uacute" horiz-adv-x="510" d="M331 500H475L403 160Q399 138 399 129Q399 91 449 91Q475 91 514 122Q528 133 550 152T581 179H615Q615 179 582 144Q483 41 426 13Q400 0 378 0Q268 0 255 84Q165 0 111 0Q-14 0 -14 109Q-14
+132 -8 160L64 500H208L136 160Q132 138 132 129Q132 91 182 91Q208 91 253 127Q254 142 259 160L331 500ZM239 561L330 750H435L314 561H239Z" />
+<glyph unicode="&#xfb;" glyph-name="ucircumflex" horiz-adv-x="520" d="M331 500H475L403 160Q399 138 399 129Q399 91 449 91Q475 91 514 122Q528 133 550 152T581 179H615Q615 179 582 144Q483 41 426 13Q400 0 378 0Q268 0 255 84Q165 0 111 0Q-14 0 -14
+109Q-14 132 -8 160L64 500H208L136 160Q132 138 132 129Q132 91 182 91Q208 91 253 127Q254 142 259 160L331 500ZM425 561H393L333 641L176 561H132L344 750H365L425 561Z" />
+<glyph unicode="&#xfc;" glyph-name="udieresis" horiz-adv-x="520" d="M331 500H475L403 160Q399 138 399 129Q399 91 449 91Q475 91 514 122Q528 133 550 152T581 179H615Q615 179 582 144Q483 41 426 13Q400 0 378 0Q268 0 255 84Q165 0 111 0Q-14 0 -14 109Q-14
+132 -8 160L64 500H208L136 160Q132 138 132 129Q132 91 182 91Q208 91 253 127Q254 142 259 160L331 500ZM350 573T332 590T314 633T332 677T375 695T418 677T436 634T418 591T375 573ZM170 573T152 590T134 633T152 677T195 695T238 677T256 634T238 591T195
+573Z" />
+<glyph unicode="&#xfd;" glyph-name="yacute" horiz-adv-x="510" d="M336 500H480L387 62Q496 115 540 210L536 131Q527 88 486 62T377 16L357 -80Q321 -250 177 -250Q129 -250 94 -220T59 -149T71 -85T110 -42Q153 -14 231 8L245 76Q162 0 111 0Q-14 0 -14 109Q-14
+132 -8 160L64 500H208L136 160Q132 138 132 129Q132 91 182 91Q211 91 257 130L336 500ZM236 561L327 750H432L311 561H236ZM114 -128Q114 -139 126 -150T154 -161T187 -143T212 -83L224 -25Q171 -43 143 -66T114 -128Z" />
+<glyph unicode="&#xfe;" glyph-name="thorn" horiz-adv-x="455" d="M-96 -250L60 485Q72 539 72 578Q72 643 29 700H74Q124 673 154 642T195 557Q236 579 273 579Q353 579 389 547T426 439Q426 408 420 369Q378 81 201 81Q160 81 122 102L55 -214L-96 -250ZM135
+164Q154 155 188 155T245 197T286 330T305 460T291 515T251 530T200 514Q200 467 189 415L135 164Z" />
+<glyph unicode="&#xff;" glyph-name="ydieresis" horiz-adv-x="510" d="M336 500H480L387 62Q496 115 540 210L536 131Q527 88 486 62T377 16L357 -80Q321 -250 177 -250Q129 -250 94 -220T59 -149T71 -85T110 -42Q153 -14 231 8L245 76Q162 0 111 0Q-14 0 -14
+109Q-14 132 -8 160L64 500H208L136 160Q132 138 132 129Q132 91 182 91Q211 91 257 130L336 500ZM168 573T151 590T133 633T151 677T194 695T237 677T255 634T237 591T194 573ZM348 573T331 590T313 633T331 677T374 695T417 677T435 634T417 591T374 573ZM114
+-128Q114 -139 126 -150T154 -161T187 -143T212 -83L224 -25Q171 -43 143 -66T114 -128Z" />
+<glyph unicode="&#x2013;" glyph-name="endash" horiz-adv-x="352" d="M297 301L280 222H19L37 301H297Z" />
+<glyph unicode="&#x2014;" glyph-name="emdash" horiz-adv-x="444" d="M387 301L370 222H19L37 301H387Z" />
+<glyph unicode="&#x2018;" glyph-name="quoteleft" horiz-adv-x="305" d="M179 748T200 728T221 674T177 615Q165 608 165 598L214 528Q214 519 205 514Q149 550 117 596T84 676T101 729T148 748Z" />
+<glyph unicode="&#x2019;" glyph-name="quoteright" horiz-adv-x="305" d="M128 615Q84 641 84 674T105 727T156 748T204 730T221 677T189 596T100 514Q91 519 91 528L140 598Q140 608 128 615Z" />
+<glyph unicode="&#x201a;" glyph-name="quotesinglbase" horiz-adv-x="283" d="M120 13Q76 39 76 72T97 125T148 146T196 128T213 75T181 -6T92 -88Q83 -83 83 -74L132 -4Q132 6 120 13Z" />
+<glyph unicode="&#x201c;" glyph-name="quotedblleft" horiz-adv-x="509" d="M391 748T412 728T433 674T389 615Q377 608 377 598L426 528Q426 519 417 514Q361 550 329 596T296 676T313 729T360 748ZM171 748T192 728T213 674T169 615Q157 608 157 598L206 528Q206
+519 197 514Q141 550 109 596T76 676T93 729T140 748Z" />
+<glyph unicode="&#x201d;" glyph-name="quotedblright" horiz-adv-x="509" d="M120 615Q76 641 76 674T97 727T148 748T196 730T213 677T181 596T92 514Q83 519 83 528L132 598Q132 608 120 615ZM340 615Q296 641 296 674T317 727T368 748T416 730T433 677T401
+596T312 514Q303 519 303 528L352 598Q352 608 340 615Z" />
+<glyph unicode="&#x201e;" glyph-name="quotedblbase" horiz-adv-x="509" d="M120 13Q76 39 76 72T97 125T148 146T196 128T213 75T181 -6T92 -88Q83 -83 83 -74L132 -4Q132 6 120 13ZM340 13Q296 39 296 72T317 125T368 146T416 128T433 75T401 -6T312 -88Q303
+-83 303 -74L352 -4Q352 6 340 13Z" />
+<glyph unicode="&#x2022;" glyph-name="bullet" horiz-adv-x="434" d="M120 227T120 267T148 335T216 364T284 336T313 267T285 199T216 171T148 199Z" />
+<glyph unicode="&#x2039;" glyph-name="guilsinglleft" horiz-adv-x="359" d="M336 449L326 394L85 254L279 138L267 81L20 238L29 279L336 449Z" />
+<glyph unicode="&#x203a;" glyph-name="guilsinglright" horiz-adv-x="344" d="M75 394L84 449L330 279L319 225L15 81L29 138L269 254L75 394Z" />
+</font>
+</defs>
+</svg>
BIN  assets/screenshot-desktop.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  assets/screenshot-iphone.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
70 assets/style.css
@@ -0,0 +1,70 @@
+@charset "UTF-8"; /* Zeichenkodierung */
+
+* { margin: 0; padding: 0; } /* Standardmäßig ist der Außen- und Innenabstand der Elemente 0 */
+
+@font-face { /* Einbinden der Schriftart Lobster von Pablo Impallari zum Herunterladen auf http://impallari.com/lobster unter der SIL Open Font License, Version 1.1 */
+ font-family: 'Lobster'; /* Name der Schriftart */
+ font-style: normal; /* nicht kursiv, normal */
+ font-weight: normal; /* normale Schriftdicke */
+ src: local('Lobster'), url('lobster.otf') format('opentype'), url('lobster.svg#Lobster') format('svg'); /* Versucht zuerst, die Schriftart auf dem Computer zu finden, ansonsten wird sie heruntergeladen */
+}
+
+
+body { /* Das sichtbare Dokument */
+ background: center repeat url(wood.jpg); /* Textur (zu finden auf http://textures.z7server.com/nTextures.php?id=10): Bild "wood.jpg", zu finden im selben Verzeichnis wie diese Datei, zentriert, wiederholend in x- und y-Richtung */
+ font-family: Helvetica, Arial, sans-serif; /* Schriftart: Nimm die Helvetica, wenn sie auf dem Rechner installiert ist, andernfalls die Arial, und wenn die auch nicht installiert ist nimm irgendeine serifenlose Schrift */
+}
+
+/* GitHub */
+#github { /* Element mit der id "github" */
+ display: block; /* Block-Element, kommt nicht innerhalb einer Zeile vor (Inline-Element). Links sind standardmäßig Inline-Elemente */
+ position: absolute; /* Element wird absolut positioniert, das heißt außerhalb des normalen Flusses von oben nach unten */
+ right: 0; top: 0; /* Element ist in der rechten, oberen Ecke (wörtlich: Abstand vom rechten und oberen Rand ist 0) */
+}
+#github img { /* Das Bild mit der Ecke */
+ border: 0; /* Standardmäßig haben Bilder innerhalb von Links einen blauen Rahmen */
+}
+
+
+#wrapper { /* "Element, das andere umschließt" */
+ margin: 0 auto; /* horizontal zentriert (wörtlich: Außenabstand oben und unten ist 0, links und rechts ist "auto") */
+ width: 351px; /* Breite von 351 Pixeln */
+}
+
+h1, #game, #controls { margin: 15px 0; } /* Die Überschrift, das Spielfeld und die Knöpfe halten einen Abstand von 15 Pixeln nach oben und unten zum nächstfolgenden Element oder Fensterrand ein. */
+h1 { /* Die Überschrift */
+ color: #fff; /* Schriftfarbe: #fff ist die Kurznotation von #ffffff, was für den RGB-Wert 255, 255, 255 (weiß) steht (jeweils zwei Buchstaben oder Ziffern bilden eine Nummber von 0-255 im Hex-Format) */
+ font: 50px Lobster, Palatino, Georgia, "Times New Roman", serif; /* 50 Pixel große Schrift der Schriftart "Lobster" mit Ersatzschriftarten */
+}
+#game, button { /* Das Spielfeld und die Knöpfe … */
+ box-shadow: 2px 2px 18px #200b00; /* … besitzen einen Schlagschatten in der Farbe #200b00, der 2px horizontal und vertikal versetzt ist und einen Unschärfebereich der Breite 18 Pixel hat */
+ -webkit-box-shadow: 2px 2px 18px #200b00; /* Für Webkit-Browser (Apple Safari, Google Chrome) */
+ -moz-box-shadow: 2px 2px 18px #200b00; /* Für den Firefox */
+}
+#controls { /* Das Element, das die Buttons beinhaltet */
+ text-align: center; /* Text im Element ist zentriert */
+}
+button { /* Jeder Knopf */
+ display: inline-block; /* Buttons werden im Textfluss angezeigt */
+ padding: 8px; /* Innenabstand: zu allen Seiten 8 Pixel */
+ margin: 0 5px; /* Außenabstand: nach links und rechts 5 Pixel */
+ border: 1px solid #333; /* Eine 1 Pixel breite Umrandung in der Farbe #333 (dunkelgrau) */
+ border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px; /* Abgerundete Ecken mit Rundungsradius 5 Pixel, Versiion für Webkit und den Firefox */
+ background: #555; color: #fff; /* dunkelgrauer Hintergrund, Text ist weiß */
+ font-size: 14px; /* Schriftgröße: 14 Pixel */
+}
+button:active { /* Jeder Knopf, wenn auf ihn gerade geklickt wird … */
+ background: #333; /* hat eine dunkele Hintergrundfarbe */
+}
+
+@media only screen and (max-device-width: 480px) { /* Weiche für das iPhone */
+ #github { /* "Element, das andere umschließt */
+ display: none !important; /* nicht anzeigen */
+ }
+ #wrapper { /* "Element, das andere umschließt */
+ width: 301px; /* Breite von nur 301 Pixeln */
+ }
+ #game, .meisterhirn {
+ -webkit-user-select: none; /* kann nicht markiert werden */
+ }
+}
BIN  assets/wood.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 index.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html><!-- HTML5 -->
+<html manifest=assets/cache.manifest><!-- Manifest für Offlinebetrieb einbinden -->
+
+<head><!-- head-Bereich: Enthält Meta-Informationen -->
+<meta charset=utf-8><!-- Zeichensatz dieser Datei -->
+<title>Meisterhirn</title><!-- Titel des Dokuments -->
+<meta name=author content="Tim Baumann"><!-- unsichtbare Information: Autor -->
+<link rel=stylesheet href=assets/style.css><!-- CSS-Stylesheet einbinden -->
+<link rel="shortcut icon" href=assets/favicon.png><!-- Favicon (kleines Bildchen) -->
+
+<!-- Besonderheiten für iPhone und iPod touch: -->
+<link rel=apple-touch-icon href=assets/apple-touch-icon.png>
+<meta name=viewport content="width=device-width, user-scalable=no"><!-- kein Auszoomen, der Benutzer kann nicht mehr zoomen -->
+<meta name=apple-mobile-web-app-capable content=yes><!-- Fullscreen -->
+<link rel=apple-touch-startup-image href=assets/apple-touch-startup.png>
+
+<body><!-- der sichtbare Inhalt -->
+<!-- Diese GitHub-Ecke rechts oben: -->
+<a id=github href=http://github.com/timjb/meisterhirn/><!-- Link Anfang -->
+ <img src=http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png alt="Fork me on GitHub"><!-- Bild -->
+</a><!-- Link Ende -->
+<div id=wrapper><!-- Element, das andere umschließt => ist gut zum Styling mittels CSS -->
+ <h1>Meisterhirn</h1><!-- Überschrift -->
+ <div id=game></div><!-- in das Element links wird später das Spiel eingefügt -->
+ <div id=controls></div><!-- in das Element links werden später die Knöpfe zum automatischen Lösen eingefügt -->
+</div><!-- Ende "Element, das andere umschließt" -->
+
+<!-- JavaScript -->
+<script src=lib/meisterhirn.js></script>
+<script src=assets/app.js></script>
181 lib/autosolver.js
@@ -0,0 +1,181 @@
+addEventListener('message', function(evt) { // wenn eine Nachricht eintrifft
+ var obj = JSON.parse(evt.data), // Nachricht-Objekt aus dem String bauen
+ command = obj.command, // das Kommando, das aufgerufen werden soll (String)
+ args = obj.arguments || []; // Die Parameter, mit denen es aufgerufen werden soll
+ if(commands[command]) { // nur wenn es das Kommando gibt …
+ commands[command].apply(commands, args); // wird es mit den den angegebenen Parametern aufgerufen
+ }
+}, false);
+
+// globale Einstellungen
+var cols, colors, combinations, scores, possibilities, first;
+
+var commands = {
+ init: function(cols1, colors1) { // die Einstellungen des Spiels werden mitgeteilt
+ cols = cols1; // Wie viele Spalten es gibt.
+ colors = colors1; // Wie viele Farben es gibt.
+
+ // => alle möglichen Kombinationen …
+ combinations = []; // … werden in einem Array gesammelt
+ var count = Math.pow(colors, cols); // Anzahl der Möglichkeiten = Anzahl der Farben hoch Anzahl der Spalten
+ for(var i = 0; i < count; i += 1) { // für jedes i von 0 bis exklusiv die Anzahl der Möglichkeiten
+ var combination = [], x = i; // eine Kombination
+ for(var j = 0; j < cols; j += 1) { // für jede Stelle:
+ var y = x % colors; // Module gibt den Rest einer Division zurück
+ x = Math.floor(x / colors); // Die Division, abgerundet (wie oft geht color in x) => neues x für die neue Stelle
+ combination[j] = y; // Stelle zur Kombination hinzufügen
+ }
+ combinations[i] = combination; // Kombination zum Array der Kombinationen hinzufügen
+ }
+
+ // Alle möglichen und unmöglichen Bewertungen einer Zeile
+ scores = [];
+ var i = cols + 1;
+ while(i) { // i: Anzahlen der schwarzen Stifte
+ i--;
+ var j = cols + 1 - i;
+ while(j) { // j: Anzahlen der weißen Stifte
+ j--;
+ scores.push([i, j]);
+ }
+ }
+ },
+ reset: function() {
+ first = true; // Das Spiel beginnt neu
+ possibilities = combinations.slice(); // Alle Möglichkeiten in Betracht ziehen
+ },
+ propose: function() {
+ // Algorithmus von Don Knuth
+ // http://en.wikipedia.org/wiki/Mastermind_%28board_game%29#Five-guess_algorithm
+ //
+ // Kurz erklärt:
+ // 1. Der erste Tipp ist zur Hälfte die erste und zur anderen Hälfte die zweite Farbe
+
+ if(first) {
+ var combination = [];
+ for(var i = 0, l = cols; i < l; i += 1) {
+ combination[i] = (i < l/2) ? 0 : 1; // Wenn Spalte kleiner als die Hälfte der Spaltenanzahl, dann Farbe 1, ansonsten Farbe 2
+ }
+ send('propose', combination); // vorschlagen
+ return; // Funktion verlassen
+ }
+
+ // 2. Wenn nur noch zwei oder gar nur noch eine Möglichkeit übrig sind, nimm einfach eine davon.
+
+ if(possibilities.length <= 2) {
+ send('propose', possibilities[0]);
+ return;
+ }
+
+ // 3. Wenn noch mehrere Kombinationen die Lösung sein können, dann gehe jede Kombination (auch die für die Lösung ausgeschlossen durch) und suche diejenige aus, bei der selbst bei ungünstigem Schwarz/Weiß-Ergebnis noch die meisten Kombinationen für das Ergebnis ausgeschlossen werden können
+
+ var maxScore = -1, // wieviele Kombinationen bei dem bisher besten Tipp mindestens ausgeschlossen werden können
+ maxCombination; // der bisher beste Tipp
+
+ // hiervon werden nachher Kopien erstellt. Siehe unten.
+ var scoresTpl = [];
+ var i = (cols + 1) * cols;
+ while(i) {
+ i--;
+ scoresTpl.push(0);
+ }
+
+ // Jede Kombination durchgehen:
+ var i = combinations.length;
+ while(i) {
+ i--;
+ var combination = combinations[i];
+
+ var possibleScores = scoresTpl.slice(); // Kopie von scoresTpl. Hier wird gespeichert, bei welchem Schwarz/Weiß-Ergebnis wie viele Kombinationen nicht ausgeschlossen werden können
+
+ // Jedes noch mögliche Ergebnis durchgehen:
+ var j = possibilities.length;
+ while(j) {
+ j--;
+ var judgement = judge(combination, possibilities[j]); // das Ergebnis, bei dem die Kombination nicht ausgeschlossen werden könnte
+ possibleScores[(cols + 1) * judgement[0] + judgement[1]]++; // kann nicht ausgeschlossen werden, also dazugehörigen Zähler hochzählen
+ }
+
+ var score = possibilities.length - Math.max.apply(Math, possibleScores); // wie viele mögliche Ergebnisse selbst bei ungünstigem Schwarz/Weiß-Ergebnis noch verbleiben: Anzahl der verbleibenden Möglichkeiten minus dem Maximum an nicht ausgeschlossenen Kombinationen
+ if(score > maxScore) { // gibt es eine neue beste Kombination?
+ maxScore = score; // neue beste Anzahl an minimalen Ausschlüssen
+ //log('new maxScore: ' + maxScore);
+ maxCombination = combination; // neuen besten Tipp setzen
+ }
+
+ }
+ send('propose', maxCombination); // Kombination vorschlagen
+ },
+ guess: function() {
+ this.propose(); // Vorschlag machen
+ send('guess'); // mitteilen, dass der Vorschlag gleich geprüft werden soll
+ },
+ row: function(row, result) { // das Ergebnis wird mitgeteilt
+ first = false; // Wir befinden uns nicht mehr in der ersten Zeile
+
+ // Über alle offenen Möglichen iterieren und Möglichkeiten ausschließen
+ var i = possibilities.length;
+ while(i) {
+ i--;
+ var judgement = judge(row, possibilities[i]); // Die Reihe auf Basis des möglichen Ergebnisses bewerten
+ if(judgement[0] != result[0] || judgement[1] != result[1]) { // kommt nicht dasselbe Ergebnis wie mitgeteilt raus
+ possibilities.splice(i, 1); // => Möglichkeit ausgeschlossen
+ }
+ }
+ }
+};
+
+function send(command) { // sendet ein Kommande an das JavaScript auf der Seite
+ postMessage(JSON.stringify({
+ command: command, // die Funktion, die aufgerufen werden soll
+ arguments: Array.prototype.slice.call(arguments, 1) // alle Argumente dieser Funktion ab dem zweiten
+ }));
+}
+
+function log() { // zum Debugging
+ var args = Array.prototype.slice.apply(arguments); // Die Argumente, mit der diese Funktion aufgerufen wurde
+ args.unshift('log'); // Vorne den String "log" hinzufügen
+ send.apply(null, args); // Funktion send mit den Argumenten aufrufen
+}
+
+// Für eine Erklärung dieser Funktion bitte meisterhirn.js betrachten
+function judge(row, solution) {
+ row = row.slice();
+ solution = solution.slice();
+
+ // Anzahl weißer und schwarzer Stecker
+ var white = 0,
+ black = 0;
+
+ // Schwarze Stecker
+ var i = row.length;
+ while(i) {
+ i--;
+ if(row[i] == solution[i]) {
+ black++;
+ // Position aus beiden Arrays löschen (=> wird nicht doppelt gezählt)
+ row .splice(i, 1);
+ solution.splice(i, 1);
+ }
+ }
+
+ // Weiße Stecker
+ var i = row.length;
+ while(i) {
+ i--;
+ var j = solution.length;
+ while(j) {
+ j--;
+ // Farbe aus erstem Array kommt irgendwo im zweiten Array vor
+ if(row[i] == solution[j]) {
+ white++;
+ // Diese Positionen löschen
+ row .splice(i, 1);
+ solution.splice(j, 1);
+ break;
+ }
+ }
+ }
+
+ return [black, white];
+}
1,121 lib/meisterhirn.js
@@ -0,0 +1,1121 @@
+/*
+ * Copyright (c) 2010 Tim Baumann
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+var Meisterhirn = (function(win, doc, M) { // Closure (Anonyme Funktion, die Sofort ausgeführt wird). Innerhalb ist das globale Objekt window als win, document als doc und Math als M verfügbar
+
+
+ /******************
+ * Hilfsfunktionen *
+ ******************/
+
+ // Führt eine Funktion fn i-Mal aus
+ function times(i, fn) {
+ for(var j = 0; j < i; j++) { // Zählvariable j zählt bi i - 1
+ fn(j); // Funktion ausführen mit der Nummer der Iteration als Parameter
+ }
+ }
+
+ // Führt für jeden Wert in einem Array oder Objekt "obj" eine Funktion "fn" aus
+ function each(obj, fn) {
+ if(obj.length) { // Arrays haben eine length-Eigenschaft
+ times(obj.length, function(i) { // Für jeden Index i im Array …
+ fn(obj[i], i); // … die Funktion mit dem Wert an Stelle i und i als Parametern aufrufen
+ });
+ } else { // Normales Objekt
+ for(var key in obj) { // For-in-Schleife: durchläuft alle Schlüssel in einem Objekt
+ if(obj.hasOwnProperty(key)) { // Schlüssel ist im Objekt selber, nicht in einem Objekt in
+ // der Prototyp-Kette enthalten
+ fn(obj[key], key); // Funktion mit dem Wert und dem Schlüssel als Parameter aufrufen
+ }
+ }
+ }
+ }
+
+ // Dunkelt eine Farbe ab
+ function darker(hex) {
+ hex = hex.replace(/^#/, ''); // Raute entfernen
+
+ // Kurzform erweitern
+ if(hex.length == 3) {
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
+ }
+
+ // Gibt eine Nummber im Hex-Format zurück, immer zweistellig
+ function toHex(index) {
+ var val = parseInt(hex.substr(index * 2, 2), 16), // Aus Zeichenkette auslesen und zu einer Zahl umrechnen
+ str = M.round(val * val / 470).toString(16); // Wert verringern (je größer ein Wert ist, desto weniger wird er verringert) und in einen String umrechnen (Basis: 16)
+ if(str.length == 1) { // Nur eine Stelle?
+ str = '0' + str; // Führende 0 hinzufügen
+ }
+ return str;
+ }
+
+ // Hex-String bauen und zurückgeben
+ return '#' + toHex(0) + toHex(1) + toHex(2);
+ }
+
+ // Gibt die Position auf der Seite eines Elements "el" zurück
+ function getOffsets(el) {
+ var left = 0,
+ top = 0;
+ // Berechnung der Position mit den Eigenschaften offsetLeft und offsetTop,
+ // die zum offsetParent relativ sind, dessen offsetLeft- und offsetTop-Werte
+ // wiederum zu dessen offsetParent relativ sind usw.
+ while(el) {
+ left += el.offsetLeft;
+ top += el.offsetTop;
+ el = el.offsetParent;
+ }
+ return [left, top]; // x- und y- Wert in Array zurückgeben
+ }
+
+
+ /*********
+ * Mixins *
+ *********/
+
+ // Fügt in ein Objekt "obj" alle in "mixin" enthaltenen Eigenschaften und Methoden ein
+ function mixin(obj, mixin) {
+ each(mixin, function(val, key) { // Für jeden Schlüssel und den dazugehörigen Wert in mixin wird eine anonyme Funktion ausgeführt (siehe Funktion each)
+ obj[key] = val; // Das obj bekommt für den Schlüssel den gleichen Wert wie mixin
+ });
+ }
+
+ // Options-Mixin: sorgt für konfigurierbare Objekte mit in obj.options gespeicherten Standardwerten
+ var Options = {
+ setOptions: function(opts) { // opts ist das vom Nutzer übermittelte Konfigurationsobjekt
+ var dflt = this.options, // Standardeinstellungen
+ options = this.options = {}; // Standardeinstallungen leeren
+
+ each(dflt, function(val, key) { // für jeden Schlüssel und Wert in den Standardeinstellungen
+ options[key] = (opts.hasOwnProperty(key)) // setze die Einstellung. Wenn der Benutzer eine Einstellung definiert hat, dann
+ ? opts[key] // nimm die Benutzereinstellung
+ : val; // ansonsten nimm die Standardeinstallung.
+ });
+ }
+ };
+
+ // Ereignisbehandlung
+ var Events = {
+ // Eine Funktion "fn", soll bei einem bestimmten Ereignis mit Namen "type" ausgeführt werden
+ addEventListener: function(type, fn) {
+ if(!this.events) { // noch kein this.events-Objekt vorhanden?
+ this.events = {}; // this.events initialisieren
+ }
+ if(!this.events[type]) { // noch keine Event-Listener für diesen Event
+ this.events[type] = []; // initalisieren
+ }
+ this.events[type].push(fn); // Funktion zum Array der Funktionen hinzufügen, die bei dem Ereignis type ausgeführt werden sollen
+ },
+ // Ereignis "type" auslösen
+ fireEvent: function(type) {
+ if(this.events) { // Eventbehandlung wurde initialisiert (das ist erst nach mind. einem Aufruf von addEventListener der Fall, siehe oben)
+ var evts = this.events[type]; // Events dieses Typs raussuchen
+ if(evts) { // Es gibt Events dieses Typs
+ var args = Array.prototype.slice.call(arguments, 1); // Erklärung:
+ // arguments sind alle Argumente mit denen die aktuelle Funktion (also hier fireEvent) aufgerufen wurde.
+ // Der erste Parameter ist ja "type", darum brauchen wir alle ab dem zweiten.
+ // Bei Arrays kann ich mit bspArray.slice(1) alle Elemente ab dem zweiten (Index: 1) extrahieren.
+ // arguments ist aber aus historischen Gründen kann Array, sondern nur array-ähnlich und unterstützt diese Methode nicht.
+ // Wir können aber die Array-Methode (verfügbar über Array.prototype.slice) auf arguments anwenden (mit der call-Methode, die jede Funktion besitzt, dabei ist der erste Parameter das Objekt, auf das sie angewendet werden soll und die nächsten Parameter sind die Parameter, mit denen die Funktion ausgeführt werden soll)
+
+ each(evts, function(evt) { // Für jedes der Event-Funktionen …
+ evt.apply(null, args); // … die Funktion mit den in der Variable args gespeicherten Parametern ausführen
+ });
+ }
+ }
+ }
+ };
+
+ // Verarbeitet Klicks
+ var ClickAreas = {
+ // fügt eine Klickzone hinzu:
+ // * name ist ein Name, der dieser Klickzone gegeben wird. Es können auch mehrere Klickzonen mit dem gleichen Namen existieren.
+ // * zone ist ein Objekt, das die Eigenschaften x, y, width und height besitzt und den Bereich relative zum Element (this.toElement()) beschreibt
+ // * fn ist eine Funktion die bei einem Klick in diesen Bereich ausgeführt wird
+ // * priority ermöglicht es, andere Bereiche zu überlagern (Klick gilt für den Bereich mit der größten Priorität). Standardwert: 0
+ addClickArea: function(name, zone, fn, priority) {
+ if(!this.clickAreas) {
+ // Initialisierung
+ this.clickAreas = {};
+
+ var isIphone = navigator.userAgent.toLowerCase().indexOf('iphone') != -1, // handelt es sich um ein iPhone oder einen iPod touch? (navigator.userAgent ist ein besonderen String, der den Browser beschreibt, mit toLowerCase() wird er Kleingeschrieben zurückgegeben und indexOf gibt die Position eines Teilstrings zurück, oder wenn er nicht vorkommt -1
+ event = (isIphone) ? 'touchstart' : 'click'; // Für iPhones ist das Event auf das gewartet wird 'touchstart' für andere Geräte 'click' (touchstart wird auf dem iPhone früher ausgelöst als click => Performance)
+ var el = this.toElement(); // das Element
+
+ var _this = this; // this ist das Objekt, auf das eine Funktion angewendet werden soll, Referenz darauf wird in der Variable _this gespeichert
+ el.addEventListener(event, function(evt) { // anonyme Funktion soll bei Event mit dem in der Variable event gespeicherten Namen (siehe oben) ausgeführt werden
+ if(isIphone) {
+ evt = evt.changedTouches[0]; // Beim iPhone sind die Eigenschaften des Events in changedTouches[0] gespeichert (da es beim iPhone mehrere Bildschirmberührungen geben kann)
+ }
+ var offsets = getOffsets(el), // Absolute Position des Elements in Array
+ x = evt.pageX - offsets[0], // relative X-Position
+ y = evt.pageY - offsets[1]; // relative Y-Position
+ _this.handleClick(evt, x, y); // handleClick-Methode mit der relativen Position aufrufen
+ }, false); // false bitte nicht beachten
+ }
+
+ if(!this.clickAreas[name]) { // noch keine Klickzone mit diesem Namen?
+ this.clickAreas[name] = []; // initialisieren
+ }
+
+ this.clickAreas[name].push({
+ callback: fn, // die Funktion, die ausgeführt werden soll
+ zone: zone, // die Zone
+ priority: priority || 0 // die Priorität, oder wenn nicht angegeben, 0
+ });
+ },
+ removeClickAreas: function(name) {
+ if(this.clickAreas && this.clickAreas[name]) { // sind die Klickzonen initialisiert und wenn ja, gibt es Klickzonen mit dem Namen?
+ delete this.clickAreas[name]; // Löschen
+ }
+ },
+ // verarbeitet einen Klick mit den relativen Koordinatien x und y
+ handleClick: function(evt, x, y) {
+ var currPriority = -1, // Die erste Priorität
+ zones = []; // Alle Zonen, in die der Klick fällt und die die aktuelle Priorität haben
+
+ each(this.clickAreas, function(cz2) {
+ each(cz2, function(zone) {
+ // Für jede Zone …
+ var rect = zone.zone; // … das Rechteck
+ if(x >= rect.x
+ && y >= rect.y
+ && x <= rect.x + rect.width
+ && y <= rect.y + rect.height) { // wenn der Punkt (x|y) in dem Rechteck liegt
+ if(zone.priority > currPriority) { // Wenn die Zone eine höhere Priorität besitzt
+ currPriority = zone.priority; // die aktuelle Priorität wird aktualisiert
+ zones = [zone]; // Zonen ist ein neues Array, das nur aus der Zone besteht
+ } else if(zone.priority == currPriority) { // Wenn die Zone die gleiche Priorität besitzt
+ zones.push(zone); // Zone speichern
+ }
+ }
+ });
+ });
+
+ var _this = this; // Referenz auf this
+ each(zones, function(zone) {
+ zone.callback.call(_this, x - zone.zone.x, y - zone.zone.y); // Für jede Zone die Callback-Funktion
+ });
+
+ if(zones.length && evt.stopPropagation) {
+ evt.stopPropagation();
+ }
+ }
+ };
+
+ /***********
+ * Bildchen *
+ ***********/
+
+ var makeIcon = function(fn) {
+ return function(ctx, x, y, a, color) {
+ ctx.save(); // Einstellungen sichern
+ ctx.translate(x, y); // Nullpunkt verschieben => Nullpunkt ist in der Mitte
+ ctx.scale(a/2, a/2); // Skalieren => von der Mitte bis zur Seite ist es nur 1 lang
+ ctx.fillStyle = color; // Füllfarbe setzen
+ ctx.strokeStyle = color; // Linienfarbe setzen
+ fn(ctx, color);
+ ctx.restore(); // Einstellungen wiederherstellen
+ };
+ };
+
+ // Eine Icon-Funktion malt ein Bild in ctx mit Mittelpunkt x, y mit Kantenlänge a und Farbe color
+ var icons = {
+ questionBubble: function(ctx, x, y, a, color) {
+ var r = a/2;
+
+ ctx.save();
+ ctx.translate(x, y);
+ ctx.scale(r, r);
+
+ // Kreis
+ ctx.beginPath();
+ ctx.arc(0, 0, 1, 0, 2 * M.PI, true);
+ ctx.fillStyle = color;
+ ctx.fill();
+
+ ctx.scale(1/r, 1/r); // Muss ausskalieren, da sonst die Browser bei der Schrift Murks machen
+ ctx.fillStyle = '#000';
+ ctx.globalCompositeOperation = 'destination-out';
+ ctx.font = 'bold ' + (1.25 * r) + 'px Helvetica, Arial, sans-serif'; // Schriftart, -Größe und -Stil
+ ctx.textAlign = 'center'; // Schrift ist horizontal zentriert am Punkt ausgerichtet
+ ctx.textBaseline = 'middle'; // Schrift ist vertikal zentriert am Punkt ausgerichtet
+ ctx.fillText('?', 0, .1*r);
+
+ ctx.restore();
+ },
+ eye: makeIcon(function(ctx) {
+ // Äußeres Oval
+ ctx.beginPath(); // Pfad beginen
+ ctx.moveTo(-1, 0); // zur Mitte der linken Kante bewegen
+ ctx.quadraticCurveTo(0, -1, 1, 0); // Eine Kurve zur Mitte der rechten Kante
+ ctx.quadraticCurveTo(0, 1, -1, 0); // Eine Kurve zur Mitte der linken Kante
+ ctx.fill(); // Füllen
+ // Innerer Augapfel
+ ctx.beginPath(); // Pfad beginnen
+ ctx.arc(0, 0, .3, 0, 2 * M.PI, false); // Einen Kreis um das Zentrum zeichnen
+ ctx.fillStyle = '#000'; // Füllfarbe setzen
+ ctx.globalCompositeOperation = 'destination-out'; // Bereich entfernen (transparent machen)
+ ctx.fill(); // Füllen
+ }),
+ checkmark: makeIcon(function(ctx) {
+ ctx.beginPath(); // Pfad beginnen
+ ctx.moveTo(-.76, 0); // Ans linke Ende des Hakens bewegen
+ ctx.quadraticCurveTo(-.30, .25, 0, .64); // Kurve zur Spitze des Hakens
+ ctx.quadraticCurveTo( .18, 0, .78, -.78); // Kurve zum rechten Ende des Hakens
+ ctx.lineWidth = .3; // Strichbreite
+ ctx.lineCap = 'square'; // Das Ende einer Linie is eckig
+ ctx.stroke(); // Pfad nachzeichnen
+ }),
+ closedArrow: makeIcon(function(ctx) {
+ // Teilkreis
+ ctx.beginPath();
+ ctx.arc(0, 0, .68, 1, 1.92 * M.PI, false);
+ ctx.lineWidth = .3;
+ ctx.stroke();
+
+ // Pfeilspitze
+ ctx.rotate(1.9 * M.PI);
+ ctx.translate(.68, 0);
+ ctx.beginPath();
+ ctx.moveTo(-.4, 0);
+ ctx.lineTo( .4, 0);
+ ctx.lineTo( 0, .4);
+ ctx.fill();
+ }),
+ bubble: makeIcon(function(ctx, color) {
+ // Hintergrund: Verlauf vom Zentrum (Glühen)
+ ctx.beginPath();
+ ctx.arc(0, 0, 1.4, 0, 2 * M.PI, true); // Kreis
+ var gradient = ctx.createRadialGradient(0, 0, 1, 0, 0, 1.4); // Runden Farbverlauf erstellen
+ gradient.addColorStop(0, 'rgba(0, 0, 0, .18)'); // Farbe am Anfang des Farbverlaufes: Schwarz, 18% opak
+ gradient.addColorStop(1, 'transparent'); // Farbe am Ende: Voll transparentes schwarz
+ ctx.fillStyle = gradient; // Füllung: der Farbverlauf
+ ctx.fill();
+
+ // Kugel
+ ctx.beginPath();
+ ctx.arc(0, 0, 1, 0, 2 * M.PI, true);
+ gradient = ctx.createRadialGradient(-.3, -.3, .03, 0, 0, 1); // Farbverlauf
+ gradient.addColorStop(0, color); // Farbe am Anfang: die Farbe
+ gradient.addColorStop(1, darker(color)); // Farbe am Ende: die Farbe, abgedunkelt
+ ctx.fillStyle = gradient;
+ ctx.fill();
+ })
+ };
+
+
+ /*********
+ * Modell *
+ *********/
+
+ // Bewertet eine gesetzte Reihe anhand der Lösung
+ function judge(row, solution) {
+ // Kopien erstellen, damit Änderungen auf das Array sich nicht außerhalb dieser Funktion auswirken
+ row = row.slice();
+ solution = solution.slice();
+
+ // Anzahl weißer und schwarzer Stecker
+ var white = 0,
+ black = 0;
+
+ // Schwarze Stecker
+ var i = row.length; // length-Eigenschaft eines Arrays ist dessen Länge
+ while(i) { // Nummern sind wahr, wenn sie ungleich 0 sind
+ i--; // i runterzählen
+ if(row[i] == solution[i]) { // Diese Position stimmt überein
+ black++; // Anzahl der schwarzen Treffer hochzählen
+ // Position aus beiden Arrays löschen (=> wird nicht doppelt gezählt)
+ row .splice(i, 1); // splice löscht von der Position i an ein Element
+ solution.splice(i, 1); // splice löscht von der Position i an ein Element
+ }
+ }
+
+ // Weiße Stecker
+ var i = row.length; // length-Eigenschaft eines Arrays ist dessen Länge
+ while(i) { // Nummern sind wahr, wenn sie ungleich 0 sind
+ i--; // i runterzählen
+ var j = solution.length; // j: Länge der Lösung
+ while(j) {
+ j--; // j runterzählen
+ // Farbe aus erstem Array kommt irgendwo im zweiten Array vor
+ if(row[i] == solution[j]) { // Übereinstimmung
+ white++; // Anzahl der weißen Treffer hochzählen
+ // Diese Positionen löschen
+ row .splice(i, 1); // splice löscht von der Position i an ein Element
+ solution.splice(j, 1); // splice löscht von der Position j an ein Element
+ break; // innere Schleife beenden
+ }
+ }
+ }
+
+ return [black, white]; // Ergebnis als Array zurückgeben
+ }
+
+ function Model(options) { // Konstruktorfunktion
+ this.setOptions(options); // Optionen setzen
+ }
+ // Instanzmethoden und -Eigenschaften
+ Model.prototype = {
+ constructor: Model, // Referenz zur Konstruktorfunktion
+
+ // Standardoptionen
+ options: {
+ rows: 8, // Anzahl Reihen
+ cols: 4, // Anzahl Spalten
+ colors: 6, // Anzahl Farben
+ multiple: false // Dürfen Farben in der Lösung doppelt vorkommen?
+ },
+
+ // Für ein neues Spiel vorbereiten
+ reset: function() {
+ this.count = 0; // Count-Eigenschaft: Nummer der aktuellen Zeile (beginnt natürlich mit 0)
+ this.won = false; // noch nicht gewonnen.
+ this.lost = false; // aber auch noch nicht verloren.
+
+ this.generateSolution(); // Lösung erzeugen
+
+ var emptyRow = [];
+ times(this.options.cols, function(i) {
+ emptyRow[i] = -1;
+ }); // Array aus Spalten mal -1 erzeugen, als Vorlage
+
+ var guesses = this.guesses = []; // Array mit den bisherigen Versuchen
+ // guesses initialisieren: Matrix mit Reihen x Spalten. Für jede Reihe ein Array mit für jeder Spalte den Wert -1
+ times(this.options.rows, function(i) { // Reihen mal
+ guesses[i] = emptyRow.slice(); // Kopie des Arrays aus -1 hinzufügen
+ });
+ },
+ // Zufällige Farbenkombination, Farben können auch mehrmals vorkommen!
+ generateSolution: function() {
+ var solution = this.solution = [], // Lösung initialisieren
+ colors = this.options.colors, // Tipparbeit sparen
+ cols = this.options.cols; // s.o.
+
+ if(this.options.multiple) { // Dürfen Farben mehrmals vorkommen?
+ // Ja
+ times(cols, function() { // Sooft wie es Spalten gibt …
+ solution.push(M.floor(M.random() * colors)); // … soll eine Zufallszahl von 0-1 erzeugt, diese mit der Anzahl der Farben multipliziert und abgerundet werden, bevor sie zum Lösungsarray hinzugefügt wird
+ });
+ } else {
+ // Nein
+
+ // Array mit den Farbnummern (0 bis Anzahl der Farben minus 1) erstellen:
+ var colorsArray = [];
+ times(colors, function(i) {
+ colorsArray.push(i);
+ });
+
+ times(cols, function() { // Sooft wie es Spalten gibt …
+ var i = M.floor(M.random() * colorsArray.length); // Eine ganze Zufallszahl von 0 bis zum letzten Index des Farbenarrays generieren
+ solution.push(colorsArray[i]); // Farbe an Position der Zufallszahl zur Lösung hinzufügen
+ colorsArray.splice(i, 1); // Farbe aus dem Farbenarray Löschen
+ });
+ }
+ },
+ nextRow: function() {
+ if(this.won || this.lost) { // Spiel schon beendet?
+ return; // Funktion verlassen
+ }
+
+ this.count++; // aktuelle Zeile hochzählen
+
+ // Maximalanzahl an Zeilen erreicht?
+ if(this.count == this.options.rows) {
+ this.lost = true; // Verloren
+ this.fireEvent('lose'); // 'lose'-Event feuern
+ }
+ },
+ // Ob die aktuelle Zeile schon vollständig mit Farben bestückt worden ist.
+ isRowSet: function() {
+ var row = this.guesses[this.count]; // aktuelle Zeile
+ var i = row.length;
+ while(i) {
+ i--;
+ if(row[i] < 0) { // Ist die Position i nicht gesetzt?
+ return false; // Falschwert zurückgeben
+ }
+ }
+ return true; // Alles gesetzt! (Richtigwert zurückgeben)
+ },
+ // Farbe color an der Position position in der aktuellen Zeile setzen
+ setColor: function(position, color) {
+ this.guesses[this.count][position] = color;
+ },
+ checkRow: function() {
+ var result = judge(this.guesses[this.count], this.solution), // Wie viele schwarze und weiße Treffer (Vergleich der aktuellen Zeile mit der Lösung)
+ black = result[0], // Anzahl schwarz
+ white = result[1]; // Anzahl weiß
+
+ if(black == this.options.cols) { // Gewonnen? (Anzahl der schwarzen Treffer ist gleich der Anzahl der Spalten)
+ this.won = true; // Ja!
+ }
+
+ // Ergebnis melden:
+ this.fireEvent('row', black, white); // Event row feuern mit der Anzahl der schwarzen und weißen Treffer als Parameter
+
+ // Gewinn melden:
+ if(this.won) { // Gewonnen?
+ this.fireEvent('win'); // "win"-Event feuern
+ }
+ }
+ };
+ mixin(Model.prototype, Options); // Unterstützung von Optionen hinzufügen
+ mixin(Model.prototype, Events); // Eventunterstützung hinzufügen
+
+
+ /***************
+ * Präsentation *
+ ***************/
+
+ function View(model, options) { // Konstruktorfunktion
+ this.model = model; // Referenz zum Model in der Instanzvariablen model Speichern
+ this.setOptions(options); // Optionen setzen
+ this.createInterface(); // Die Benutzeroberfläche aufbauen
+ }
+ View.prototype = {
+ constructor: View, // Referenz von der Instanz zur Konstruktorfunktion
+
+ // Optionen
+ options: {
+ colors: ['#f44', '#4f4', '#ff4', '#4ff', '#fa5', '#ff59e1', '#9d00ce', '#88f'], // Die Farben. Sollte mindestens so lang sein wie die Anzahl der Farben in den Einstellungen des Modells
+ ruleWidth: 1, // Breite des Gitters zwischen den Feldern
+ ruleColor: '#bbb', // Farbe des Gitters
+ gridWidth: 69, // Breite eines Feldes (in Pixeln)
+ relativeBubbleRadius: .7, // Durchmesser einer Kugel (relativ zum ganzen Feld)
+ backgroundColor: '#eee', // Hintergrundfarbe im eigentlichen Spielfeld
+ leftBackgroundColor: '#5B0000', // Hintergrundfarbe links (dort, wo die Zeilennummern oder Treffer stehen)
+ bottomBackgroundColor: '#444', // Hintergrundfarbe unten (dort, wo das Ergebnis angezeigt wird und der Knopf zum Neustarten ist)
+ numberFont: '30px Georgia, serif', // Schriftgröße und -art der Zeilennummern
+ numberColor: '#ffffca', // Die Farbe der Zeilennummern
+ iconColor: '#fff', // Die Farbe der Buttons links unten
+ relativeIconSize: .75, // Seitenlänge der Knöpfe links unten und zum Akzeptieren einer Zeile relative zum ganzen Feld
+
+ // Einstellungen zum Layer, der sich öffnet, wenn man die Farbe auf einem Feld auswählen möchte
+ selectTriangleHeight: 16, // Höhe des kleinen Dreiecks, das zum Mittelpunkt des Feldes weist in Pixeln
+ selectPadding: 10, // Innenabstand in Pixeln
+ selectGridWidth: 50, // Rasterbreite
+ selectRelativeBubbleRadius: .8, // Durchmesser einer Kugel, relativ zur Rasterbreite
+ selectBorderRadius: 10, // Abrundung des Rands in Pixeln
+ selectMargin: 10, // Außenabstand (zum Rand des Spielfeldes)
+ selectBackgroundColor: 'rgba(0, 0, 0, 0.6)', // Hintergrundfarbe
+
+ questionColor: '#666', // Farbe des verdeckten Erebnisses (die Kreise mit dem Fragezeichen in der Mitte)
+ holeColor: '#aaa', // Farbe des Steckplatzes
+ relativeHoleRadius: .1, // Radius des Steckplatzes, relativ zur Feldgröße
+
+ // Einstellungen zu der Trefferanzeige:
+ matchesRelativeWidth: .7, // Welchen Platz nimmt die Trefferanzeige relativ zum ganzen Feld ein
+ matchesRelativeRadius: .7, // Radius eines Treffers (relativ, 1 heißt: alle Treffer würden ohne Abstand aneinanderpacken)
+ matchesBlackColor: '#ff0', // Farbe für einen "schwarzen" Treffer (gleicher Ort, gleiche Farbe)
+ matchesWhiteColor: '#fff', // Farbe für einen "weißen" Treffer (nur gleiche Farbe)
+
+ // Einstellungen zu den eingeblendeten Nachrichten:
+ messageFont: '40px Lobster, Palatino, Georgia, serif', // Schriftgröße und -art
+ messageColor: '#fff', // Schriftfarbe
+ messageGaveUp: 'You gave up', // Nachricht beim Aufgeben
+ messageWon: 'We have a winner!', // Nachricht bei Gewinn
+ messageLost: 'You\'re a loser!', // Nachricht bei Niederlage
+ messageShadowColor: '#fff', // Schriftschattenfarbe
+ messageShadowBlur: 20, // Ungenauigkeit des Schriftschattens in Pixeln
+ messageMargin: 10, // minimaler Abstand vom Rand
+ messageBackgroundColor: 'rgba(0, 0, 0, 0.5)' // Hintergrundfarbe
+ },
+
+ // Benutzeroberfläche erstellen
+ createInterface: function() {
+ this.calculateDimensions(); // Wie groß wird das Feld werden?
+
+ this.el = doc.createElement('div'); // Ein div-Element erstellen
+ this.el.className = 'meisterhirn'; // Klasse des Elements: "mastermind"
+ this.el.style.position = 'relative'; // Element ist relativ positioniert => Kindelemente können relativ zu diesem Element positioniert werden
+ this.el.style.width = this.width + 'px'; // Breite des Elements auf die mit calculateDimensions errechnete Breite setzen
+ this.el.style.height = this.height + 'px'; // Höhe des Elements auf die mit calculateDimensions errechnete Höhe setzen
+
+ this.createBackgroundCanvas(); // Hintergrund erzeugen
+ this.createForegroundCanvas(); // Vordergrund erzeugen
+ },
+ createBackgroundCanvas: function() {
+ // Tipparbeit sparen:
+ var w = this.width,
+ h = this.height,
+ opts = this.options,
+ rw = opts.ruleWidth,
+ gw = opts.gridWidth,
+ ww = rw + gw
+ ctx = this.background = this.createCanvas(); // neue, leere Zeichenfläche
+
+ // Hintergrund malen
+ ctx.fillStyle = opts.backgroundColor;
+ ctx.fillRect(0, 0, w, h);
+
+ // Hintergrund im unteren Bereich (Ergebnis) malen
+ ctx.fillStyle = opts.bottomBackgroundColor;
+ ctx.fillRect(rw, h - ww, w - 2 * rw, gw);
+
+ // Hintergrund im linken Bereich (Zeilennummern, Trefferanzeiger) malen
+ ctx.fillStyle = opts.leftBackgroundColor;
+ ctx.fillRect(rw, rw, gw, h - gw - 3 * rw);
+
+ // Gitter zeichnen
+ ctx.fillStyle = opts.ruleColor;
+ // Horizontale Gitterlinien zeichnen
+ times(this.model.options.rows + 2, function(i) {
+ ctx.fillRect(0, i * ww, w, rw);
+ });
+ // Vertikale Gitterlinien zeichnen
+ times(this.model.options.cols + 2, function(i) {
+ ctx.fillRect(i * ww, 0, rw, h);
+ });
+ },
+ createForegroundCanvas: function() {
+ this.foreground = this.createCanvas(); // Neue leere Zeichenfläche
+ },
+
+ // Hilfsfunktionen
+ // löscht (transparent machen) ein Feld field (mit x, y, width und height) im Vordergrund
+ clearField: function(field) {
+ this.foreground.clearRect(field.x, field.y, field.width, field.height); // clearRect löscht einen rechteckigen Bereich. Parameter: x, y, width, height
+ },
+ // Zeichnet einen Knopf mittels "iconFn" im Feld (x|y), fügt die entsprechende Klickzone hinzu (mit dem Namen "clickArea") und feuert beim Klick ein bestimmtes Event
+ drawButton: function(iconFn, x, y, clickArea, clickEvent) {
+ var field = this.getField(x, y), // Rechteck des Feldes mit den Koordinaten (x|y)
+ coords = this.getMidpoint(field); // Mittelpunkt des Feldes
+
+ // Malen
+ this.clearField(field); // Feld löschen
+ iconFn(this.foreground, coords[0], coords[1], this.options.gridWidth * this.options.relativeIconSize, this.options.iconColor); // Icon im Vordergrund ausgerichtet am Mittelpunkt des Feldes in der eingestellten Farbe und der eingestellten Größe zeichnen
+
+ // Klickbereich
+ this.removeClickAreas(clickArea); // Klickzonen mit dem Namen löschen
+ var _this = this; // Referenz auf this zur Verwendung in verschachtelten Funktionen speichern
+ this.addClickArea(clickArea, field, function() { // Neue Klickzone mit dem Namen clickArea im Rechteck field
+ _this.fireEvent(clickEvent); // Event auslösen
+ }, 6); // 6 ist die Priorität
+ },
+ // baut ein Canvas-Element in der Größe des Spielfeldes, fügt es ein und gibt das Zeichenfeld zurück => neuer Layer zum zeichnen
+ createCanvas: function() {
+ var canvas = doc.createElement('canvas'); // Neues Canvas-Element erzeugen
+ canvas.style.position = 'absolute'; // Absolut ausgerichtet => gleiche Position wie Elternelement
+ canvas.width = this.width; // Breite auf die Spielfeldbreite setzen
+ canvas.height = this.height; // Höhe auf die Spielfeldhöhe setzen
+ this.el.appendChild(canvas); // Ins Dokument als Kindknoten von this.el einfügen
+
+ return canvas.getContext('2d'); // Zeichenfläche zurückgeben
+ },
+ // Zeichnet eine Kugel im Feld (x|y) in der Farbe Nummer color
+ drawBubble: function(x, y, color) {
+ var a = this.options.gridWidth * this.options.relativeBubbleRadius // Durchmesser
+ field = this.getField(x, y), // Rechteck
+ coords = this.getMidpoint(field); // Rechteckmittelpunkt
+
+ this.clearField(field); // Feld löschen
+ icons.bubble(this.foreground, coords[0], coords[1], a, this.options.colors[color]); // zeichnen
+ },
+ // Zeichnet eine verdeckte Kugel im Feld (x|y)
+ drawQuestionBubble: function(x, y) {
+ var a = this.options.gridWidth * this.options.relativeBubbleRadius // Durchmesser
+ field = this.getField(x, y), // Rechteck
+ coords = this.getMidpoint(field); // Rechtecksmittelpunkt
+
+ this.clearField(field); // Feld löschen
+ icons.questionBubble(this.foreground, coords[0], coords[1], a, this.options.questionColor); // zeichnen
+ },
+ // Größen und Positionen berechnen
+ calculateDimensions: function() {
+ var rows = this.model.options.rows + 1; // Zeilen für das Spielfeld + eine Zeile für das Ergebnis
+ this.height = rows * this.options.gridWidth
+ + (rows + 1) * this.options.ruleWidth; // Die Höhe ist die Anzahl der Reihen mal der Rasterbreite plus (die Anzahl der Zeilen plus eins) mal der Gitterbreite
+
+ var cols = this.model.options.cols + 1; // Spalten für das Spielfeld + eine Spalte für die Zeilennummern
+ this.width = cols * this.options.gridWidth
+ + (cols + 1) * this.options.ruleWidth; // Analog zur Höhe, s.o.
+ },
+ // Gibt ein Objekt zurück, das mit den Eigenschaften x, y, width und height die Position und Größe des Feldes (x|y)
+ getField: function(x, y) {
+ var gw = this.options.gridWidth,
+ rw = this.options.ruleWidth;
+ return {
+ x: x * gw + (x + 1) * rw, // Die Position ist die Anzahl der vorhergehenden Spalten (x) mal der Gitterbreite plus (die Anzahl der vorhergehenden Spalten plus eins) mal der Gitterbreite
+ y: y * gw + (y + 1) * rw, // Analog, s.o.
+ width: gw, // Die Gitterbreite
+ height: gw // s.o.
+ };
+ },
+ // gibt den Mittelpunkt eines Rechtecks, so wie getField eines zurückgibt
+ getMidpoint: function(field) {
+ var x = field.x + field.width / 2,
+ y = field.y + field.height / 2;
+ return [x, y];
+ },
+ // zeigt eine Nachricht msg, Spielfeld wird wird verdunkelt
+ showMessage: function(msg) {
+ var ctx = this.message = this.createCanvas(), // neue Zeichenfläche
+ opts = this.options,
+ // Rechteck: ganzes Spielfeld außer der untersten Zeile
+ field = {
+ x: opts.ruleWidth,
+ y: opts.ruleWidth,
+ width: (this.model.options.cols + 1) * (opts.gridWidth + opts.ruleWidth) - opts.ruleWidth,
+ height: this.model.options.rows * (opts.gridWidth + opts.ruleWidth) - opts.ruleWidth
+ },
+ coords = this.getMidpoint(field);
+ ctx.fillStyle = opts.messageBackgroundColor; // Füllfarbe setzen
+ ctx.fillRect(field.x, field.y, field.width, field.height); // damit füllen
+ ctx.textAlign = 'center'; // Text horizontal mittig ausrichten
+ ctx.textBaseline = 'middle'; // Text vertikal mittig ausrichten
+ ctx.font = opts.messageFont; // Schriftgröße und -art setzen
+ ctx.shadowBlur = opts.messageShadowBlur; // Schattenunschärfe setzen
+ ctx.shadowColor = opts.messageShadowColor; // Schattenfarbe setzen
+ ctx.fillStyle = opts.messageColor; // Füllfarbe: Schriftfarbe
+ ctx.fillText(msg, coords[0], coords[1], this.width - 2 * opts.messageMargin); // Text in der Füllfarbe an die Koordinaten in coords schreiben mit der gesamten Breite minus zweimal dem Abstand als Maximalbreite
+ },
+
+ // API
+ showRestartButton: function() {
+ this.drawButton(icons.closedArrow, 0, this.model.options.rows, 'bottomleft', 'restart'); // in der linken unteren Ecke einen kreisförmigen Pfeil zeichnen, bei Klick wird das Event "restart" ausgelöst
+ },
+ showShowButton: function() {
+ this.drawButton(icons.eye, 0, this.model.options.rows, 'bottomleft', 'show'); // analog, s.o.
+ },
+ showCheckButton: function() {
+ this.drawButton(icons.checkmark, 0, this.model.count, 'left', 'check'); // in der aktuellen Zeile links einen Haken malen, bei Klick wird das Event "ckeck" gefeuert
+ },
+ setBubble: function(position, color) {
+ this.drawBubble(position + 1, this.model.count, color); // in der aktuellen Zeile an die Position position eine Kugel in der Farbe Nummer color malen
+ },
+ drawLineNumbers: function() {
+ // Zeilennummern
+ var ctx = this.foreground; // Zeichenkontext
+ ctx.font = this.options.numberFont; // Schrift
+ ctx.fillStyle = this.options.numberColor; // Farbe
+ ctx.textAlign = 'center'; // horizontal mittig ausgerichtet
+ ctx.textBaseline = 'middle'; // vertikal mittig ausgerichtet
+ var _this = this; // Referenz auf this in _this speichern
+ times(this.model.options.rows, function(i) { // Für jedes i von 0 bis exklusiv Anzahl der Reihen
+ var field = _this.getField(0, i), // Rechteck links in der Zeile Nummer i
+ coords = _this.getMidpoint(field); // Mittelpunkt
+ _this.clearField(field); // Feld löschen
+ ctx.fillText(i + 1, coords[0], coords[1]); // Zeilennummer schreiben (i + 1 da normale Leute bei 1 zu zählen beginnen)
+ });
+ },
+ // die Steckplätze malen
+ drawHoles: function() {
+ var ctx = this.foreground; // Zeichenkontext
+ ctx.beginPath(); // Pfad beginnen
+
+ var _this = this,
+ radius = this.options.relativeHoleRadius * this.options.gridWidth / 2; // Radius berechnen
+ times(this.model.options.rows, function(r) { // Für jede Reihe …
+ times(_this.model.options.cols, function(c) { // … und jede Spalte
+ var field = _this.getField(c + 1, r), // das Feld raussuchen
+ coords = _this.getMidpoint(field); // dessen Mittelpunkt
+ _this.clearField(field); // Feld löschen
+ ctx.moveTo(coords[0], coords[1]); // zum Mittelpunkt bewegen
+ ctx.arc(coords[0], coords[1], radius, 0, 2 * M.PI, true); // Kreis zeichnen
+ });
+ });
+
+ ctx.fillStyle = this.options.holeColor; // Füllfarbe
+ ctx.fill(); // Füllen
+ },
+ // Lösung verstecken
+ hideSolution: function() {
+ // Die Ergebnisanzeige: Versteckt, symbolisiert durch Kreise mit Fragezeichen
+ var _this = this;
+ times(this.model.options.cols, function(i) { // Für jede Spalte …
+ _this.drawQuestionBubble(i + 1, _this.model.options.rows); // in der letzten Zeile an der Position i + 1 (weil die Linke spalte ja die Nummern sind) eine verdeckte Kugel zeichnen
+ });
+ },
+ // Die Lösung anzeigen
+ showSolution: function() {
+ var _this = this;
+ each(this.model.solution, function(color, i) {
+ _this.drawBubble(i + 1, _this.model.options.rows, color);
+ });
+ },
+ openSelect: function(i) {
+ this.closeSelect(); // Alle evt. offenen Selects schließen
+
+ var field = this.getField(i + 1, this.model.count), // Feld raussuchen: in der aktuellen Zeile, an der Position i + 1 (linke Spalte beachten)
+ coords = this.getMidpoint(field); // Mittelpunkt
+
+ var opts = this.options,
+ horizontalSpace = this.width - 2 * (opts.selectPadding + opts.selectMargin),
+ maxCols = M.min(this.model.options.colors, M.floor(horizontalSpace / opts.selectGridWidth)),
+ rows = Math.ceil(this.model.options.colors / maxCols),
+ cols = Math.ceil(this.model.options.colors / rows),
+ w = 2 * opts.selectPadding + cols * opts.selectGridWidth,
+ h = 2 * opts.selectPadding + rows * opts.selectGridWidth + opts.selectTriangleHeight; // Breite und Höhe der Select-Blase
+
+ // x und y sind die Koordinaten der linken, oberen Ecke
+ var x = coords[0] - w / 2; // zentriert
+ x = M.min(x, this.width - w - opts.selectMargin); // ragt nicht über den rechten Rand hinaus
+ x = M.max(x, opts.selectMargin); // ragt nicht über den linken Rand hinaus
+ var y = coords[1];
+
+ var ctx = this.select = this.createCanvas(); // Zeichenfläche
+
+ var tx = coords[0] - x, // der Abstand von der linken Seite zur Spitze des Dreiecks
+ th = opts.selectTriangleHeight,
+ br = opts.selectBorderRadius;
+
+ ctx.save(); // Einstellungen speichern
+ ctx.translate(x, y); // der Punkt (x|y) ist nun die linke, obere Ecke
+
+ // Das Ding, das so wie eine Sprechblase aussieht
+ ctx.beginPath(); // Pfad anfangen
+ ctx.moveTo(tx, 0); // Zur Spitze des Dreiecks
+ ctx.lineTo(tx + .6 * th, th); // rechte Seite des Dreiecks
+ ctx.lineTo(w - br, th); // rechte obere Seite
+ ctx.quadraticCurveTo(w, th, w, th + br); // Ecke rechts oben
+ ctx.lineTo(w, h - br); // rechte Seite
+ ctx.quadraticCurveTo(w, h, w - br, h); // Ecke rechts unten
+ ctx.lineTo(br, h); // untere Seite
+ ctx.quadraticCurveTo(0, h, 0, h - br); // Ecke links unten
+ ctx.lineTo(0, th + br); // linke Seite
+ ctx.quadraticCurveTo(0, th, br, th); // Ecke links oben
+ ctx.lineTo(tx - .6 * th, th); // linke obere Seite
+ ctx.lineTo(tx, 0); // linke Seite des Dreiecks
+
+ ctx.fillStyle = opts.selectBackgroundColor; // Füllfarbe setzen
+ ctx.fill(); // Füllen
+
+ ctx.restore(); // Einstellungen wiederherstellen
+
+ // Kugeln malen
+ var _this = this,
+ gw = opts.selectGridWidth,
+ pd = opts.selectPadding,
+ r = gw * opts.selectRelativeBubbleRadius,
+ colors = this.options.colors;
+ times(this.model.options.colors, function(j) { // Für jede Farbe eine
+ var field = {
+ x: x + pd + (j % cols) * gw,
+ y: y + th + pd + M.floor(j/cols) * gw,
+ width: gw,
+ height: gw
+ };
+ var coords = _this.getMidpoint(field);
+ _this.addClickArea('select', field, function() {
+ _this.fireEvent('select', i, j); // Für welche Position i welche Farbe j ausgewählt wurde
+ }, 9);
+ icons.bubble(ctx, coords[0], coords[1], r, colors[j]);
+ });
+
+ function close() {
+ _this.closeSelect(); // diese Auswahl-Blase schließen
+ doc.body.removeEventListener('click', close, false);
+ }
+
+ // Schließbar durch klicken irgendwo im Dokument
+ document.body.addEventListener('click', close, false);
+
+ // Aber nicht durch klicken in die Blase
+ this.addClickArea('bubble', {
+ x: x,
+ y: y + th, // Nicht der Bereich auf Höhe des Dreicks!
+ width: w,
+ height: h - th // … deshalb müssen wir die Dreieckshöhe auch von der Gesamthöhe abziehen
+ }, function() { /* leere anonyme Funktion */ }, 8);
+ },
+ closeSelect: function() {
+ if(this.select) { // Ist so eine Selectblase eigentlich offen
+ // Die in der obigen Funktion definierten Klickbereiche entfernen
+ this.removeClickAreas('select');
+ this.removeClickAreas('field');
+ this.removeClickAreas('bubble');
+ var c = this.select.canvas; // Das zur Zeichenfläche korrespondierende Element
+ c.parentNode.removeChild(c); // aus dem DOM (Document Object Model) entfernen
+ delete this.select; // Referenz auf die Selectblase entfernen
+ }
+ },
+ initRow: function() {
+ this.removeClickAreas('left'); // Es kann nicht mehr auf die Stelle geklickt werden, wo der Haken zum Prüfen war
+ this.removeClickAreas('row'); // Man kann keine Farben mehr durch Klicken auf die entsprechende Position mehr auswählen
+ var y = this.model.count, // aktuelle Zeilennummer
+ _this = this; // Referenz zur Verwendung in einer inneren Funktion:
+ times(this.model.options.cols, function(x) { // für jede Spalte
+ var field = _this.getField(x + 1, y); // Feld in der aktuellen Zeile und dieser Spalte
+ _this.addClickArea('row', field, function() { // und wenn man da hin klickt …
+ _this.fireEvent('rowclick', x); // dann wird das Event "rowclick" gefeuert mit der Nummer der Spalte, in die geklickt wurde
+ }, 6);
+ });
+ },
+ removeFieldClickAreas: function() {
+ this.removeClickAreas('row'); // Man kann nicht mehr auf Felder klicken, um die Farbe auszuwählen
+ this.removeClickAreas('left'); // Man kann keine Reihe mehr akzeptieren
+ },
+ // zeigt in der aktuellen Zeile das Ergebnis (wie viele Kugeln haben die gleiche Farbe und sind am gleichen Ort, wie viele haben nur die gleiche Farbe) an
+ showMatches: function(black, white) { // black sind die Volltreffer, white sind die Halbtreffer
+ var opts = this.options,
+ a = M.ceil(M.sqrt(this.model.options.cols)); // Seitenlänge im Quadrat in Anzahl von Stiften
+ aw = opts.gridWidth * opts.matchesRelativeWidth, // Seitenlänge des Ergebnisquadrats
+ gw = aw / a, // Welches Quadrat bleibt dem einzelnen Stift?
+ r = gw * opts.matchesRelativeRadius / 2, // Der Radius eines Stiftes innerhalb dieses Quadrates
+ field = this.getField(0, this.model.count), // Das Feld, in dem das Ergebnis gemalt wird
+ coords = this.getMidpoint(field), // Der Mittelpunkt dieses Feldes, in dem die Treffer angezeigt werden
+ ctx = this.foreground; // Da wird drauf gemalt
+
+ var position = 0; // Die Position der Kugel
+ function draw(color) {
+ var col = position % a, // In der wievielten Spalte soll die Kugel gezeichnet werden?
+ row = (position - col) / a, // In der wievielten Zeile soll die Kugel gezeichnet werden?
+ x = coords[0] - aw / 2 + (col + .5) * gw,
+ y = coords[1] - aw / 2 + (row + .5) * gw;
+
+ ctx.beginPath();
+ ctx.arc(x, y, r, 0, 2 * M.PI, false);
+ ctx.fillStyle = color;
+ ctx.fill();
+
+ position++; // nächste Kugel bekommt die nächste Position
+ }
+
+ this.clearField(field); // Dort wo das Ergebnis gezeichnet werden soll, alles löschen
+ // Sooft wie es schwarze Kugeln gibt, eine Kugel in der in den Einstellungen angegebenen Farbe zeichen:
+ times(black, function() {
+ draw(opts.matchesBlackColor);
+ });
+ // Sooft wie es weiße Kugeln gibt, eine Kugel in der in den Einstellungen angegebenen Farbe zeichen:
+ times(white, function() {
+ draw(opts.matchesWhiteColor);
+ });
+ },
+ // Nachrichten zeigen:
+ showGaveUpMessage: function() {
+ this.showMessage(this.options.messageGaveUp);
+ },
+ showLostMessage: function() {
+ this.showMessage(this.options.messageLost);
+ },
+ showWonMessage: function() {
+ this.showMessage(this.options.messageWon);
+ },
+ // Die aktuell angezeigte Nachricht verstecken:
+ hideMessage: function() {
+ if(this.message) { // Nur wenn überhaupt eine Nachricht angezeigt wird.
+ var canvas = this.message.canvas; // Das Element, das zur Nachrichten-Zeichenfläche gehört
+ canvas.parentNode.removeChild(canvas); // Element aus dem DOM entfernen
+ delete this.message; // und die Referenz auf die Zeichenfläche löschen
+ }
+ },
+ // Element-Methoden: Ich baue diese Methoden immer ein, damit ich bei meinen Projekten immer eine einheitliche Methode hat, um an das HTML-Element zu gelangen. Oft will man noch etwas daran verändern, bevor es in den Dokumentbaum eingefügt wird. Abgeguckt vom JS-Framework MooTools
+ toElement: function() {
+ return this.el;
+ },
+ // fügt mir das Spiel als Kindknoten von parent in das Dokument ein
+ inject: function(parent) {
+ parent.appendChild(this.el);
+ },
+ dispose: function() {
+ var parent = this.el.parentNode;
+ if(parent) {
+ parent.removeChild(this.el);
+ }
+ }
+ };
+ mixin(View.prototype, Options);
+ mixin(View.prototype, Events);
+ mixin(View.prototype, ClickAreas);
+
+
+ /************
+ * Steuerung *
+ ************/
+
+ // Controller ist die Haupt"klasse" (JS kennt keine Klassen). Diese Klasse erstellt für uns Instanzen von Model und View und vermittelt zwischen diesen mit Events.
+ function Controller(modelOptions, viewOptions, autosolver) { // damit wir eigene Optionen für Model und View festlegen können
+ this.modelOptions = modelOptions || {}; // Entweder das mitgegebene Objekt oder ein leeres Objekt
+ this.viewOptions = viewOptions || {}; // s.o.
+
+ this.createModel(); // Model erstellen
+ this.createView(); // View erstellen
+ if(autosolver === undefined) {
+ autosolver = 'lib/autosolver.js';
+ }
+ this.createAutosolver(autosolver); // erstellt einen sogenannten Worker, dem die Ergebnisse mitgeteilt werden und der automatisch das Spiel lösen kann
+
+ this.newGame(); // ein neues Spiel starten
+ }
+ Controller.prototype = {
+ constructor: Controller, // Referenz von der Instanz zur Konstruktorfunktion
+
+ createModel: function() {
+ this.model = new Model(this.modelOptions); // beim Aufruf einer Funktion mit dem new-Operator wird 1. ein neues Objekt erstellt, das von dem prototype-Member der Funktion erbt 2. Das Schlüsselwort this in der Funktion an das neue Objekt gebunden 3. Die Funktion ausgeführt => neue Instanz von Model
+
+ // Auf ein paar Events reagieren:
+ var _this = this;
+ this.model.addEventListener('row', function(black, white) { // wenn eine Zeile bewertet wurde
+ if(_this.autosolver) { // wenn die Technik für den Autosolver funktioniert
+ _this.autosolver.postMessage(JSON.stringify({
+ command: 'row',
+ arguments: [_this.model.guesses[_this.model.count], [black, white]]
+ })); // teile ihm die Zeile und das Ergebnis mit. JSON.stringify baut mir aus dem Objekt einen String, das Objekt ist eine Art Protokoll, das ich auf die Schnelle erfunden habe für die Kommunikation mit Strings
+ }
+ _this.view.showMatches(black, white); // das Ergebnis anzeigen
+ _this.view.closeSelect(); // möglicherweise offen Farbwahlfenster schließen
+ _this.model.nextRow(); // zur nächsten Zeile gehen
+ _this.view.initRow(); // die aktuelle Zeile im View initialisieren (z.B. Eventlistener hinzufügen, wenn man in diese Zeile klickt, etc.)
+ });
+ this.model.addEventListener('win', function() { // wenn der Benutzer gewonnen hat
+ _this.view.showWonMessage(); // Nachricht anzeigen
+ _this.endGame(); // Spiel beenden
+ });
+ this.model.addEventListener('lose', function() { // wenn der Benutzer verloren hat
+ _this.view.showLostMessage(); // Nachricht anzeigen
+ _this.endGame(); // Spiel beenden
+ });
+ },
+ createView: function() {
+ this.view = new View(this.model, this.viewOptions); // neuer View
+
+ // Auf ein paar Events reagieren:
+ var _this = this;
+ this.view.addEventListener('show', function() { // Der Benutzer will die Lösung sehen
+ if(_this.model.isRowSet()) { // wenn die aktuelle Zeile schon vollständig gesetzt ist …
+ _this.model.checkRow(); // … dann überprüf die noch
+ }
+ _this.view.showGaveUpMessage(); // Nachricht anzeigen, dass der Benutzer aufgegeben hat
+ _this.model.lost = true;
+ _this.endGame(); // Spiel beenden
+ });
+ this.view.addEventListener('restart', function() { // Der Benutzer hat auf den Neustarten-Button geklickt
+ _this.newGame(); // neues Spiel beginnen
+ });
+ this.view.addEventListener('select', function(position, color) { // Der Benutzer hat für ein Feld (position) in der aktuellen Reihe eine Farbe Nummer color gewählt
+ _this.view.setBubble(position, color); // dann mal die Farbe dahin
+ _this.model.setColor(position, color); // im Model die Farbe auch einstellen
+ if(_this.model.isRowSet()) { // wenn nun die gesamte Reihe gesetzt ist …
+ _this.view.showCheckButton(); // … dann biete dem Benutzer an, die Reihe überprüfen zu lassen
+ }
+ });
+ this.view.addEventListener('rowclick', function(position) { // Der Benutzer hat auf ein Feld in der aktuellen Zeile geklickt
+ _this.view.openSelect(position); // Farbwähler öffnen
+ });
+ this.view.addEventListener('check', function() { // der Benutzer will seine gesetzte Zeile überprüfen lassen
+ _this.model.checkRow(); // vom Model überprüfen lassen
+ });
+ },
+ createAutosolver: function(autosolver) {
+ if(!win.Worker || !autosolver) { return; }; // Browser unterstützt noch keine WebWorker
+
+ this.autosolver = new Worker(autosolver); // Neuer Worker: siehe Datei autosover.js
+ this.autosolver.postMessage(JSON.stringify({
+ command: 'init',
+ arguments: [this.model.options.cols, this.model.options.colors]
+ })); // Dem autosolver werden wichtige Einstellungen des Spiels mitgeteilt (Anzahl der Spalten und Farben)
+
+ var _this = this;
+ // Funktionen, die der Webworker aufrufen kann:
+ var commands = {
+ log: function() { // Zum Debugging
+ if(win.console) { // console stellt Funktionen zum Debugging bereit, ist aber nicht in allen Browsern verfügbar
+ console.log.apply(console, arguments); // Alle Parameter, mit denen diese Funktion aufgerufen wurde, in die Debugging-Konsole schreiben
+ }
+ },
+ propose: function(row) { // Worker schlägt eine Kombination vor
+ // Die Kombination in Model und View setzen
+ each(row, function(color, position) {
+ _this.view.setBubble(position, color);
+ _this.model.setColor(position, color);
+ });
+ _this.view.closeSelect(); // evt. offene Farbwahlfenster schließen
+ _this.view.showCheckButton(); // dem Benutzer anbieten, die Reihe überprüfen zu lassen
+ },
+ guess: function() {
+ _this.model.checkRow(); // Reihe überprüfen lassen
+ _this.view.removeFieldClickAreas(); // Der Benutzer darf nichts tun
+ if(!_this.model.won && !_this.model.lost) { // das Spiel ist noch nicht beendet
+ _this.autosolver.postMessage(JSON.stringify({
+ command: 'guess'
+ })); // Der autosolver soll gleich die nächste Reihe vorschlagen
+ }
+ }
+ };
+ this.autosolver.addEventListener('message', function(evt) { // wenn diese Datei vom Worker eine Nachricht bekomment
+ var obj = JSON.parse(evt.data), // evt.data ist der Inhalt der Nachricht, mit JSON.parse mach ich aus dem Nachricht-String wieder ein Objekt
+ command = obj.command, // die Funktion, die hier aufgerufen werden soll
+ args = obj.arguments || []; // die Argumente, mit denen die Funktion aufgerufen werden soll
+ if(commands[command]) { // die Funktion gibt es hier
+ commands[command].apply(commands, args); // aufrufen
+ }
+ }, false);
+ },
+
+ newGame: function() { // ein neues Spiel starten
+ this.model.reset();
+
+ if(this.autosolver) { // Der autosolver existiert
+ this.autosolver.postMessage(JSON.stringify({
+ command: 'reset'
+ })); // Der autosolver kann wieder alle möglichen Kombinationen in Betracht ziehen, da das Spiel neu gestartet wird
+ }
+ this.view.hideMessage(); // evt. angezeigte Nachrichten verstecken
+ this.view.hideSolution(); // Diese Fragezeichen-Kugeln anzeigen
+ this.view.drawLineNumbers(); // Zeilennummern zeichnen
+ this.view.drawHoles(); // die Steckplätze zeichnen
+ this.view.showShowButton(); // der Button zum Zeigen des Ergebnisses
+ this.view.initRow(); // Einrichten, was passiert, wenn man in die aktuelle Zeile klickt
+ },
+ endGame: function() {
+ this.view.showRestartButton(); // Einen Button zum Starten eines neuen Spiels einblenden
+ this.view.showSolution(); // Die Lösung anzeigen
+ this.view.closeSelect(); // evt. offene Farbwahlblasen anzeigen
+ this.view.removeFieldClickAreas(); // Nichts passiert mehr, wenn man in das Spielfeld klickt
+ },
+
+ propose: function() {
+ if(!this.autosolver) { return; }; // Browser unterstützt noch keine WebWorker
+ if(!this.model.won && !this.model.lost) { // Nur wenn das Spiel noch nicht beendet ist
+ this.autosolver.postMessage(JSON.stringify({
+ command: 'propose'
+ })); // Der autosolver soll mir gefälligst eine Kombination vorschlagen, mit der ich viele Möglichkeiten eliminieren kann
+ }
+ },
+ solve: function() {
+ if(!this.autosolver) { return; }; // Browser unterstützt noch keine WebWorker
+ if(!this.model.won && !this.model.lost) { // Spiel ist noch nicht beendet
+ this.view.removeFieldClickAreas(); // Der Benutzer macht ab jetzt nichts mehr!
+ this.autosolver.postMessage(JSON.stringify({
+ command: 'guess'
+ })); // Der autosolver soll mir eine Kombination vorschlagen, dann das "guess"-Event feuern, woraufhin ihm wieder mitgeteilt wird, dass er die nächste Kombination vorschlagen soll und so weiter bis das Spiel gelöst ist
+ }
+ },
+
+ // Element-Methoden weiterleiten
+ toElement: function() {
+ return this.view.toElement();
+ },
+ inject: function(parent) {
+ this.view.inject(parent);
+ },
+ dispose: function() {
+ this.view.dispose();
+ }
+ };
+
+
+ return Controller; // Rückgabewert der anonymen Funktion, macht Controller auch extern verfügbar (heißt im globalen Gültigkeitsbereich aber Meisterhirn, siehe Zeile 1
+})(window, document, Math); // Ende der anonymen Funktion, sofortiger Aufruf
Please sign in to comment.
Something went wrong with that request. Please try again.