├── .gitignore ├── LICENSE.md ├── README.adoc ├── cheatsheet.adoc └── cheatsheet.css /.gitignore: -------------------------------------------------------------------------------- 1 | /cheatsheet.html 2 | /Design patterns.pdf 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Gres (gres@gres.biz) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Short cheatsheet of software design patterns 2 | 3 | Rendered pdf is in github's 'releases' page. 4 | 5 | == Steps to obtain printable format 6 | 7 | - install link:http://asciidoctor.org/[asciidoctor] 8 | - execute ```asciidoctor cheatsheet.adoc``` 9 | - open/print cheatsheet.html 10 | -------------------------------------------------------------------------------- /cheatsheet.adoc: -------------------------------------------------------------------------------- 1 | = Design patterns 2 | :experimental: 3 | :source-highlighter: prettify 4 | :source-language: cpp 5 | :stylesheet: cheatsheet.css 6 | :noheader: 7 | :nofooter: 8 | 9 | :creational-type: creation 10 | :structural-type: structure 11 | :behavioral-type: behavior 12 | :concurrency-type: async 13 | :architectural-type: architecture 14 | 15 | 16 | [cols="6*"] 17 | |=== 18 | 19 | // Creational 20 | 21 | a| 22 | == Abstract factory [pattern-type]#{creational-type}# 23 | 24 | create similar hierarchies 25 | ``` 26 | struct OrcFactory: ArmyFactory { 27 | Fighter* createFighter () override { 28 | return new OrcFighter; 29 | } 30 | Officer* createOfficer () override { 31 | return new OrcOfficer; 32 | } 33 | } 34 | ``` 35 | 36 | a| 37 | == Factory method [pattern-type]#{creational-type}# 38 | 39 | create single object 40 | ``` 41 | struct OrcBlacksmith : Blacksmith { 42 | Weapon* createWeapon () override { 43 | return new OrcWeapon; 44 | } 45 | } 46 | ``` 47 | 48 | a| 49 | == Builder [pattern-type]#{creational-type}# 50 | 51 | create object from parts 52 | ``` 53 | struct OrcBuilder { 54 | void setWeapon (Weapon weapon) { 55 | orcWeapon = weapon; 56 | } 57 | void setArmor (Armor armor) { 58 | orcArmor = armor; 59 | } 60 | Orc build () { 61 | return Orc (orcWeapon, orcArmor); 62 | } 63 | } 64 | ``` 65 | 66 | a| 67 | == Step builder [pattern-type]#{creational-type}# 68 | 69 | wizard-like object creation 70 | ``` 71 | struct OrcBuilder : Armorer, Builder { 72 | Builder* setArmor (Armor armor) override { // Armorer 73 | orcArmor = armor; 74 | return static_cast(this); 75 | } 76 | Orc build () override { // Builder 77 | return Orc (orcWeapon); 78 | } 79 | } 80 | ``` 81 | 82 | a| 83 | == Lazy initialization [pattern-type]#{creational-type}# 84 | 85 | create object only when it is needed 86 | ``` 87 | struct Castle { 88 | Castle () : kitchen (nullptr); 89 | private: 90 | Kitchen& getKitchen () { 91 | if (!kitchen) { 92 | kitchen = createKitchen (); 93 | } 94 | return *kitchen; 95 | } 96 | } 97 | ``` 98 | 99 | a| 100 | == Multiton [pattern-type]#{creational-type}# 101 | 102 | limit objects variety 103 | ``` 104 | struct Kingdom { 105 | static Kingdom& get (Name name) { 106 | static map kingdoms; 107 | return kingdoms[name]; 108 | } 109 | } 110 | ``` 111 | 112 | a| 113 | == Object mother [pattern-type]#{creational-type}# 114 | 115 | create preset objects 116 | ``` 117 | struct OrcObjectMother { 118 | Orc createAngry () { 119 | return Orc (State::Angry); 120 | } 121 | Orc createWounded () { 122 | Orc orc; 123 | orc.setHealth (90); 124 | return orc; 125 | } 126 | } 127 | ``` 128 | 129 | a| 130 | == Object pool [pattern-type]#{creational-type}# 131 | 132 | store and reuse expensive objects 133 | ``` 134 | struct Museum { 135 | Artifact& acquire (); 136 | void release (Artifact& returned); 137 | private: 138 | set all; 139 | set taken; 140 | } 141 | ``` 142 | 143 | a| 144 | == Prototype [pattern-type]#{creational-type}# 145 | 146 | create objects by copying prototype 147 | ``` 148 | struct Monster { 149 | virtual Monster* clone () = 0; 150 | } 151 | struct MonsterFactory { 152 | Monster* create (Type type) { 153 | return prototypes[type]->clone (); 154 | } 155 | private: 156 | map prototypes; 157 | } 158 | ``` 159 | 160 | a| 161 | == Resource acquisition is initialization (RAII) [pattern-type]#{creational-type}# 162 | 163 | make object responsible for its resources 164 | ``` 165 | struct OrcShaman { 166 | OrcShaman () { 167 | ManaSource::addLeacher (this); 168 | } 169 | ~OrcShaman () { 170 | ManaSource::removeLeacher (this); 171 | } 172 | } 173 | ``` 174 | 175 | a| 176 | == Singleton [pattern-type]#{creational-type}# 177 | 178 | allow only one instance 179 | ``` 180 | struct Earth { 181 | static Earth& instance () { 182 | static Earth earth; 183 | return earth; 184 | } 185 | int getRadius () const { 186 | return radius; 187 | } 188 | private: 189 | Earth (); 190 | int radius; 191 | } 192 | ``` 193 | 194 | a| 195 | == MonoState [pattern-type]#{creational-type}# 196 | 197 | many instances with single state 198 | ``` 199 | struct Earth { 200 | Earth (); 201 | int getRadius () const { 202 | return Earth::radius; 203 | } 204 | private: 205 | static int radius; 206 | } 207 | ``` 208 | 209 | 210 | 211 | // Structural 212 | 213 | 214 | a| 215 | == Abstract document [pattern-type]#{structural-type}# 216 | 217 | dynamically manage properties 218 | ``` 219 | struct MonsterDocument { 220 | void set (Type, Value); 221 | Value get (Type); 222 | } 223 | struct Orc : MonsterDocument, Armed { 224 | Weapon weapon () override { // Armed 225 | return Weapon (get (Type::Weapon)); 226 | } 227 | } 228 | ``` 229 | 230 | a| 231 | == Adapter [pattern-type]#{structural-type}# 232 | 233 | adapt foreign api 234 | ``` 235 | struct OrcTypeAdapter : Monster, Orc { 236 | void attack () override { 237 | Orc::smash (); 238 | } 239 | } 240 | struct OrcObjectAdapter : Monster { 241 | void attack () override { 242 | orc.smash (); 243 | } 244 | } 245 | ``` 246 | 247 | a| 248 | == Bridge [pattern-type]#{structural-type}# 249 | 250 | separate interface and implementation changes 251 | ``` 252 | struct Fighter : Soldier { 253 | Fighter (Creature* impl); 254 | void attack () override { 255 | impl->attackImpl (); 256 | } 257 | } 258 | struct Orc : Creature { 259 | void attackImpl () override; 260 | } 261 | ``` 262 | 263 | a| 264 | == Composite [pattern-type]#{structural-type}# 265 | 266 | treat composite object same way as single 267 | ``` 268 | struct Kingdom : Area { 269 | double square () override { 270 | return sum (owned, Area::square()); 271 | } 272 | void addArea (Area*) override; 273 | private: 274 | set owned; 275 | } 276 | ``` 277 | 278 | a| 279 | == Decorator [pattern-type]#{structural-type}# 280 | 281 | dynamically add/remove behavior to object 282 | ``` 283 | struct Walled : public Town { 284 | Walled (Town* decorated); 285 | int strength () override { 286 | return decorated->strength () + 10; 287 | } 288 | } 289 | Town* castle = new Walled (new Town ()); 290 | ``` 291 | 292 | a| 293 | == Event aggregator [pattern-type]#{structural-type}# 294 | 295 | gather all events in one place 296 | ``` 297 | struct Aggregator { 298 | void subscribe (Subscriber*); 299 | void publish (Event event) { 300 | each (subscribers, 301 | Subscriber::handle (event)); 302 | } 303 | } 304 | officer.subscribe (fighter); 305 | officer.publish (AttackEvent ()); 306 | ``` 307 | 308 | a| 309 | == Extension object [pattern-type]#{structural-type}# 310 | 311 | provide additional interface without inherritance 312 | ``` 313 | struct Kingdom { 314 | Kingdom (Capital* capital); 315 | Capital* getCapital () { 316 | return capital; 317 | } 318 | } 319 | ``` 320 | 321 | a| 322 | == Facade [pattern-type]#{structural-type}# 323 | 324 | single interface for several subsystems 325 | ``` 326 | struct Army { 327 | void attack () { 328 | officers->makeOrders (); 329 | fighters->followOrders (); 330 | shamans->prey (); 331 | } 332 | } 333 | ``` 334 | 335 | a| 336 | == Flyweight [pattern-type]#{structural-type}# 337 | 338 | many similar objects with shared state 339 | ``` 340 | struct Forge { 341 | Weapon craft (Type type) { 342 | return Weapon (stats[type]); 343 | } 344 | private: 345 | map stats; 346 | } 347 | ``` 348 | 349 | a| 350 | == Front controller [pattern-type]#{structural-type}# 351 | 352 | handle all requests in one place 353 | ``` 354 | struct Controller { 355 | void handle (Request request) { 356 | getProcessor (request.type) 357 | .process (request); 358 | } 359 | Processor getProcessor (RequestType); 360 | } 361 | ``` 362 | 363 | a| 364 | == Marker [pattern-type]#{structural-type}# 365 | 366 | indicate class behaviour 367 | ``` 368 | struct Orc : Agressive { 369 | } 370 | if (dynamic_cast(monster)) 371 | monster->attack (); 372 | if (dynamic_cast(monster)) 373 | monster->guard (); 374 | ``` 375 | 376 | a| 377 | == Module [pattern-type]#{structural-type}# 378 | 379 | group connected functions 380 | ``` 381 | struct ConsoleModule { 382 | void prepare (); 383 | void unprepare (); 384 | static ConsoleModule& instance (); 385 | void print (Variant); 386 | variant scan (); 387 | } 388 | ``` 389 | 390 | a| 391 | == Mock object [pattern-type]#{structural-type}# 392 | 393 | partially simulate object behaviour for testing 394 | ``` 395 | struct Shaman { 396 | Spell* castSpell () { 397 | openSpellbook (); 398 | Glyph* glyph = findSpell (); 399 | return glyph->cast (); 400 | } 401 | } 402 | struct ShamanMock { 403 | Spell* castSpell () { 404 | return new MightySpell (); 405 | } 406 | } 407 | ``` 408 | 409 | a| 410 | == Proxy [pattern-type]#{structural-type}# 411 | 412 | add behaviour to existing interface 413 | ``` 414 | struct GuardedArmoryProxy : Armory { 415 | GuardedArmory (Armory* armory); 416 | void enter(Orc& orc) override { 417 | if (looksFriendly (orc)) 418 | armory->enter (orc); 419 | else 420 | logFailure (orc); 421 | } 422 | } 423 | ``` 424 | 425 | a| 426 | == Service locator [pattern-type]#{structural-type}# 427 | 428 | ease and cache service discovery 429 | ``` 430 | struct OrcIntelligence { 431 | static Area locate (Army army) { 432 | if (!lastSeen.contains (army)) { 433 | lastSeen[army] = lookFor (army); 434 | } 435 | return lastSeen[army]; 436 | } 437 | private: 438 | map lastSeen; 439 | } 440 | ``` 441 | 442 | 443 | 444 | // Behavioral 445 | 446 | 447 | a| 448 | == Blackboard [pattern-type]#{behavioral-type}# 449 | 450 | integrate many modules in complex strategy 451 | ``` 452 | struct Intelligence { 453 | void updateDisposition () { 454 | // gather knowledge from sources 455 | each (scouts, Source::update(map)); 456 | // process knowledge 457 | correctConflicts (map); 458 | // configure sources 459 | killLiars (scouts); 460 | } 461 | private: 462 | Blackboard map; 463 | set scouts; 464 | } 465 | ``` 466 | 467 | a| 468 | == Chain of responsibility [pattern-type]#{behavioral-type}# 469 | 470 | unknown concrete handler for concrete request 471 | ``` 472 | struct OrcFighter : RequestHandler { 473 | OrcFighter (RequestHandler* next); 474 | void handle(Request req) override { 475 | if (req.type == Type::Attack) { 476 | attack (); 477 | // more logic 478 | if (++req.done > 10) return; 479 | } 480 | if (next) next->handle (req); 481 | } 482 | } 483 | ``` 484 | 485 | a| 486 | == Command [pattern-type]#{behavioral-type}# 487 | 488 | hold all required data to perform/abort event 489 | ``` 490 | struct Move : Command { 491 | Move (Army army, Area from, Area to); 492 | void execute () override { 493 | from.removeArmy (army); 494 | to.addArmy (army); 495 | } 496 | void abort () override { 497 | to.removeArmy (army); 498 | from.addArmy (army); 499 | } 500 | } 501 | ``` 502 | 503 | a| 504 | == Delegation [pattern-type]#{behavioral-type}# 505 | 506 | provide functionality via composition part 507 | ``` 508 | struct OrcFighter { 509 | Size weaponSize () const { 510 | return weapon.size (); 511 | } 512 | } 513 | ``` 514 | 515 | a| 516 | == Dependency injection [pattern-type]#{behavioral-type}# 517 | 518 | use constructed dependency 519 | ``` 520 | struct OrcFighter { 521 | OrcFighter (AbstractArmor* armor); 522 | void hit (Damage damage) { 523 | health -= armor->reduce (damage); 524 | } 525 | } 526 | ``` 527 | 528 | a| 529 | == Feature toggle [pattern-type]#{behavioral-type}# 530 | 531 | dynamically enable/disable code branches 532 | ``` 533 | struct OrcFighter { 534 | void attack () { 535 | if (FeatureToggle::isOn(Stealth)){ 536 | hiddenAttack (); 537 | } 538 | else { 539 | simpleAttack (); 540 | } 541 | } 542 | } 543 | ``` 544 | 545 | a| 546 | == Intercepting filter [pattern-type]#{behavioral-type}# 547 | 548 | add pre/post-processing to requests 549 | ``` 550 | struct FilterManager { 551 | FilterManager (Target* target); 552 | void handle (Request request) { 553 | each (filters, 554 | Filter::handle (request)); 555 | target->deliver (request); 556 | } 557 | private: 558 | list filters; 559 | } 560 | ``` 561 | 562 | a| 563 | == Interpreter [pattern-type]#{behavioral-type}# 564 | 565 | handle AST of domain specific language 566 | ``` 567 | struct Plus : Expression { 568 | Plus (Expression& left, Expression& right); 569 | Value interpret () override { 570 | return left.interpret () 571 | + right.interpret (); 572 | } 573 | } 574 | ``` 575 | 576 | a| 577 | == Iterator [pattern-type]#{behavioral-type}# 578 | 579 | traverse container without knowing its structure 580 | ``` 581 | struct OrcIterator { 582 | OrcIterator& operator++ (); // next 583 | Orc& operator-> (); // value 584 | bool operator!= (const OrcIterator&) const; 585 | } 586 | for (OrcIterator it = army.begin (), 587 | end = army.end (); it != end; ++it) { 588 | it->attack (); 589 | } 590 | ``` 591 | 592 | a| 593 | == Mediator [pattern-type]#{behavioral-type}# 594 | 595 | hide objects interacion details 596 | ``` 597 | struct OrcTrainingCamp { 598 | void train (Orc& old, Orc& young) { 599 | young.raiseSkill (old.skill ()); 600 | } 601 | } 602 | ``` 603 | 604 | a| 605 | == Memento [pattern-type]#{behavioral-type}# 606 | 607 | save/restore object's state 608 | ``` 609 | struct Orc { 610 | Memento state () { 611 | return Memento {this->health}; 612 | } 613 | void restore (Memento memento) { 614 | this->health = memento.health; 615 | } 616 | class Memento { 617 | int health; 618 | friend class Orc; 619 | } 620 | } 621 | ``` 622 | 623 | a| 624 | == Method chaining [pattern-type]#{behavioral-type}# 625 | 626 | multiple method calls in one expression 627 | ``` 628 | struct Orc { 629 | Orc& setName (Name name) { 630 | this->name = name; 631 | return *this; 632 | } 633 | Orc& setWeapon (Weapon); 634 | } 635 | Orc orc = Orc().setName ("Named") 636 | .setWeapon (Sword()); 637 | ``` 638 | 639 | a| 640 | == Null object [pattern-type]#{behavioral-type}# 641 | 642 | specific object for empty (null) behaviour 643 | ``` 644 | struct FakeOrc : Orc { 645 | void attack () override {} 646 | } 647 | Orc* makeNewOrc () { 648 | if (!reachedLimit ()) return new Orc; 649 | return new FakeOrc; 650 | } 651 | ``` 652 | 653 | a| 654 | == Observer [pattern-type]#{behavioral-type}# 655 | 656 | notify subscribers about publisher events 657 | ``` 658 | struct OrcCampObserver : Observer { 659 | void notify (Event& event) override { 660 | each (orcs, Orc::handle (event)); 661 | } 662 | } 663 | struct OrcCamp : Observable { 664 | void addObserver (Observer) override; 665 | void dinnerTime () { 666 | each (observers, 667 | Observer::notify (DinnerEvent())); 668 | } 669 | } 670 | ``` 671 | 672 | a| 673 | == Servant [pattern-type]#{behavioral-type}# 674 | 675 | add behaviour to other classes 676 | ``` 677 | struct Blacksmith { 678 | void sharpenWeapon (Fighter*); 679 | } 680 | ``` 681 | 682 | a| 683 | == Specification [pattern-type]#{behavioral-type}# 684 | 685 | filter of validate objects with dynamic rules 686 | ``` 687 | struct BySkill : Specification { 688 | bool check (Orc& orc) override { 689 | return orc.gotSkill (Sneak); 690 | } 691 | } 692 | void recruit (Orc& orc) { 693 | auto filter = BySkill ().and (ByMana ()); 694 | if (filter.check (orc)) { 695 | assignForImportantMission (orc); 696 | } 697 | } 698 | ``` 699 | 700 | a| 701 | == State [pattern-type]#{behavioral-type}# 702 | 703 | behavior depends on finite internal states 704 | ``` 705 | struct Orc { 706 | void fear () { 707 | setState (new ScaredState(this)); 708 | } 709 | void attack () { 710 | state->attack (); 711 | } 712 | } 713 | struct ScaredState : OrcState { 714 | void attack () override { 715 | owner->flee (); 716 | } 717 | } 718 | ``` 719 | 720 | a| 721 | == Strategy [pattern-type]#{behavioral-type}# 722 | 723 | use group of interchangeable algorithms 724 | ``` 725 | struct Orc { 726 | void attack () {strategy->attack ();} 727 | private: 728 | AttackStrategy* strategy; 729 | } 730 | struct Defensive : AttackStrategy { 731 | void attack () override { 732 | raiseShield (); 733 | swordAttack (); 734 | } 735 | } 736 | ``` 737 | 738 | a| 739 | == Template method [pattern-type]#{behavioral-type}# 740 | 741 | override only part of algorithm 742 | ``` 743 | struct Orc { 744 | virtual Target* chooseTarget (); 745 | virtual hitTarget () = 0; 746 | void stepBack (); 747 | void attack () { 748 | auto target = chooseTarget (); 749 | hitTarget (target); 750 | stepBack (); 751 | } 752 | } 753 | ``` 754 | 755 | a| 756 | == Type tunnel [pattern-type]#{behavioral-type}# 757 | 758 | unified processing of different types 759 | ``` 760 | struct Dragon { 761 | void eatImpl (Food); 762 | Food makeFood (Orc); 763 | Food makeFood (Dwarf); 764 | template 765 | void eat (T t) { 766 | eatImpl (makeFood (t)); 767 | } 768 | } 769 | ``` 770 | 771 | a| 772 | == Visitor [pattern-type]#{behavioral-type}# 773 | 774 | apply operation on object's elements 775 | ``` 776 | struct ArmyMeleePower : Visitor { 777 | void visit (Melee& orc) override { 778 | this->power += orc.power (); 779 | } 780 | void visit (Ranged& orc) override {} 781 | } 782 | struct Melee : Visitable { 783 | void accept (Visitor& visitor) override{ 784 | visitor.visit (*this); 785 | } 786 | } 787 | ``` 788 | 789 | 790 | 791 | // Concurrency 792 | 793 | 794 | a| 795 | == Active object [pattern-type]#{concurrency-type}# 796 | 797 | separate execution and invocation threads 798 | ``` 799 | struct ActiveObject { 800 | void addCommand (Command command) { 801 | this->commands << command; 802 | } 803 | ~ActiveObject () { 804 | thread thread ([this]() { 805 | each (commands, Command::exec()); 806 | } 807 | thread.join (); 808 | } 809 | } 810 | ``` 811 | 812 | a| 813 | == Async method call [pattern-type]#{concurrency-type}# 814 | 815 | non-blocking method call in remote thread 816 | ``` 817 | struct Shaman { 818 | void resurrect (Creature& dead) { 819 | Finder& remote = astral.soul(dead); 820 | if (!remote.isReady ()) drink (); 821 | Soul& soul = astral.takeSoul(remote); // blocks 822 | dead.revive (soul); 823 | } 824 | } 825 | ``` 826 | 827 | a| 828 | == Balking [pattern-type]#{concurrency-type}# 829 | 830 | ignore calls until ready 831 | ``` 832 | struct Barracks { 833 | Fighter* trainRecruit () { 834 | AutoLock lock; 835 | if (!gotRecruits ()) return {}; 836 | return train (takeRecruit ()); 837 | } 838 | void addRecruit (Recruit recruit) { 839 | AutoLock lock; 840 | addRecruit (recruit); 841 | } 842 | } 843 | ``` 844 | 845 | a| 846 | == Binding properties [pattern-type]#{concurrency-type}# 847 | 848 | synchronize several properties 849 | ``` 850 | template struct Property { 851 | void bind (Property* other); 852 | void set (T value) { 853 | preventInfiniteRecursion (); 854 | other->set (value); 855 | } 856 | } 857 | house.isWarm.bind (&heater.isOn); 858 | ``` 859 | 860 | a| 861 | == Blockchain [pattern-type]#{concurrency-type}# 862 | 863 | ordered appendable chain of verified transactions 864 | ``` 865 | struct OrcHistorian : BlockchainNode { 866 | bool addLegend (Legend legend) { 867 | if (!verify (legend)) return false; 868 | bool accepted = all (others, &OrcHistorian::addLegend (legend)) 869 | if (accepted) writeLegend (legend); 870 | return accepted; 871 | } 872 | private: 873 | list others; 874 | } 875 | ``` 876 | 877 | a| 878 | == Double-checked locking [pattern-type]#{concurrency-type}# 879 | 880 | reduce locking overhead for conditional 881 | ``` 882 | struct Tavern { 883 | bool close () { 884 | if (state != Empty) return false; 885 | // be sure in interested case 886 | AutoLock lock; 887 | if (state == Empty) state = Closed; 888 | } 889 | } 890 | ``` 891 | 892 | a| 893 | == Guarded suspension [pattern-type]#{concurrency-type}# 894 | 895 | block call until ready 896 | ``` 897 | struct Barracks { 898 | Fighter* trainRecruit () { 899 | while (true) { 900 | if (AutoLock lock, gotRecruits()) 901 | return train (takeRecruit ()); 902 | wait (); 903 | } 904 | } 905 | void addRecruit (Recruit recruit) { 906 | AutoLock lock; 907 | addRecruit (recruit); 908 | } 909 | } 910 | ``` 911 | 912 | a| 913 | == Join [pattern-type]#{concurrency-type}# 914 | 915 | pipleine of sync/async messaging channels 916 | ``` 917 | struct Channel { 918 | void put (Message* message); 919 | Message* get (); 920 | } 921 | struct Forge : Pipe { 922 | void craft (Message* iron, Message* crafter); 923 | } 924 | Tavern ().when (minesChannel).and (craftersChannel).do (Forge::craft); 925 | ``` 926 | 927 | a| 928 | == Lock (Mutex) [pattern-type]#{concurrency-type}# 929 | 930 | block if resource is busy 931 | ``` 932 | struct Tavern { 933 | void enter () { 934 | lock.acquire (); // blocks if busy 935 | ++customers; 936 | lock.release (); 937 | } 938 | void leave () { 939 | lock.acquire (); // blocks if busy 940 | --customers; 941 | lock.release (); 942 | } 943 | } 944 | ``` 945 | 946 | a| 947 | == Monitor object [pattern-type]#{concurrency-type}# 948 | 949 | allow conditional access to guarded resourse 950 | ``` 951 | struct Tavern { 952 | void enter () { 953 | lock.acquire (); 954 | while (isFull ()) { 955 | monitor.wait (lock, queue1); // release on sleep, acquire on wake 956 | } 957 | ++customers; 958 | lock.release (); 959 | } 960 | void leave () { 961 | AutoLock lock(this->lock) 962 | --customers; 963 | monitor.wakeOne (queue1); 964 | } 965 | } 966 | ``` 967 | 968 | a| 969 | == Proactor [pattern-type]#{concurrency-type}# 970 | 971 | gather async requests and send to async handlers 972 | ``` 973 | struct Forge { 974 | void exec () { 975 | each (mines, Mine::startDig (), static_cast (Forge::craft)); 976 | } 977 | void craft (Iron iron) { 978 | nextCrafter ()->asyncCraft (iron, static_cast (::deliver)); 979 | } 980 | } 981 | ``` 982 | 983 | a| 984 | == Reactor [pattern-type]#{concurrency-type}# 985 | 986 | gather async requests and send to sync handlers 987 | ``` 988 | struct Forge { 989 | void exec () { 990 | while (true) { 991 | for (Iron& i: getAllReadyIron()){ 992 | craft (i); 993 | } 994 | waitForMoreIronReady (timeout); 995 | } 996 | } 997 | void craft (Iron iron) { 998 | ::deliver (nextCrafter ()->craft (iron)); 999 | } 1000 | } 1001 | ``` 1002 | 1003 | a| 1004 | == Read-write lock [pattern-type]#{concurrency-type}# 1005 | 1006 | allow concurrent reads, but exclusive writes 1007 | ``` 1008 | struct Tavern { 1009 | list customers () const { 1010 | rwLock.readAcquire (); // allow many 1011 | auto result = customers; 1012 | rwLock.readRelease (); 1013 | return result; 1014 | } 1015 | void addCustomer (Customer customer) { 1016 | rwLock.writeAcquire (); // allow one 1017 | customers << customer; 1018 | rwLock.writeRelease (); 1019 | } 1020 | } 1021 | ``` 1022 | 1023 | a| 1024 | == Scheduler [pattern-type]#{concurrency-type}# 1025 | 1026 | control resource usage time 1027 | ``` 1028 | struct Forge : Scheduler { 1029 | void requestAnvil (Crafter user) { 1030 | plan.add (user); 1031 | } 1032 | void exec () { 1033 | while (true) { 1034 | Crafter& current = anvil.user(); 1035 | if (!current.isFinished ()) { 1036 | current.pause (); 1037 | plan.add (current); 1038 | } 1039 | Crafter& next = plan.takeNext (); 1040 | anvil.setUser (next); 1041 | waitForNextEvent (plan); 1042 | } 1043 | } 1044 | } 1045 | ``` 1046 | 1047 | a| 1048 | == Thread pool [pattern-type]#{concurrency-type}# 1049 | 1050 | execute task in idle thread from pool 1051 | ``` 1052 | using Staff = Thread; 1053 | struct Tavern { 1054 | void addVisitor (Visitor visitor) { 1055 | queue << new ServeEvent (visitor); 1056 | if (gotIdle ()) processQueue(); 1057 | } 1058 | void processQueue () { 1059 | while (Staff* staff = nextIdle()) { 1060 | if (Event* e = queue.takeNext ()) 1061 | staff.run (e); 1062 | else break; 1063 | } 1064 | } 1065 | } 1066 | ``` 1067 | 1068 | 1069 | a| 1070 | == Active record [pattern-type]#{architectural-type}# 1071 | 1072 | manupilate single row in database 1073 | ``` 1074 | struct Orc { 1075 | void save () { 1076 | run ("insert into orcs values(?,?)", id, name); 1077 | } 1078 | void remove () { 1079 | run ("delete from orc where id = ?", id); 1080 | } 1081 | static Orc* find (Name name); 1082 | } 1083 | ``` 1084 | 1085 | | 1086 | | 1087 | | 1088 | | 1089 | 1090 | |=== 1091 | -------------------------------------------------------------------------------- /cheatsheet.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v2.1.2 | MIT License | git.io/normalize */ 2 | /* ========================================================================== HTML5 display definitions ========================================================================== */ 3 | /** Correct `block` display not defined in IE 8/9. */ 4 | article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { display: block; } 5 | 6 | /** Correct `inline-block` display not defined in IE 8/9. */ 7 | audio, canvas, video { display: inline-block; } 8 | 9 | /** Prevent modern browsers from displaying `audio` without controls. Remove excess height in iOS 5 devices. */ 10 | audio:not([controls]) { display: none; height: 0; } 11 | 12 | /** Address `[hidden]` styling not present in IE 8/9. Hide the `template` element in IE, Safari, and Firefox < 22. */ 13 | [hidden], template { display: none; } 14 | 15 | script { display: none !important; } 16 | 17 | /* ========================================================================== Base ========================================================================== */ 18 | /** 1. Set default font family to sans-serif. 2. Prevent iOS text size adjust after orientation change, without disabling user zoom. */ 19 | html { font-family: sans-serif; /* 1 */ -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ } 20 | 21 | /** Remove default margin. */ 22 | body { margin: 0; } 23 | 24 | /* ========================================================================== Links ========================================================================== */ 25 | /** Remove the gray background color from active links in IE 10. */ 26 | a { background: transparent; } 27 | 28 | /** Address `outline` inconsistency between Chrome and other browsers. */ 29 | a:focus { outline: thin dotted; } 30 | 31 | /** Improve readability when focused and also mouse hovered in all browsers. */ 32 | a:active, a:hover { outline: 0; } 33 | 34 | /* ========================================================================== Typography ========================================================================== */ 35 | /** Address variable `h1` font-size and margin within `section` and `article` contexts in Firefox 4+, Safari 5, and Chrome. */ 36 | h1 { font-size: 2em; margin: 0.67em 0; } 37 | 38 | /** Address styling not present in IE 8/9, Safari 5, and Chrome. */ 39 | abbr[title] { border-bottom: 1px dotted; } 40 | 41 | /** Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. */ 42 | b, strong { font-weight: bold; } 43 | 44 | /** Address styling not present in Safari 5 and Chrome. */ 45 | dfn { font-style: italic; } 46 | 47 | /** Address differences between Firefox and other browsers. */ 48 | hr { -moz-box-sizing: content-box; box-sizing: content-box; height: 0; } 49 | 50 | /** Address styling not present in IE 8/9. */ 51 | mark { background: #ff0; color: #000; } 52 | 53 | /** Correct font family set oddly in Safari 5 and Chrome. */ 54 | code, kbd, pre, samp { font-family: monospace, serif; font-size: 1em; } 55 | 56 | /** Improve readability of pre-formatted text in all browsers. */ 57 | pre { white-space: pre-wrap; } 58 | 59 | /** Set consistent quote types. */ 60 | q { quotes: "\201C" "\201D" "\2018" "\2019"; } 61 | 62 | /** Address inconsistent and variable font size in all browsers. */ 63 | small { font-size: 80%; } 64 | 65 | /** Prevent `sub` and `sup` affecting `line-height` in all browsers. */ 66 | sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } 67 | 68 | sup { top: -0.5em; } 69 | 70 | sub { bottom: -0.25em; } 71 | 72 | /* ========================================================================== Embedded content ========================================================================== */ 73 | /** Remove border when inside `a` element in IE 8/9. */ 74 | img { border: 0; } 75 | 76 | /** Correct overflow displayed oddly in IE 9. */ 77 | svg:not(:root) { overflow: hidden; } 78 | 79 | /* ========================================================================== Figures ========================================================================== */ 80 | /** Address margin not present in IE 8/9 and Safari 5. */ 81 | figure { margin: 0; } 82 | 83 | /* ========================================================================== Forms ========================================================================== */ 84 | /** Define consistent border, margin, and padding. */ 85 | fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; } 86 | 87 | /** 1. Correct `color` not being inherited in IE 8/9. 2. Remove padding so people aren't caught out if they zero out fieldsets. */ 88 | legend { border: 0; /* 1 */ padding: 0; /* 2 */ } 89 | 90 | /** 1. Correct font family not being inherited in all browsers. 2. Correct font size not being inherited in all browsers. 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. */ 91 | button, input, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 2 */ margin: 0; /* 3 */ } 92 | 93 | /** Address Firefox 4+ setting `line-height` on `input` using `!important` in the UA stylesheet. */ 94 | button, input { line-height: normal; } 95 | 96 | /** Address inconsistent `text-transform` inheritance for `button` and `select`. All other form control elements do not inherit `text-transform` values. Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. Correct `select` style inheritance in Firefox 4+ and Opera. */ 97 | button, select { text-transform: none; } 98 | 99 | /** 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 2. Correct inability to style clickable `input` types in iOS. 3. Improve usability and consistency of cursor style between image-type `input` and others. */ 100 | button, html input[type="button"], input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ } 101 | 102 | /** Re-set default cursor for disabled elements. */ 103 | button[disabled], html input[disabled] { cursor: default; } 104 | 105 | /** 1. Address box sizing set to `content-box` in IE 8/9. 2. Remove excess padding in IE 8/9. */ 106 | input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } 107 | 108 | /** 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome (include `-moz` to future-proof). */ 109 | input[type="search"] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; } 110 | 111 | /** Remove inner padding and search cancel button in Safari 5 and Chrome on OS X. */ 112 | input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } 113 | 114 | /** Remove inner padding and border in Firefox 4+. */ 115 | button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } 116 | 117 | /** 1. Remove default vertical scrollbar in IE 8/9. 2. Improve readability and alignment in all browsers. */ 118 | textarea { overflow: auto; /* 1 */ vertical-align: top; /* 2 */ } 119 | 120 | /* ========================================================================== Tables ========================================================================== */ 121 | /** Remove most spacing between table cells. */ 122 | table { border-collapse: collapse; border-spacing: 0; } 123 | 124 | meta.foundation-mq-small { font-family: "only screen and (min-width: 768px)"; width: 768px; } 125 | 126 | meta.foundation-mq-medium { font-family: "only screen and (min-width:1280px)"; width: 1280px; } 127 | 128 | meta.foundation-mq-large { font-family: "only screen and (min-width:1440px)"; width: 1440px; } 129 | 130 | *, *:before, *:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } 131 | 132 | html, body { font-size: 100%; font-size: 8px; } 133 | 134 | body { background: white; color: #222222; padding: 0; margin: 0; font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; font-weight: normal; font-style: normal; line-height: 1; position: relative; cursor: auto; } 135 | 136 | a:hover { cursor: pointer; } 137 | 138 | img, object, embed { max-width: 100%; height: auto; } 139 | 140 | object, embed { height: 100%; } 141 | 142 | img { -ms-interpolation-mode: bicubic; } 143 | 144 | #map_canvas img, #map_canvas embed, #map_canvas object, .map_canvas img, .map_canvas embed, .map_canvas object { max-width: none !important; } 145 | 146 | .left { float: left !important; } 147 | 148 | .right { float: right !important; } 149 | 150 | .text-left { text-align: left !important; } 151 | 152 | .text-right { text-align: right !important; } 153 | 154 | .text-center { text-align: center !important; } 155 | 156 | .text-justify { text-align: justify !important; } 157 | 158 | .hide { display: none; } 159 | 160 | .antialiased { -webkit-font-smoothing: antialiased; } 161 | 162 | img { display: inline-block; vertical-align: middle; } 163 | 164 | textarea { height: auto; min-height: 50px; } 165 | 166 | select { width: 100%; } 167 | 168 | object, svg { display: inline-block; vertical-align: middle; } 169 | 170 | .center { margin-left: auto; margin-right: auto; } 171 | 172 | .spread { width: 100%; } 173 | 174 | p.lead, .paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { font-size: 1.21875em; line-height: 1.6; } 175 | 176 | .subheader, .admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { line-height: 1.4; /*color: #6c818f;*/ font-weight: bold; margin-top: 0.2em; margin-bottom: 0.5em; font-size: 1.2em; } 177 | 178 | /* Typography resets */ 179 | div, dl, dt, dd, ul, ol, li, h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6, pre, form, p, blockquote, th, td { margin: 0; padding: 0; direction: ltr; } 180 | 181 | /* Default Link Styles */ 182 | a { color: #444444; text-decoration: underline; line-height: inherit; } 183 | a:hover, a:focus { color: #111111; } 184 | a img { border: none; } 185 | 186 | /* Default paragraph styles */ 187 | p { font-family: inherit; font-weight: normal; font-size: 1em; line-height: 1.5; text-rendering: optimizeLegibility; } 188 | p aside { font-size: 0.875em; line-height: 1.35; font-style: italic; } 189 | 190 | /* Default header styles */ 191 | h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, "Helvetica Neue", sans-serif; font-weight: bold; font-style: normal; color: #465158; text-rendering: optimizeLegibility; line-height: 1.2125em; } 192 | h1 small, h2 small, h3 small, #toctitle small, .sidebarblock > .content > .title small, h4 small, h5 small, h6 small { font-size: 60%; color: #909ea7; line-height: 0; } 193 | 194 | h1 { font-size: 2.125em; } 195 | 196 | h2 { font-size: 1.6875em; } 197 | 198 | h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.375em; } 199 | 200 | h4 { font-size: 1.125em; } 201 | 202 | h5 { font-size: 1.125em; } 203 | 204 | h6 { font-size: 1em; } 205 | 206 | hr { border: solid #dddddd; border-width: 1px 0 0; clear: both; margin: 1.25em 0 1.1875em; height: 0; } 207 | 208 | /* Helpful Typography Defaults */ 209 | em, i { font-style: italic; line-height: inherit; } 210 | 211 | strong, b { font-weight: bold; line-height: inherit; } 212 | 213 | small { font-size: 60%; line-height: inherit; } 214 | 215 | code { font-family: "Consolas", "Deja Vu Sans Mono", "Bitstream Vera Sans Mono", monospace; font-weight: normal; color: #444444; } 216 | 217 | /* Lists */ 218 | ul, ol, dl { font-size: 1em; line-height: 1.5; margin-bottom: 1.25em; list-style-position: outside; font-family: inherit; } 219 | 220 | ul, ol { margin-left: 0; } 221 | ul.no-bullet, ol.no-bullet { margin-left: 0; } 222 | 223 | /* Unordered Lists */ 224 | ul li ul, ul li ol { margin-left: 1.25em; margin-bottom: 0; font-size: 1em; /* Override nested font-size change */ } 225 | ul.square li ul, ul.circle li ul, ul.disc li ul { list-style: inherit; } 226 | ul.square { list-style-type: square; } 227 | ul.circle { list-style-type: circle; } 228 | ul.disc { list-style-type: disc; } 229 | ul.no-bullet { list-style: none; } 230 | 231 | /* Ordered Lists */ 232 | ol li ul, ol li ol { margin-left: 1.25em; margin-bottom: 0; } 233 | 234 | /* Definition Lists */ 235 | dl dt { margin-bottom: 0.3em; font-weight: bold; } 236 | dl dd { margin-bottom: 0.75em; } 237 | 238 | /* Abbreviations */ 239 | abbr, acronym { text-transform: uppercase; font-size: 90%; color: black; border-bottom: 1px dotted #dddddd; cursor: help; } 240 | 241 | abbr { text-transform: none; } 242 | 243 | /* Blockquotes */ 244 | blockquote { margin: 0 0 1.25em; padding: 0.5625em 1.25em 0 1.1875em; border-left: 1px solid #dddddd; } 245 | blockquote cite { display: block; font-size: 0.8125em; color: #748590; } 246 | blockquote cite:before { content: "\2014 \0020"; } 247 | blockquote cite a, blockquote cite a:visited { color: #748590; } 248 | 249 | blockquote, blockquote p { line-height: 1.5; color: #909ea7; } 250 | 251 | /* Microformats */ 252 | .vcard { display: inline-block; margin: 0 0 1.25em 0; border: 1px solid #dddddd; padding: 0.625em 0.75em; } 253 | .vcard li { margin: 0; display: block; } 254 | .vcard .fn { font-weight: bold; font-size: 0.9375em; } 255 | 256 | .vevent .summary { font-weight: bold; } 257 | .vevent abbr { cursor: auto; text-decoration: none; font-weight: bold; border: none; padding: 0 0.0625em; } 258 | 259 | @media only screen and (min-width: 768px) { h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { line-height: 1.4; } 260 | h1 { font-size: 2.75em; } 261 | h2 { font-size: 1.6875em; } 262 | h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.6875em; } 263 | h4 { font-size: 1.4375em; } } 264 | /* Tables */ 265 | table { background: white; margin-bottom: 0em; border: solid 0 #dddddd; } 266 | table thead, table tfoot { background: none; font-weight: bold; } 267 | table thead tr th, table thead tr td, table tfoot tr th, table tfoot tr td { padding: 1px 8px 1px 5px; font-size: 1em; color: #222222; text-align: left; } 268 | table tr th, table tr td { padding: 1px 1px 1px 1px; font-size: 1em; color: #222222; } 269 | table tr.even, table tr.alt, table tr:nth-of-type(even) { background: none; } 270 | table thead tr th, table tfoot tr th, table tbody tr td, table tr td, table tfoot tr td { display: table-cell; line-height: 1.5; } 271 | 272 | body { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; tab-size: 4; } 273 | 274 | h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { line-height: 1.4; } 275 | 276 | .clearfix:before, .clearfix:after, .float-group:before, .float-group:after { content: " "; display: table; } 277 | .clearfix:after, .float-group:after { clear: both; } 278 | 279 | *:not(pre) > code { font-size: 0.95em; font-style: normal !important; letter-spacing: 0; padding: 0; background-color: #f2f2f2; -webkit-border-radius: 6px; border-radius: 6px; line-height: inherit; word-wrap: break-word; } 280 | *:not(pre) > code.nobreak { word-wrap: normal; } 281 | *:not(pre) > code.nowrap { white-space: nowrap; } 282 | 283 | pre, pre > code { line-height: 1.2; color: inherit; font-family: "Consolas", "Deja Vu Sans Mono", "Bitstream Vera Sans Mono", monospace; font-weight: normal; } 284 | 285 | em em { font-style: normal; } 286 | 287 | strong strong { font-weight: normal; } 288 | 289 | .keyseq { color: #333333; } 290 | 291 | kbd { font-family: "Consolas", "Deja Vu Sans Mono", "Bitstream Vera Sans Mono", monospace; display: inline-block; color: black; font-size: 0.65em; line-height: 1.45; background-color: #f7f7f7; border: 1px solid #ccc; -webkit-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; margin: 0 0.15em; padding: 0.2em 0.5em; vertical-align: middle; position: relative; top: -0.1em; white-space: nowrap; } 292 | 293 | .keyseq kbd:first-child { margin-left: 0; } 294 | 295 | .keyseq kbd:last-child { margin-right: 0; } 296 | 297 | .menuseq, .menu { color: black; } 298 | 299 | b.button:before, b.button:after { position: relative; top: -1px; font-weight: normal; } 300 | 301 | b.button:before { content: "["; padding: 0 3px 0 2px; } 302 | 303 | b.button:after { content: "]"; padding: 0 2px 0 3px; } 304 | 305 | p a > code:hover { color: #373737; } 306 | 307 | #header, #content, #footnotes, #footer { width: 100%; margin-left: 0; margin-right: 0; margin-top: 0; margin-bottom: 0; *zoom: 1; position: relative; padding-left: 0.9375em; padding-right: 0.9375em; } 308 | #header:before, #header:after, #content:before, #content:after, #footnotes:before, #footnotes:after, #footer:before, #footer:after { content: " "; display: table; } 309 | #header:after, #content:after, #footnotes:after, #footer:after { clear: both; } 310 | 311 | #content { margin-top: 1.25em; } 312 | 313 | #content:before { content: none; } 314 | 315 | #header > h1:first-child { color: #111111; margin-top: 2.25rem; margin-bottom: 0; } 316 | #header > h1:first-child + #toc { margin-top: 8px; border-top: 1px solid #dddddd; } 317 | #header > h1:only-child, body.toc2 #header > h1:nth-last-child(2) { border-bottom: 1px solid #dddddd; padding-bottom: 8px; } 318 | #header .details { border-bottom: 1px solid #dddddd; line-height: 1.45; padding-top: 0.25em; padding-bottom: 0.25em; padding-left: 0.25em; color: #748590; display: -ms-flexbox; display: -webkit-flex; display: flex; -ms-flex-flow: row wrap; -webkit-flex-flow: row wrap; flex-flow: row wrap; } 319 | #header .details span:first-child { margin-left: -0.125em; } 320 | #header .details span.email a { color: #909ea7; } 321 | #header .details br { display: none; } 322 | #header .details br + span:before { content: "\00a0\2013\00a0"; } 323 | #header .details br + span.author:before { content: "\00a0\22c5\00a0"; color: #909ea7; } 324 | #header .details br + span#revremark:before { content: "\00a0|\00a0"; } 325 | #header #revnumber { text-transform: capitalize; } 326 | #header #revnumber:after { content: "\00a0"; } 327 | 328 | #content > h1:first-child:not([class]) { color: #111111; border-bottom: 1px solid #dddddd; padding-bottom: 8px; margin-top: 0; padding-top: 1rem; margin-bottom: 1.25rem; } 329 | 330 | #toc { border-bottom: 1px solid #dddddd; padding-bottom: 0.5em; } 331 | #toc > ul { margin-left: 0.125em; } 332 | #toc ul.sectlevel0 > li > a { font-style: italic; } 333 | #toc ul.sectlevel0 ul.sectlevel1 { margin: 0.5em 0; } 334 | #toc ul { font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, "Helvetica Neue", sans-serif; list-style-type: none; } 335 | #toc li { line-height: 1.3334; margin-top: 0.3334em; } 336 | #toc a { text-decoration: none; } 337 | #toc a:active { text-decoration: underline; } 338 | 339 | #toctitle { color: #6c818f; font-size: 1.2em; } 340 | 341 | @media only screen and (min-width: 768px) { #toctitle { font-size: 1.375em; } 342 | body.toc2 { padding-left: 15em; padding-right: 0; } 343 | #toc.toc2 { margin-top: 0 !important; background-color: #f2f2f2; position: fixed; width: 15em; left: 0; top: 0; border-right: 1px solid #dddddd; border-top-width: 0 !important; border-bottom-width: 0 !important; z-index: 1000; padding: 1.25em 1em; height: 100%; overflow: auto; } 344 | #toc.toc2 #toctitle { margin-top: 0; margin-bottom: 0.8rem; font-size: 1.2em; } 345 | #toc.toc2 > ul { font-size: 0.9em; margin-bottom: 0; } 346 | #toc.toc2 ul ul { margin-left: 0; padding-left: 1em; } 347 | #toc.toc2 ul.sectlevel0 ul.sectlevel1 { padding-left: 0; margin-top: 0.5em; margin-bottom: 0.5em; } 348 | body.toc2.toc-right { padding-left: 0; padding-right: 15em; } 349 | body.toc2.toc-right #toc.toc2 { border-right-width: 0; border-left: 1px solid #dddddd; left: auto; right: 0; } } 350 | @media only screen and (min-width: 1280px) { body.toc2 { padding-left: 20em; padding-right: 0; } 351 | #toc.toc2 { width: 20em; } 352 | #toc.toc2 #toctitle { font-size: 1.375em; } 353 | #toc.toc2 > ul { font-size: 0.95em; } 354 | #toc.toc2 ul ul { padding-left: 1.25em; } 355 | body.toc2.toc-right { padding-left: 0; padding-right: 20em; } } 356 | #content #toc { border-style: solid; border-width: 1px; border-color: #d9d9d9; margin-bottom: 1.25em; padding: 1.25em; background: #f2f2f2; -webkit-border-radius: 6px; border-radius: 6px; } 357 | #content #toc > :first-child { margin-top: 0; } 358 | #content #toc > :last-child { margin-bottom: 0; } 359 | 360 | #footer { max-width: 100%; background-color: black; padding: 1.25em; } 361 | 362 | #footer-text { color: white; line-height: 1.35; } 363 | 364 | 365 | .sect1 + .sect1 { border-top: 1px solid #dddddd; } 366 | 367 | #content h1 > a.anchor, h2 > a.anchor, h3 > a.anchor, #toctitle > a.anchor, .sidebarblock > .content > .title > a.anchor, h4 > a.anchor, h5 > a.anchor, h6 > a.anchor { position: absolute; z-index: 1001; width: 1.5ex; margin-left: -1.5ex; display: block; text-decoration: none !important; visibility: hidden; text-align: center; font-weight: normal; } 368 | #content h1 > a.anchor:before, h2 > a.anchor:before, h3 > a.anchor:before, #toctitle > a.anchor:before, .sidebarblock > .content > .title > a.anchor:before, h4 > a.anchor:before, h5 > a.anchor:before, h6 > a.anchor:before { content: "\00A7"; font-size: 0.85em; display: block; padding-top: 0.1em; } 369 | #content h1:hover > a.anchor, #content h1 > a.anchor:hover, h2:hover > a.anchor, h2 > a.anchor:hover, h3:hover > a.anchor, #toctitle:hover > a.anchor, .sidebarblock > .content > .title:hover > a.anchor, h3 > a.anchor:hover, #toctitle > a.anchor:hover, .sidebarblock > .content > .title > a.anchor:hover, h4:hover > a.anchor, h4 > a.anchor:hover, h5:hover > a.anchor, h5 > a.anchor:hover, h6:hover > a.anchor, h6 > a.anchor:hover { visibility: visible; } 370 | #content h1 > a.link, h2 > a.link, h3 > a.link, #toctitle > a.link, .sidebarblock > .content > .title > a.link, h4 > a.link, h5 > a.link, h6 > a.link { color: #465158; text-decoration: none; } 371 | #content h1 > a.link:hover, h2 > a.link:hover, h3 > a.link:hover, #toctitle > a.link:hover, .sidebarblock > .content > .title > a.link:hover, h4 > a.link:hover, h5 > a.link:hover, h6 > a.link:hover { color: #3b444a; } 372 | 373 | .audioblock, .imageblock, .literalblock, .listingblock, .stemblock, .videoblock { margin-bottom: 1.25em; } 374 | 375 | .admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { text-rendering: optimizeLegibility; text-align: center; } 376 | 377 | table.tableblock > caption.title { white-space: nowrap; overflow: visible; max-width: 0; } 378 | 379 | .paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { color: #111111; } 380 | 381 | table.tableblock #preamble > .sectionbody > .paragraph:first-of-type p { font-size: inherit; } 382 | 383 | .admonitionblock > table { border-collapse: separate; border: 0; background: none; width: 100%; } 384 | .admonitionblock > table td.icon { text-align: center; width: 80px; } 385 | .admonitionblock > table td.icon img { max-width: initial; } 386 | .admonitionblock > table td.icon .title { font-weight: bold; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, "Helvetica Neue", sans-serif; text-transform: uppercase; } 387 | .admonitionblock > table td.content { padding-left: 1.125em; padding-right: 1.25em; border-left: 1px solid #dddddd; color: #748590; } 388 | .admonitionblock > table td.content > :last-child > :last-child { margin-bottom: 0; } 389 | 390 | .exampleblock > .content { border-style: solid; border-width: 1px; border-color: #e6e6e6; margin-bottom: 1.25em; padding: 1.25em; background: white; -webkit-border-radius: 6px; border-radius: 6px; } 391 | .exampleblock > .content > :first-child { margin-top: 0; } 392 | .exampleblock > .content > :last-child { margin-bottom: 0; } 393 | 394 | .sidebarblock { border-style: solid; border-width: 1px; border-color: #d9d9d9; margin-bottom: 1.25em; padding: 1.25em; background: #f2f2f2; -webkit-border-radius: 6px; border-radius: 6px; } 395 | .sidebarblock > :first-child { margin-top: 0; } 396 | .sidebarblock > :last-child { margin-bottom: 0; } 397 | .sidebarblock > .content > .title { color: #6c818f; margin-top: 0; } 398 | 399 | .exampleblock > .content > :last-child > :last-child, .exampleblock > .content .olist > ol > li:last-child > :last-child, .exampleblock > .content .ulist > ul > li:last-child > :last-child, .exampleblock > .content .qlist > ol > li:last-child > :last-child, .sidebarblock > .content > :last-child > :last-child, .sidebarblock > .content .olist > ol > li:last-child > :last-child, .sidebarblock > .content .ulist > ul > li:last-child > :last-child, .sidebarblock > .content .qlist > ol > li:last-child > :last-child { margin-bottom: 0; } 400 | 401 | .literalblock pre, .listingblock pre:not(.highlight), .listingblock pre[class="highlight"], .listingblock pre[class^="highlight "], .listingblock pre.CodeRay, .listingblock pre.prettyprint { background: #eeeeee; } 402 | .sidebarblock .literalblock pre, .sidebarblock .listingblock pre:not(.highlight), .sidebarblock .listingblock pre[class="highlight"], .sidebarblock .listingblock pre[class^="highlight "], .sidebarblock .listingblock pre.CodeRay, .sidebarblock .listingblock pre.prettyprint { background: #f2f1f1; } 403 | 404 | .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { border: 1px solid #cccccc; -webkit-border-radius: 6px; border-radius: 6px; word-wrap: break-word; padding: 0.5em; font-size: 0.8125em; } 405 | .literalblock pre.nowrap, .literalblock pre[class].nowrap, .listingblock pre.nowrap, .listingblock pre[class].nowrap { overflow-x: auto; white-space: pre; word-wrap: normal; } 406 | @media only screen and (min-width: 768px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 0.90625em; } } 407 | @media only screen and (min-width: 1280px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 1em; } } 408 | 409 | .literalblock.output pre { color: #eeeeee; background-color: inherit; } 410 | 411 | .listingblock pre.highlightjs { padding: 0; } 412 | .listingblock pre.highlightjs > code { padding: 0.5em; -webkit-border-radius: 6px; border-radius: 6px; } 413 | 414 | .listingblock > .content { position: relative; } 415 | 416 | .listingblock code[data-lang]:before { display: none; content: attr(data-lang); position: absolute; font-size: 0.75em; top: 0.425rem; right: 0.5rem; line-height: 1; text-transform: uppercase; color: #999; } 417 | 418 | .listingblock:hover code[data-lang]:before { display: block; } 419 | 420 | .listingblock.terminal pre .command:before { content: attr(data-prompt); padding-right: 0.5em; color: #999; } 421 | 422 | .listingblock.terminal pre .command:not([data-prompt]):before { content: "$"; } 423 | 424 | table.pyhltable { border-collapse: separate; border: 0; margin-bottom: 0; background: none; } 425 | 426 | table.pyhltable td { vertical-align: top; padding-top: 0; padding-bottom: 0; line-height: 1.2; } 427 | 428 | table.pyhltable td.code { padding-left: .75em; padding-right: 0; } 429 | 430 | pre.pygments .lineno, table.pyhltable td:not(.code) { color: #999; padding-left: 0; padding-right: .5em; border-right: 1px solid #dddddd; } 431 | 432 | pre.pygments .lineno { display: inline-block; margin-right: .25em; } 433 | 434 | table.pyhltable .linenodiv { background: none !important; padding-right: 0 !important; } 435 | 436 | .quoteblock { margin: 0 1em 1.25em 1.5em; display: table; } 437 | .quoteblock > .title { margin-left: -1.5em; margin-bottom: 0.75em; } 438 | .quoteblock blockquote, .quoteblock blockquote p { color: #909ea7; font-size: 1.15rem; line-height: 1.75; word-spacing: 0.1em; letter-spacing: 0; font-style: italic; text-align: justify; } 439 | .quoteblock blockquote { margin: 0; padding: 0; border: 0; } 440 | .quoteblock blockquote:before { content: "\201c"; float: left; font-size: 2.75em; font-weight: bold; line-height: 0.6em; margin-left: -0.6em; color: #6c818f; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } 441 | .quoteblock blockquote > .paragraph:last-child p { margin-bottom: 0; } 442 | .quoteblock .attribution { margin-top: 0.5em; margin-right: 0.5ex; text-align: right; } 443 | .quoteblock .quoteblock { margin-left: 0; margin-right: 0; padding: 0.5em 0; border-left: 3px solid #748590; } 444 | .quoteblock .quoteblock blockquote { padding: 0 0 0 0.75em; } 445 | .quoteblock .quoteblock blockquote:before { display: none; } 446 | 447 | .verseblock { margin: 0 1em 1.25em 1em; } 448 | .verseblock pre { font-family: "Open Sans", "DejaVu Sans", sans; font-size: 1.15rem; color: #909ea7; font-weight: 300; text-rendering: optimizeLegibility; } 449 | .verseblock pre strong { font-weight: 400; } 450 | .verseblock .attribution { margin-top: 1.25rem; margin-left: 0.5ex; } 451 | 452 | .quoteblock .attribution, .verseblock .attribution { font-size: 0.8125em; line-height: 1.45; font-style: italic; } 453 | .quoteblock .attribution br, .verseblock .attribution br { display: none; } 454 | .quoteblock .attribution cite, .verseblock .attribution cite { display: block; letter-spacing: -0.025em; color: #748590; } 455 | 456 | .quoteblock.abstract { margin: 0 0 1.25em 0; display: block; } 457 | .quoteblock.abstract blockquote, .quoteblock.abstract blockquote p { text-align: left; word-spacing: 0; } 458 | .quoteblock.abstract blockquote:before, .quoteblock.abstract blockquote p:first-of-type:before { display: none; } 459 | 460 | table.tableblock { max-width: 100%; border-collapse: separate; } 461 | table.tableblock td > .paragraph:last-child p > p:last-child, table.tableblock th > p:last-child, table.tableblock td > p:last-child { margin-bottom: 0; } 462 | 463 | table.tableblock, th.tableblock, td.tableblock { border: 0 solid #dddddd; } 464 | 465 | table.grid-all th.tableblock, table.grid-all td.tableblock { border-width: 0 0 0 0; } 466 | 467 | table.grid-all tfoot > tr > th.tableblock, table.grid-all tfoot > tr > td.tableblock { border-width: 0 0 0 0; } 468 | 469 | table.grid-cols th.tableblock, table.grid-cols td.tableblock { border-width: 0 0 0 0; } 470 | 471 | table.grid-all * > tr > .tableblock:last-child, table.grid-cols * > tr > .tableblock:last-child { border-right-width: 0; } 472 | 473 | table.grid-rows th.tableblock, table.grid-rows td.tableblock { border-width: 0 0 0 0; } 474 | 475 | table.grid-all tbody > tr:last-child > th.tableblock, table.grid-all tbody > tr:last-child > td.tableblock, table.grid-all thead:last-child > tr > th.tableblock, table.grid-rows tbody > tr:last-child > th.tableblock, table.grid-rows tbody > tr:last-child > td.tableblock, table.grid-rows thead:last-child > tr > th.tableblock { border-bottom-width: 0; } 476 | 477 | table.grid-rows tfoot > tr > th.tableblock, table.grid-rows tfoot > tr > td.tableblock { border-width: 0 0 0 0; } 478 | 479 | table.frame-all { border-width: 0; } 480 | 481 | table.frame-sides { border-width: 0 0; } 482 | 483 | table.frame-topbot { border-width: 0 0; } 484 | 485 | th.halign-left, td.halign-left { text-align: left; } 486 | 487 | th.halign-right, td.halign-right { text-align: right; } 488 | 489 | th.halign-center, td.halign-center { text-align: center; } 490 | 491 | th.valign-top, td.valign-top { vertical-align: top; } 492 | 493 | th.valign-bottom, td.valign-bottom { vertical-align: bottom; } 494 | 495 | th.valign-middle, td.valign-middle { vertical-align: middle; } 496 | 497 | table thead th, table tfoot th { font-weight: bold; } 498 | 499 | tbody tr th { display: table-cell; line-height: 1.5; background: none; } 500 | 501 | tbody tr th, tbody tr th p, tfoot tr th, tfoot tr th p { color: #222222; font-weight: bold; } 502 | 503 | p.tableblock > code:only-child { background: none; padding: 0; } 504 | 505 | p.tableblock { font-size: 1em; } 506 | 507 | td > div.verse { white-space: pre; } 508 | 509 | ol { margin-left: 0.25em; } 510 | 511 | ul li ol { margin-left: 0; } 512 | 513 | dl dd { margin-left: 1.125em; } 514 | 515 | dl dd:last-child, dl dd:last-child > :last-child { margin-bottom: 0; } 516 | 517 | ol > li p, ul > li p, ul dd, ol dd, .olist .olist, .ulist .ulist, .ulist .olist, .olist .ulist { margin-bottom: 0.625em; } 518 | 519 | ul.unstyled, ol.unnumbered, ul.checklist, ul.none { list-style-type: none; } 520 | 521 | ul.unstyled, ol.unnumbered, ul.checklist { margin-left: 0.625em; } 522 | 523 | ul.checklist li > p:first-child > .fa-square-o:first-child, ul.checklist li > p:first-child > .fa-check-square-o:first-child { width: 1em; font-size: 0.85em; } 524 | 525 | ul.checklist li > p:first-child > input[type="checkbox"]:first-child { width: 1em; position: relative; top: 1px; } 526 | 527 | ul.inline { margin: 0 auto 0.625em auto; margin-left: -1.375em; margin-right: 0; padding: 0; list-style: none; overflow: hidden; } 528 | ul.inline > li { list-style: none; float: left; margin-left: 1.375em; display: block; } 529 | ul.inline > li > * { display: block; } 530 | 531 | .unstyled dl dt { font-weight: normal; font-style: normal; } 532 | 533 | ol.arabic { list-style-type: decimal; } 534 | 535 | ol.decimal { list-style-type: decimal-leading-zero; } 536 | 537 | ol.loweralpha { list-style-type: lower-alpha; } 538 | 539 | ol.upperalpha { list-style-type: upper-alpha; } 540 | 541 | ol.lowerroman { list-style-type: lower-roman; } 542 | 543 | ol.upperroman { list-style-type: upper-roman; } 544 | 545 | ol.lowergreek { list-style-type: lower-greek; } 546 | 547 | .hdlist > table, .colist > table { border: 0; background: none; } 548 | .hdlist > table > tbody > tr, .colist > table > tbody > tr { background: none; } 549 | 550 | td.hdlist1, td.hdlist2 { vertical-align: top; padding: 0 0.625em; } 551 | 552 | td.hdlist1 { font-weight: bold; padding-bottom: 1.25em; } 553 | 554 | .literalblock + .colist, .listingblock + .colist { margin-top: -0.5em; } 555 | 556 | .colist > table tr > td:first-of-type { padding: 0 0.75em; line-height: 1; } 557 | .colist > table tr > td:first-of-type img { max-width: initial; } 558 | .colist > table tr > td:last-of-type { padding: 0.25em 0; } 559 | 560 | .thumb, .th { line-height: 0; display: inline-block; border: solid 4px white; -webkit-box-shadow: 0 0 0 1px #dddddd; box-shadow: 0 0 0 1px #dddddd; } 561 | 562 | .imageblock.left, .imageblock[style*="float: left"] { margin: 0.25em 0.625em 1.25em 0; } 563 | .imageblock.right, .imageblock[style*="float: right"] { margin: 0.25em 0 1.25em 0.625em; } 564 | .imageblock > .title { margin-bottom: 0; } 565 | .imageblock.thumb, .imageblock.th { border-width: 6px; } 566 | .imageblock.thumb > .title, .imageblock.th > .title { padding: 0 0.125em; } 567 | 568 | .image.left, .image.right { margin-top: 0.25em; margin-bottom: 0.25em; display: inline-block; line-height: 0; } 569 | .image.left { margin-right: 0.625em; } 570 | .image.right { margin-left: 0.625em; } 571 | 572 | a.image { text-decoration: none; display: inline-block; } 573 | a.image object { pointer-events: none; } 574 | 575 | sup.footnote, sup.footnoteref { font-size: 0.875em; position: static; vertical-align: super; } 576 | sup.footnote a, sup.footnoteref a { text-decoration: none; } 577 | sup.footnote a:active, sup.footnoteref a:active { text-decoration: underline; } 578 | 579 | #footnotes { padding-top: 0.75em; padding-bottom: 0.75em; margin-bottom: 0.625em; } 580 | #footnotes hr { width: 20%; min-width: 6.25em; margin: -0.25em 0 0.75em 0; border-width: 1px 0 0 0; } 581 | #footnotes .footnote { padding: 0 0.375em 0 0.225em; line-height: 1.3334; font-size: 0.875em; margin-left: 1.2em; text-indent: -1.05em; margin-bottom: 0.2em; } 582 | #footnotes .footnote a:first-of-type { font-weight: bold; text-decoration: none; } 583 | #footnotes .footnote:last-of-type { margin-bottom: 0; } 584 | #content #footnotes { margin-top: -0.625em; margin-bottom: 0; padding: 0.75em 0; } 585 | 586 | .gist .file-data > table { border: 0; background: #fff; width: 100%; margin-bottom: 0; } 587 | .gist .file-data > table td.line-data { width: 99%; } 588 | 589 | div.unbreakable { page-break-inside: avoid; } 590 | 591 | .big { font-size: larger; } 592 | 593 | .small { font-size: smaller; } 594 | 595 | .underline { text-decoration: underline; } 596 | 597 | .overline { text-decoration: overline; } 598 | 599 | .line-through { text-decoration: line-through; } 600 | 601 | .aqua { color: #00bfbf; } 602 | 603 | .aqua-background { background-color: #00fafa; } 604 | 605 | .black { color: black; } 606 | 607 | .black-background { background-color: black; } 608 | 609 | .blue { color: #0000bf; } 610 | 611 | .blue-background { background-color: #0000fa; } 612 | 613 | .fuchsia { color: #bf00bf; } 614 | 615 | .fuchsia-background { background-color: #fa00fa; } 616 | 617 | .gray { color: #606060; } 618 | 619 | .gray-background { background-color: #7d7d7d; } 620 | 621 | .green { color: #006000; } 622 | 623 | .green-background { background-color: #007d00; } 624 | 625 | .lime { color: #00bf00; } 626 | 627 | .lime-background { background-color: #00fa00; } 628 | 629 | .maroon { color: #600000; } 630 | 631 | .maroon-background { background-color: #7d0000; } 632 | 633 | .navy { color: #000060; } 634 | 635 | .navy-background { background-color: #00007d; } 636 | 637 | .olive { color: #606000; } 638 | 639 | .olive-background { background-color: #7d7d00; } 640 | 641 | .purple { color: #600060; } 642 | 643 | .purple-background { background-color: #7d007d; } 644 | 645 | .red { color: #bf0000; } 646 | 647 | .red-background { background-color: #fa0000; } 648 | 649 | .silver { color: #909090; } 650 | 651 | .silver-background { background-color: #bcbcbc; } 652 | 653 | .teal { color: #006060; } 654 | 655 | .teal-background { background-color: #007d7d; } 656 | 657 | .white { color: #bfbfbf; } 658 | 659 | .white-background { background-color: #fafafa; } 660 | 661 | .yellow { color: #bfbf00; } 662 | 663 | .yellow-background { background-color: #fafa00; } 664 | 665 | span.icon > .fa { cursor: default; } 666 | 667 | .admonitionblock td.icon [class^="fa icon-"] { font-size: 2.5em; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); cursor: default; } 668 | .admonitionblock td.icon .icon-note:before { content: "\f05a"; color: #333333; } 669 | .admonitionblock td.icon .icon-tip:before { content: "\f0eb"; text-shadow: 1px 1px 2px rgba(155, 155, 0, 0.8); color: #111; } 670 | .admonitionblock td.icon .icon-warning:before { content: "\f071"; color: #bf6900; } 671 | .admonitionblock td.icon .icon-caution:before { content: "\f06d"; color: #bf3400; } 672 | .admonitionblock td.icon .icon-important:before { content: "\f06a"; color: #bf0000; } 673 | 674 | .conum[data-value] { display: inline-block; color: #fff !important; background-color: black; -webkit-border-radius: 100px; border-radius: 100px; text-align: center; font-size: 0.75em; width: 1.67em; height: 1.67em; line-height: 1.67em; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-style: normal; font-weight: bold; } 675 | .conum[data-value] * { color: #fff !important; } 676 | .conum[data-value] + b { display: none; } 677 | .conum[data-value]:after { content: attr(data-value); } 678 | pre .conum[data-value] { position: relative; top: -0.125em; } 679 | 680 | b.conum * { color: inherit !important; } 681 | 682 | .conum:not([data-value]):empty { display: none; } 683 | 684 | h4 { color: #6c818f; } 685 | 686 | .literalblock > .content > pre, .listingblock > .content > pre { -webkit-border-radius: 6px; border-radius: 6px; margin-left: 0em; margin-right: 0.5em; } 687 | 688 | .admonitionblock { margin-left: 2em; margin-right: 2em; } 689 | .admonitionblock > table { border: 1px solid #609060; border-top-width: 1.5em; background-color: #e9ffe9; border-collapse: separate; -webkit-border-radius: 0; border-radius: 0; } 690 | .admonitionblock > table td.icon { padding-top: .5em; padding-bottom: .5em; } 691 | .admonitionblock > table td.content { padding: .5em 1em; color: black; font-size: .9em; border-left: none; } 692 | 693 | .sidebarblock { background-color: #e8ecef; border-color: #ccc; } 694 | .sidebarblock > .content > .title { color: #444444; } 695 | 696 | table.tableblock.grid-all { border-collapse: collapse; -webkit-border-radius: 0; border-radius: 0; } 697 | table.tableblock.grid-all th.tableblock, table.tableblock.grid-all td.tableblock { border-bottom: 0px solid #aaa; } 698 | 699 | #footer { background-color: #465158; padding: 2em; } 700 | 701 | #footer-text { color: #eee; font-size: 0.8em; text-align: center; } 702 | 703 | span.pattern-type { font-size: 0.55em; } 704 | --------------------------------------------------------------------------------