diff --git a/site/404.html b/site/404.html new file mode 100644 index 0000000000..0ab7657457 --- /dev/null +++ b/site/404.html @@ -0,0 +1,646 @@ + + + + + + + + + + + + + + + + My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/site/Credits/index.html b/site/Credits/index.html new file mode 100644 index 0000000000..96bc12abe2 --- /dev/null +++ b/site/Credits/index.html @@ -0,0 +1,2235 @@ + + + + + + + + + + + + + + + + Icon Credits - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + +
+
+ + + + +

Icon Credits

+

Flag Icons made by Freepik from www.flaticon.com + and licensed by Creative Commons 3.0

+

New Unciv logo made by u-ndefined on Discord

+

Base tile icons for the "Fantasy Hex" tileset belong to CuddlyClover @ https://cuddlyclover.itch.io/fantasy-hex-tiles with a few additions by me

+

Trees for the jungle tiles in the "Fantasy Hex" are extracted from Desert Strike for the Amiga

+

Almost all the improvements and units made by The Bucketeer on Discord

+

Tile icons for the "ThorfMaps tileset belong to Thorfinn Tait and are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Based on work at www.thorfmaps.com.

+

Unless otherwise specified, all the following are from the Noun Project licenced under either Creative Commons or Public Domain

+

Stat icons

+
    +
  • Gear by Alex Bickov for Production
  • +
  • Apple by Pedro Gonçalves for Food
  • +
  • gold by Eliricon for Gold
  • +
  • Beaker by Delwar Hossain for Science
  • +
  • Music by Naomi Atkinson for Culture
  • +
  • Smiley by Alexander Skowalsky for Happiness
  • +
  • Dove by Sandra for Faith
  • +
  • User by Stéphanie Rusch for Population
  • +
  • Unhappy By Daryl Vandermont for Malcontent
  • +
+

Units

+

Ancient Era

+
    +
  • Hammer By Hea Poh Lin for Worker
  • +
  • Flag By Melvin Poppelaars for Settler
  • +
  • Eagle By anggun for Scout
  • +
  • Axe By ehab.abdullah for Warrior
  • +
  • Haka By Josh for Maori Warrior
  • +
  • Spiked Club by Hamish
  • +
  • Bow And Arrow By Viktor Ostrovsky for Archer
  • +
  • Bow By Arthur Shlain for Bowman
  • +
  • Javelin By WEBTECHOPS LLP for Atlatlist
  • +
  • arrows by Ayub Irawan for Skirmisher
  • +
  • Fishing Vessel By Luis Prado for Work Boats
  • +
  • Greek Trireme By Zachary McCune for Trireme
  • +
  • Greek Trireme By Zachary McCune for Quinquereme. The original work has been modified.
  • +
  • dragon by BGBOXXX Design for Dromon
  • +
  • Viking Boat by Eucalyp for Galley
  • +
  • Chariot By Andrew Doane for Chariot Archer
  • +
  • Elephant By Luis Prado for War Elephant
  • +
  • Centaur by Michael Wohlwend for Horse Archer
  • +
  • Spear By Stephen Copinger for Spearman
  • +
  • Greek shield for Hoplite
  • +
  • ram by Becris for Battering Ram
  • +
  • Spear by lastspark for Marauder
  • +
  • Spiked club for Brute
  • +
  • Hoplite by Eucalyp for Immortal
  • +
  • Slingshot by James Keuning for Slinger
  • +
  • warrior By DinosoftLab for Pictish Warrior (combined with Shamrock, see Promotions)
  • +
+

Classical Era

+
    +
  • Catapult By Jakub Ukrop
  • +
  • Unloaded Crossbow By Hamish as Ballista
  • +
  • Bow and arrow By Lars Meiertoberens for Composite Bowman
  • +
  • Sword By Guilherme Furtado for Swordsman
  • +
  • Mohawk By Dairy Free Design for Mohawk Warrior
  • +
  • Roman Helmet By parkjisun for Legion
  • +
  • Horse By AFY Studio for Horseman
  • +
  • Horse Head By Juan Pablo Bravo for Companion Cavalry
  • +
  • Elephant By Angriawan Ditya Zulkarnain for African Forest Elephant. The original work has been modified.
  • +
  • Horse By Ranah Pixel Studio for Cataphract
  • +
+

Medieval Era

+
    +
  • Ship By Vanisha for Galleass
  • +
  • Crossbow By Creaticca Creative Agency for Crossbowman
  • +
  • Longbow By Hamish for Longbowman
  • +
  • Trebuchet By Ben Davis
  • +
  • Sword By uzeir syarief for Longswordsman
  • +
  • Samurai By Chanut is Industries
  • +
  • Spear By Alvaro Cabrera for Pikeman
  • +
  • Halberd parkjisun for Landsknecht
  • +
  • Knight By Tyler Glaude
  • +
+

Renaissance Era

+ +

Industrial Era

+
    +
  • Rifle By Chameleon Design for Rifleman
  • +
  • Bayonet By food lover for Carolean
  • +
  • soldier by ProSymbols for Mehal Sefari
  • +
  • Horse By Bakunetso Kaito for Cavalry
  • +
  • horse racing By Sergio Morozov for Cossack
  • +
  • Marching Band by Darrin Loeliger, US for Hussar. The original work has been modified.
  • +
  • Artillery By Creative Mania
  • +
  • Ship By Aisyah for Ironclad
  • +
+

Modern Era

+
    +
  • Submarine By Hea Poh Lin, MY
  • +
  • Helmet By Daniel Turner for Great War Infantry
  • +
  • Cap By Creative Mania for Foreign Legion
  • +
  • xm8 By Xela Ub for Infantry
  • +
  • Icon for Carrier made by JackRainy, based on Aircraft Carrier By IcoLabs, BR
  • +
  • Battleship By Vitaliy Gorbachev, KZ for Battleship
  • +
  • machine-gun By Joana Pereira for Machine Gun
  • +
  • artillery by Izwar Muis for Anti-Aircraft Gun
  • +
  • Tank By corpus delicti for Landship
  • +
  • Warship By zidney for Destroyer
  • +
+

Atomic Era

+ +

Information Era

+
    +
  • Submarine by Freepik adapted for Nuclear Submarine
  • +
  • APC By Luke Anthony Firth for Mechanized Infantry
  • +
  • Battleship by Edi Prastyo for Missile Cruiser
  • +
  • Modern Armor By Public Domain Nouns for Modern Armor
  • +
  • Nuclear Missile By Lluisa Iborra, ES
  • +
  • Robot by Lluisa Iborra, ES for Giant Death Robot
  • +
  • Missile By ProSymbols for SS Booster
  • +
  • Rocket By BomSymbols for SS Cockpit
  • +
  • Engine By Andre for SS Engine
  • +
  • Chamber By IYIKON for SS Stasis Chamber
  • +
+

All Eras

+
    +
  • Pallet By James Keuning for Great Artist
  • +
  • Gear By Melvin Salas for Great Engineer
  • +
  • Beaker By Delwar Hossain for Great Scientist
  • +
  • Dove by sandra for Great Prophet
  • +
  • General By anbileru adaleru for Great General
  • +
  • Religion by Bruno Gätjens González adapted for Missionary
  • +
  • invisibility cloak by Locad for Inquisitor
  • +
+

Resources

+
    +
  • Saffron By parkjisun for Dye
  • +
  • Can By Nick Bluth for Aluminum
  • +
  • Coal By Michael Wohlwend
  • +
  • Anvil By Jason Dilworth for Iron
  • +
  • Deer By Richard Nixon
  • +
  • Banana By Adrian Coquet
  • +
  • Oil By Tiago Maricate (also as Civilopedia category icon)
  • +
  • Statue By Joris Hoogendoorn for Marble
  • +
  • Ribbon By Anton for Silk
  • +
  • Stone By AFY Studio
  • +
  • Goblet By Pedro Santos for Silver
  • +
  • Sugar By ahmad
  • +
  • Spice By ahmad
  • +
  • Radiation symbol By icon 54 for Uranium
  • +
  • Wine By Adrien Coquet
  • +
  • Wheat By Juraj Sedlak
  • +
  • Sheep By Unrecognized
  • +
  • Elephant By Kelsey Armstrong for Ivory
  • +
  • Cattle By Daniela Baptista
  • +
  • Leather By Alen Krummenacher for Furs
  • +
  • Gem By Lluisa Iborra
  • +
  • Joss Stick By Hea Poh Lin for Incense
  • +
  • Pottery By Laymik, UA for Porcelain
  • +
  • Jewelry By Shocho, IN
  • +
  • Lemons By sachin modgekar, IN for Citrus
  • +
  • Pipes By Nibras@design for Copper
  • +
  • Crab By YuguDesign
  • +
  • Truffle By parkjisun
  • +
  • Salt By HAMEL KHALED, DZ
  • +
+

Improvements

+ +

Buildings

+

Ancient Era

+ +

Classical Era

+ +

Medieval Era

+ +

Renaissance Era

+ +

Industrial Era

+ +

Modern Era

+ +

Atomic Era

+ +

Information Era

+ +

All Era's

+ +

Social Policies

+

Tradition

+
    +
  • coat of arms By Martina Krasnayova for Oligarchy
  • +
  • Apple By EnQiu for Landed Elite
  • +
  • Crown By Alexander Skowalsky for Monarchy
  • +
  • Pyramid By Creative Stall for Aristocracy
  • +
  • Gavel By Rflor for Legalism
  • +
+

Liberty

+
    +
  • People By Elizabeth Lopez for Citizenship
  • +
  • Assembly By Noël Rasendrason for Republic
  • +
  • People By Gregor Cresnar for Meritocracy
  • +
  • People By Wilson Joseph for Representation
  • +
  • Torch By Hea Poh Lin for Collective Rule
  • +
+

Honor

+
    +
  • Sword By dsathiyaraj for Military Tradition
  • +
  • Castle By Gabriele Malaspina for Military Caste
  • +
  • Roman Armor By Parkjisun for Professional Army
  • +
  • Shield By Kimmi Studio for Discipline
  • +
  • Spartan Helmet By Joni Ramadhan for Warrior Code
  • +
+

Piety

+
    +
  • Protestantism By Evgeni Moryakov for Reformation
  • +
  • Temple By N.K.Narasimhan for Theocracy
  • +
  • Religion By Ben Avery for Free Religion
  • +
  • Flame By Ian Shoobridge for Mandate Of Heaven
  • +
+

Patronage

+
    +
  • Adapted from Gold by Aneeque Ahmed for Philantropy
  • +
  • Ornament by Tommy Suhartomo for Aesthetics
  • +
  • Book Gift by Wolf Böse for Scholasticism
  • +
  • agreement by RomanP for Cultural Diplomacy
  • +
  • professor by Andrew Doane for Educated Elite
  • +
+

Commerce

+
    +
  • Trade By Gregor Cresnar for Trade Unions
  • +
  • Pie Chart By Adrien Coquet for Protectionism
  • +
  • Coins By icon 54 for Mercantilism
  • +
  • Sextant By lastspark for Naval Tradition
  • +
  • captain by taamir468 + and Wheel by Andrejs Kirma for Merchant Navy
  • +
+

Rationalism

+
    +
  • Science By Three Six Five for Scientific Revolution
  • +
  • Graph By Ben Davis for Secularism
  • +
  • Logic By Jenya K for Sovereignty
  • +
  • Dialogue By ProSymbols for Free Thought
  • +
  • Logic By Arthur Shlain for Humanism
  • +
+

Freedom

+ +

Autocracy

+ +

Order

+
    +
  • Adapted from Plan by Cattaleeya Thongsriphong for Planned Economy
  • +
  • Flag by Muhammad Tajudin for Nationalism
  • +
  • Communism By Valerio Poltrini for Socialism
  • +
  • Hammer and Sickle by Dmitry Baranovskiy for Communism
  • +
  • United by Izwar Muis for United Front
  • +
+

Technologies

+

Ancient

+
    +
  • Agriculture By OCHA Visual Information Unit
  • +
  • Jug By Vladimir Belochkin for Pottery
  • +
  • Archery By icon 54
  • +
  • Mining By art shop
  • +
  • Sailing By Daniela Baptista
  • +
  • Sundial By Bonegolem for Calendar
  • +
  • Cuneiform By Michael Wohlwend for Writing
  • +
  • Trap By Sergey Demushkin for Trapping
  • +
  • innovative By Matt Brooks for The Wheel
  • +
  • Bricks By Vaibhav Radhakrishnan for Construction
  • +
  • Mallet By Ben Avery for Bronze Working
  • +
+

Classical

+ +

Medieval

+ +

Renaissance

+ +

Industrial

+ +

Modern

+
    +
  • Gears By Aiden Icons for Replaceable Parts
  • +
  • Radio By Arthur Shlain
  • +
  • Piston By Proletkult Graphik for Combustion
  • +
  • Plastic By Yu luck
  • +
  • Microphone By Viktor Vorobyev for Mass Media
  • +
  • Flight By Genius Icons
  • +
  • Train By Federico Panzano for Railroad
  • +
  • Fridge By b farias for Refrigeration
  • +
  • telegraph by Luke Anthony Firth for Telegraph*
  • +
+

Atomic

+ +

Information

+ +

Future

+ +

Terrain

+ +

Nations

+ +

Promotions

+ +

Religions

+
    +
  • Lightning Bolt by sian huxtable for Pantheon
  • +
  • Christianity by Public Domain Nouns for Christianity
  • +
  • Islam by Muhammed Riza for Islam
  • +
  • taoism by parkjisun for Taosim
  • +
  • Buddhism by Julio Yanes for Buddhism
  • +
  • Hinduism by Mugda Damle for Hinduism
  • +
  • Confucianism by Dabid J. Pascual for Confucianism
  • +
  • Judaism by Dabid J. Pascual for Judaism
  • +
  • Shinto by Dabid J. Pascual for Shinto
  • +
  • Sikhism by Dabid J. Pascual for Sikhism
  • +
  • Tengrism by Dabid J. Pascual for Tengriism
  • +
  • Zoroastrianism by Dabid J. Pascual for Zoroastrianism
  • +
  • praying by parkjisun for Religion (Civilopedia concept entry)
  • +
  • praying by Gan Khoon Lay for Follower
  • +
  • Hero by Andrew J. Young for Founder
  • +
  • yell by Adrien Coquet for Enhancer
  • +
+

Others

+
    +
  • Circle By Aybige
  • +
  • Arrow By Joe Mortell for movement
  • +
  • Swap By iconomania for swapping units
  • +
  • Connection By Travis Avery
  • +
  • Skull By Vladimir Belochkin for disbanding units
  • +
  • Crosshair By Bakunetsu Kaito for selecting enemies to attack
  • +
  • City By Felix Westphal
  • +
  • Fire By Lloyd Humphreys for "city being razed" icon
  • +
  • Sleep By Saeful Muslim
  • +
  • Banner By Emir Palavan for embarked units
  • +
  • Arrow By uzeir syarief for moving between idle units
  • +
  • Replace By Mike Rowe for switching tiles between cities
  • +
  • Resistance By HeadsOfBirds
  • +
  • Viking Hat By my name is mud for pillaging improvements
  • +
  • Aim By Kaviashri for ranged strength
  • +
  • Capitol By Loren Klein for City-States
  • +
  • Aircraft By Tom Fricker for aircraft icon in city button
  • +
  • radar scan By icon 54 for Range
  • +
  • short range radar by Vectors Point for Intercept range
  • +
  • Puppet By Ben Davis for puppeted cities
  • +
  • City By Muhajir ila Robbi in the Icon center
  • +
  • Lock by Vadim Solomakhin for locked tiles
  • +
  • Hourglass by I Create Stuff for the 'Turn' icon
  • +
  • Shield by Gregor Cresnar for Religious Strength
  • +
  • skill sword flame by Maxicons) for Remove Heresy
  • +
  • Pencil by Muhamad Aldi Maulana for Enter Text Prompt Button / Pencil
  • +
  • Parchment by hans draiman for Cultured City-States
  • +
  • connection by Popular for Mercantile City-States
  • +
  • crossed sword by ProSymbols for Militaristic City-States
  • +
  • ship helm by Vectors Market for Maritime City-States
  • +
  • Magnifying Glass by John Caserta for Mod filter
  • +
  • tick by Adrien Coquet on Nation picker
  • +
  • people by Wilson Joseph as base for Civilopedia category Nations
  • +
  • Mountains by Andrew J. Young as base for Civilopedia category Terrains
  • +
  • File:Maya.svg for Mayan numerals
  • +
  • East side of stela C, Quirigua for Mayan calendar symbols
  • +
  • Footprints by Abdul Wahhab for movement overlay toggle, slightly modified. Currently unused.
  • +
  • Arrows.svg by Intralexical (@will-ca), CC0.
  • +
+ + +

Sound credits

+

Sounds are from FreeSound.org unless otherwise noted and are either Creative Commons or Public Domain unless otherwise noted

+ +

Music

+

The following music is from https://filmmusic.io +"Thatched Villagers" by Kevin MacLeod (https://incompetech.com)

+ + +
+
+
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/site/Game Making Tips/index.html b/site/Game Making Tips/index.html new file mode 100644 index 0000000000..9ba6c76002 --- /dev/null +++ b/site/Game Making Tips/index.html @@ -0,0 +1,965 @@ + + + + + + + + + + + + + + + + Tips and tricks for making a LibGDX game - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + +
+
+ + + + +

Tips and tricks for making a LibGDX game

+

Here are a bunch of things I've learned from by brief excursion into the world of game making.

+

Some of our will be obvious to you, some will not.

+

Use Kotlin

+

Unciv started its life as a Unity project in C#, was shifted to Java and LibGDX, and finally to Kotlin.

+

I regret every minute that I spent writing events in Java, this is probably the most significant change that your application could see.

+

Use Scene2d

+

Unless you plan on creating images on the fly, you'll probably be using prerendered assets.

+

Placing them manually is akin to manually positioning html tags, instead of using html heirarchy and css to guide positions.

+

So too is Scene2d - as a placement framework. it's relatively simple to understand, especially when you...

+

Ignore Horizontal and Vertical groups - use Table

+

I personally found that table has all the functionality of the above, and more.

+

Each class has a different syntax too, so I found it much simpler to just stick with Table for everything.

+

Table does just about EVERYTHING! It's insanely amazing!

+

If your game is getting slow, use the Android profiler in Android Studio

+

The top-down CPU chart is the best code profiler I've ever seen, use it to your advantage!

+

Cache everything

+

Caching is a trade-off between purer, state-agnostic code and higher performance. +Coming from a PC background, I automatically assume that anything less than O(n^2) is less than a milisecond and therefore, not a cachinhg candidate. +This is not so in mobile development.

+

This becomes especially relevant when you need to save and load game data which has lots of connected parts - you have to avoid circular references, and you want to minimise the save size, but you need to reconstruct the missing links when loading.

+

Minimize String operations

+

All the tip and tricks you've heard to minimize String operations? Use them!

+

String constants should be consts, use StringBuilders (or just ArrayLists of strings that you later .joinToString())

+

Sequences everywhere!

+

One thing I did not expect to be such an issue is intermediate lists when sorting and mapping.

+

But apparently, the memory allocation for these tasks is Serious Business.

+

So whenever possible, take your list and .asSequence() it before actiating list operations - this results in huge savings of both time and memory!

+

The only time you shouldn't be doing this, though, is when you want to cache the specific values for future use - + sequences will go through the whole process every time you iterate on them, so just .toList() them when you've gotten the final results!

+

General tips for making an Open Source game

+

Lower the entry bar - for both programmers and players

+

I think that most Open Source games suffer from this problem - those that are in are way in, but those that are out and want to join have to learn the ecosystem.

+

Documentation is a big issue here, but so are detailed instructions - and I mean "Spoonfeeding".

+

Treat new developers as if they've never used Git before - it's possible they haven't!

+

Explain how to dowload the sourecode, the tools, how to get the game running locally, how to make changes and how to submit them.

+

Same think with new players - getting the game up and running should be AS SIMPLE AS HUMANLY POSSIBLE - you want people to play your game, don't you?

+

This includes:

+
    +
  • Source-To-Executable automation - I use Travis
  • +
  • Play stores and the like
  • +
  • Internal game tutorials - your players will NEVER BE SATISFIED with this last point, but at least do what you candidate
  • +
+

Community, Community, Community!

+

I, personally, underestimated this point for about a year after launch.

+

I communicated with players through the Google Play Store and Github issues, and that seemed to be enough.

+

It was only after repeated urgings from players that I opened a Discord server - and that gradually lead to a massive change!

+

You see, it's not ABOUT programmer-to-player interaction. There will always be a small number of core devs relative to the large playerbase.

+

The key to the community is the player-to-player interaction. Explaining things, questions, ideas, things that players bounc off each other, +not only make the amorphous community a better pllace, but actually lead to a better game!

+

Another think to remember is that there's a larger community around you - the Open Source community, the Linux community, etc.

+

There are lots of people who will play your game only because it's open source, and it also means they don't have as many options.

+

For example...

+
    +
  • Being the best 4X game means competing with the biggest names out there
  • +
  • Being the best 4X game for Linux means many less competitors, but All The Cool Kids (tm) are multiplatforming nowadays so you're still outperformed.
  • +
  • Being the best Open Source 4X game means about 5 competitors, and no money is involved either so the average entry is not as polished.
  • +
  • Being the best Open Source 4X game for Android... means having so few competitors that it's totally doable.
  • +
+

Everything is marketing.

+

Your game's name, the icon, screenshots, everythig a player sees about your game is marketing.

+

Icons and bylines are especially important, since they're the first things your players will probably see.

+

I saw an almost 50% (!) by changing the icon, after seveeral experiments, which Google Play lets you conduct very easily.

+

Translations are part of your source code

+

This may be slightly contraversial, so I'll explain.

+

We went though a number of iterations regarding how to save translations until we arrived at the current format.

+

The important parts are:

+
    +
  • +

    Game translation files should be AUTO GENERATED. This allows you to add new objects into the game with impunity, + knowing that corresponding lines will be auto-added to the translations.

    +
  • +
  • +

    Translations for each language should be stored separately - this allows concurrent modification of several independant languages with no risk of conflict

    +
  • +
  • +

    Translations should be PR'd in! This allows other speakers to question or change the proposed translations, and allows you to run tests on your translations. +If you require a specific format, this is invaluable as it means that bad translations will be rejected at the door.

    +
  • +
+

Open source problems require open (source?) solutions

+

TL;DR, consider using APIs that are free, even if they're not Open Source.

+

Multiplayer requires syncing game files beween clients, even when one of them is not currently online.

+

The 'correct' way to solve this would probably be to have an online DB and a service which handles user requests.

+

Since this is an Open Source game, I'm working on a 0$ budget, so we just store all the files in Dropbox and upload/download there.

+

Is this secure? No, but does it need to be? You need to think of the cost vs the value.

+

Same thing with Mods. Steam is big and secure so it handles its mods itself.

+

We are small and open, so we just allow to download from Github, which lets us use all of Github's built in functions (user management, readmes, stars, versioning...) at no extra cost.

+

And unlike the Dropbox usage, which is basically abuse, Github is built for thiss kind of thing! +This is exactly the kind of use case they were thinking of to start with!

+

The Reckoning

+

There comes a time in every project where the cool stuff is done. All the cutting-edge awesomeness and algorithmic playdough is done, and now all (hah) it needs is polish.

+

You know who loves polish? Players! Sure, there are some that say "a good game is good even if it's basic" but they have standards for what a basic game should have as well.

+

And the numbers don't lie. Polished games sell themselves better, and so are played more.

+

You know who doesn't love polish? DEVELOPERS.

+

When your game is relatively simple, then the options for polish are more limited, but the more complex the game, the more polish-venues there are.

+

And it can be an ABSOLUTE GRIND. Another weird use-case, another ingame option, "better performance" (I must have spent dozens of hours on different performance related actions)

+

And the worst thing is, that everyone notices when it's missing, but no one notices when it's there. A hundred versions of polish - literally - and the average player may notice only a slight change.

+

And then comes the moment when you ask yourself, why bother? What are we even doing here?

+

For me, the answers are as follows:

+

A. To build something truly great, you have to keep going way beyond when it stops being fun. +B. There's a community of people that like what you're doing and want there to be more of it :) +C. You know you want to keep coding, and what, you think you're going to start another project and it'll work out as well? You've tried that multiple times, and let's face it the chance of you making a second game that goes so well is really small unless you invest in it as much time as you have in this, and yeah, then you'll be back in this position again.

+

And that's basically the loop I've been in for the last hundred versions or so! Solve bugs, fix edge cases, improve AI, accept PRs. Lots of mod-related changes, both to stop the game breaking when people do things in mods that they shouldn't and to allow them more freedom in making them.

+

I don't think I'll ever really continue to finish G&K, I'm DEFINITELY not planning on implementing BNW mechanics which frankly I think are...not great.

+

That's where I am right now. Kind of done with the game, but considering that I thought that half a year ago and releases are still releasing roughly every week, also kind of not.

+ + +
+
+
+ +
+ + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/site/assets/images/favicon.png b/site/assets/images/favicon.png new file mode 100644 index 0000000000..1cf13b9f9d Binary files /dev/null and b/site/assets/images/favicon.png differ diff --git a/site/assets/javascripts/bundle.8aa65030.min.js b/site/assets/javascripts/bundle.8aa65030.min.js new file mode 100644 index 0000000000..a75b6dccfc --- /dev/null +++ b/site/assets/javascripts/bundle.8aa65030.min.js @@ -0,0 +1,29 @@ +(()=>{var Zi=Object.create;var Mt=Object.defineProperty;var ea=Object.getOwnPropertyDescriptor;var ta=Object.getOwnPropertyNames,Tt=Object.getOwnPropertySymbols,ra=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,an=Object.prototype.propertyIsEnumerable;var on=(e,t,r)=>t in e?Mt(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,$=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&on(e,r,t[r]);if(Tt)for(var r of Tt(t))an.call(t,r)&&on(e,r,t[r]);return e};var na=e=>Mt(e,"__esModule",{value:!0});var sn=(e,t)=>{var r={};for(var n in e)yr.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Tt)for(var n of Tt(e))t.indexOf(n)<0&&an.call(e,n)&&(r[n]=e[n]);return r};var ht=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var oa=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ta(t))!yr.call(e,o)&&(r||o!=="default")&&Mt(e,o,{get:()=>t[o],enumerable:!(n=ea(t,o))||n.enumerable});return e},qe=(e,t)=>oa(na(Mt(e!=null?Zi(ra(e)):{},"default",!t&&e&&e.__esModule?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);var un=ht((xr,cn)=>{(function(e,t){typeof xr=="object"&&typeof cn!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(xr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function c(_){return!!(_&&_!==document&&_.nodeName!=="HTML"&&_.nodeName!=="BODY"&&"classList"in _&&"contains"in _.classList)}function s(_){var $e=_.type,de=_.tagName;return!!(de==="INPUT"&&a[$e]&&!_.readOnly||de==="TEXTAREA"&&!_.readOnly||_.isContentEditable)}function u(_){_.classList.contains("focus-visible")||(_.classList.add("focus-visible"),_.setAttribute("data-focus-visible-added",""))}function f(_){!_.hasAttribute("data-focus-visible-added")||(_.classList.remove("focus-visible"),_.removeAttribute("data-focus-visible-added"))}function l(_){_.metaKey||_.altKey||_.ctrlKey||(c(r.activeElement)&&u(r.activeElement),n=!0)}function p(_){n=!1}function d(_){!c(_.target)||(n||s(_.target))&&u(_.target)}function h(_){!c(_.target)||(_.target.classList.contains("focus-visible")||_.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),f(_.target))}function b(_){document.visibilityState==="hidden"&&(o&&(n=!0),j())}function j(){document.addEventListener("mousemove",F),document.addEventListener("mousedown",F),document.addEventListener("mouseup",F),document.addEventListener("pointermove",F),document.addEventListener("pointerdown",F),document.addEventListener("pointerup",F),document.addEventListener("touchmove",F),document.addEventListener("touchstart",F),document.addEventListener("touchend",F)}function K(){document.removeEventListener("mousemove",F),document.removeEventListener("mousedown",F),document.removeEventListener("mouseup",F),document.removeEventListener("pointermove",F),document.removeEventListener("pointerdown",F),document.removeEventListener("pointerup",F),document.removeEventListener("touchmove",F),document.removeEventListener("touchstart",F),document.removeEventListener("touchend",F)}function F(_){_.target.nodeName&&_.target.nodeName.toLowerCase()==="html"||(n=!1,K())}document.addEventListener("keydown",l,!0),document.addEventListener("mousedown",p,!0),document.addEventListener("pointerdown",p,!0),document.addEventListener("touchstart",p,!0),document.addEventListener("visibilitychange",b,!0),j(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var fn=ht(Sr=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(u){return!1}},r=t(),n=function(u){var f={next:function(){var l=u.shift();return{done:l===void 0,value:l}}};return r&&(f[Symbol.iterator]=function(){return f}),f},o=function(u){return encodeURIComponent(u).replace(/%20/g,"+")},i=function(u){return decodeURIComponent(String(u).replace(/\+/g," "))},a=function(){var u=function(l){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var p=typeof l;if(p!=="undefined")if(p==="string")l!==""&&this._fromString(l);else if(l instanceof u){var d=this;l.forEach(function(K,F){d.append(F,K)})}else if(l!==null&&p==="object")if(Object.prototype.toString.call(l)==="[object Array]")for(var h=0;hd[0]?1:0}),u._entries&&(u._entries={});for(var l=0;l1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Sr);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(s,u){typeof s!="string"&&(s=String(s)),u&&typeof u!="string"&&(u=String(u));var f=document,l;if(u&&(e.location===void 0||u!==e.location.href)){u=u.toLowerCase(),f=document.implementation.createHTMLDocument(""),l=f.createElement("base"),l.href=u,f.head.appendChild(l);try{if(l.href.indexOf(u)!==0)throw new Error(l.href)}catch(_){throw new Error("URL unable to set base "+u+" due to "+_)}}var p=f.createElement("a");p.href=s,l&&(f.body.appendChild(p),p.href=p.href);var d=f.createElement("input");if(d.type="url",d.value=s,p.protocol===":"||!/:/.test(p.href)||!d.checkValidity()&&!u)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:p});var h=new e.URLSearchParams(this.search),b=!0,j=!0,K=this;["append","delete","set"].forEach(function(_){var $e=h[_];h[_]=function(){$e.apply(h,arguments),b&&(j=!1,K.search=h.toString(),j=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var F=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==F&&(F=this.search,j&&(b=!1,this.searchParams._fromString(this.search),b=!0))}})},a=i.prototype,c=function(s){Object.defineProperty(a,s,{get:function(){return this._anchorElement[s]},set:function(u){this._anchorElement[s]=u},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(s){c(s)}),Object.defineProperty(a,"search",{get:function(){return this._anchorElement.search},set:function(s){this._anchorElement.search=s,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(a,{toString:{get:function(){var s=this;return function(){return s.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(s){this._anchorElement.href=s,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(s){this._anchorElement.pathname=s},enumerable:!0},origin:{get:function(){var s={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],u=this._anchorElement.port!=s&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(u?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(s){},enumerable:!0},username:{get:function(){return""},set:function(s){},enumerable:!0}}),i.createObjectURL=function(s){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(s){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Sr)});var Rn=ht((Fs,Ct)=>{/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */var pn,ln,mn,dn,hn,bn,vn,gn,yn,Lt,wr,xn,Sn,wn,Xe,En,On,_n,Tn,Mn,Ln,An,Cn,At;(function(e){var t=typeof global=="object"?global:typeof self=="object"?self:typeof this=="object"?this:{};typeof define=="function"&&define.amd?define("tslib",["exports"],function(n){e(r(t,r(n)))}):typeof Ct=="object"&&typeof Ct.exports=="object"?e(r(t,r(Ct.exports))):e(r(t));function r(n,o){return n!==t&&(typeof Object.create=="function"?Object.defineProperty(n,"__esModule",{value:!0}):n.__esModule=!0),function(i,a){return n[i]=o?o(i,a):a}}})(function(e){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,o){n.__proto__=o}||function(n,o){for(var i in o)Object.prototype.hasOwnProperty.call(o,i)&&(n[i]=o[i])};pn=function(n,o){if(typeof o!="function"&&o!==null)throw new TypeError("Class extends value "+String(o)+" is not a constructor or null");t(n,o);function i(){this.constructor=n}n.prototype=o===null?Object.create(o):(i.prototype=o.prototype,new i)},ln=Object.assign||function(n){for(var o,i=1,a=arguments.length;i=0;f--)(u=n[f])&&(s=(c<3?u(s):c>3?u(o,i,s):u(o,i))||s);return c>3&&s&&Object.defineProperty(o,i,s),s},hn=function(n,o){return function(i,a){o(i,a,n)}},bn=function(n,o){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(n,o)},vn=function(n,o,i,a){function c(s){return s instanceof i?s:new i(function(u){u(s)})}return new(i||(i=Promise))(function(s,u){function f(d){try{p(a.next(d))}catch(h){u(h)}}function l(d){try{p(a.throw(d))}catch(h){u(h)}}function p(d){d.done?s(d.value):c(d.value).then(f,l)}p((a=a.apply(n,o||[])).next())})},gn=function(n,o){var i={label:0,sent:function(){if(s[0]&1)throw s[1];return s[1]},trys:[],ops:[]},a,c,s,u;return u={next:f(0),throw:f(1),return:f(2)},typeof Symbol=="function"&&(u[Symbol.iterator]=function(){return this}),u;function f(p){return function(d){return l([p,d])}}function l(p){if(a)throw new TypeError("Generator is already executing.");for(;i;)try{if(a=1,c&&(s=p[0]&2?c.return:p[0]?c.throw||((s=c.return)&&s.call(c),0):c.next)&&!(s=s.call(c,p[1])).done)return s;switch(c=0,s&&(p=[p[0]&2,s.value]),p[0]){case 0:case 1:s=p;break;case 4:return i.label++,{value:p[1],done:!1};case 5:i.label++,c=p[1],p=[0];continue;case 7:p=i.ops.pop(),i.trys.pop();continue;default:if(s=i.trys,!(s=s.length>0&&s[s.length-1])&&(p[0]===6||p[0]===2)){i=0;continue}if(p[0]===3&&(!s||p[1]>s[0]&&p[1]=n.length&&(n=void 0),{value:n&&n[a++],done:!n}}};throw new TypeError(o?"Object is not iterable.":"Symbol.iterator is not defined.")},wr=function(n,o){var i=typeof Symbol=="function"&&n[Symbol.iterator];if(!i)return n;var a=i.call(n),c,s=[],u;try{for(;(o===void 0||o-- >0)&&!(c=a.next()).done;)s.push(c.value)}catch(f){u={error:f}}finally{try{c&&!c.done&&(i=a.return)&&i.call(a)}finally{if(u)throw u.error}}return s},xn=function(){for(var n=[],o=0;o1||f(b,j)})})}function f(b,j){try{l(a[b](j))}catch(K){h(s[0][3],K)}}function l(b){b.value instanceof Xe?Promise.resolve(b.value.v).then(p,d):h(s[0][2],b)}function p(b){f("next",b)}function d(b){f("throw",b)}function h(b,j){b(j),s.shift(),s.length&&f(s[0][0],s[0][1])}},On=function(n){var o,i;return o={},a("next"),a("throw",function(c){throw c}),a("return"),o[Symbol.iterator]=function(){return this},o;function a(c,s){o[c]=n[c]?function(u){return(i=!i)?{value:Xe(n[c](u)),done:c==="return"}:s?s(u):u}:s}},_n=function(n){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var o=n[Symbol.asyncIterator],i;return o?o.call(n):(n=typeof Lt=="function"?Lt(n):n[Symbol.iterator](),i={},a("next"),a("throw"),a("return"),i[Symbol.asyncIterator]=function(){return this},i);function a(s){i[s]=n[s]&&function(u){return new Promise(function(f,l){u=n[s](u),c(f,l,u.done,u.value)})}}function c(s,u,f,l){Promise.resolve(l).then(function(p){s({value:p,done:f})},u)}},Tn=function(n,o){return Object.defineProperty?Object.defineProperty(n,"raw",{value:o}):n.raw=o,n};var r=Object.create?function(n,o){Object.defineProperty(n,"default",{enumerable:!0,value:o})}:function(n,o){n.default=o};Mn=function(n){if(n&&n.__esModule)return n;var o={};if(n!=null)for(var i in n)i!=="default"&&Object.prototype.hasOwnProperty.call(n,i)&&At(o,n,i);return r(o,n),o},Ln=function(n){return n&&n.__esModule?n:{default:n}},An=function(n,o,i,a){if(i==="a"&&!a)throw new TypeError("Private accessor was defined without a getter");if(typeof o=="function"?n!==o||!a:!o.has(n))throw new TypeError("Cannot read private member from an object whose class did not declare it");return i==="m"?a:i==="a"?a.call(n):a?a.value:o.get(n)},Cn=function(n,o,i,a,c){if(a==="m")throw new TypeError("Private method is not writable");if(a==="a"&&!c)throw new TypeError("Private accessor was defined without a setter");if(typeof o=="function"?n!==o||!c:!o.has(n))throw new TypeError("Cannot write private member to an object whose class did not declare it");return a==="a"?c.call(n,i):c?c.value=i:o.set(n,i),i},e("__extends",pn),e("__assign",ln),e("__rest",mn),e("__decorate",dn),e("__param",hn),e("__metadata",bn),e("__awaiter",vn),e("__generator",gn),e("__exportStar",yn),e("__createBinding",At),e("__values",Lt),e("__read",wr),e("__spread",xn),e("__spreadArrays",Sn),e("__spreadArray",wn),e("__await",Xe),e("__asyncGenerator",En),e("__asyncDelegator",On),e("__asyncValues",_n),e("__makeTemplateObject",Tn),e("__importStar",Mn),e("__importDefault",Ln),e("__classPrivateFieldGet",An),e("__classPrivateFieldSet",Cn)})});var Yr=ht((Et,Kr)=>{/*! + * clipboard.js v2.0.10 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Et=="object"&&typeof Kr=="object"?Kr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Et=="object"?Et.ClipboardJS=r():t.ClipboardJS=r()})(Et,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return Xi}});var a=i(279),c=i.n(a),s=i(370),u=i.n(s),f=i(817),l=i.n(f);function p(I){try{return document.execCommand(I)}catch(T){return!1}}var d=function(T){var w=l()(T);return p("cut"),w},h=d;function b(I){var T=document.documentElement.getAttribute("dir")==="rtl",w=document.createElement("textarea");w.style.fontSize="12pt",w.style.border="0",w.style.padding="0",w.style.margin="0",w.style.position="absolute",w.style[T?"right":"left"]="-9999px";var U=window.pageYOffset||document.documentElement.scrollTop;return w.style.top="".concat(U,"px"),w.setAttribute("readonly",""),w.value=I,w}var j=function(T){var w=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},U="";if(typeof T=="string"){var k=b(T);w.container.appendChild(k),U=l()(k),p("copy"),k.remove()}else U=l()(T),p("copy");return U},K=j;function F(I){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?F=function(w){return typeof w}:F=function(w){return w&&typeof Symbol=="function"&&w.constructor===Symbol&&w!==Symbol.prototype?"symbol":typeof w},F(I)}var _=function(){var T=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},w=T.action,U=w===void 0?"copy":w,k=T.container,N=T.target,Ee=T.text;if(U!=="copy"&&U!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(N!==void 0)if(N&&F(N)==="object"&&N.nodeType===1){if(U==="copy"&&N.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(U==="cut"&&(N.hasAttribute("readonly")||N.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Ee)return K(Ee,{container:k});if(N)return U==="cut"?h(N):K(N,{container:k})},$e=_;function de(I){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?de=function(w){return typeof w}:de=function(w){return w&&typeof Symbol=="function"&&w.constructor===Symbol&&w!==Symbol.prototype?"symbol":typeof w},de(I)}function Je(I,T){if(!(I instanceof T))throw new TypeError("Cannot call a class as a function")}function nn(I,T){for(var w=0;w0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof k.action=="function"?k.action:this.defaultAction,this.target=typeof k.target=="function"?k.target:this.defaultTarget,this.text=typeof k.text=="function"?k.text:this.defaultText,this.container=de(k.container)==="object"?k.container:document.body}},{key:"listenClick",value:function(k){var N=this;this.listener=u()(k,"click",function(Ee){return N.onClick(Ee)})}},{key:"onClick",value:function(k){var N=k.delegateTarget||k.currentTarget,Ee=this.action(N)||"copy",_t=$e({action:Ee,container:this.container,target:this.target(N),text:this.text(N)});this.emit(_t?"success":"error",{action:Ee,text:_t,trigger:N,clearSelection:function(){N&&N.focus(),document.activeElement.blur(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(k){return gr("action",k)}},{key:"defaultTarget",value:function(k){var N=gr("target",k);if(N)return document.querySelector(N)}},{key:"defaultText",value:function(k){return gr("text",k)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(k){var N=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return K(k,N)}},{key:"cut",value:function(k){return h(k)}},{key:"isSupported",value:function(){var k=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],N=typeof k=="string"?[k]:k,Ee=!!document.queryCommandSupported;return N.forEach(function(_t){Ee=Ee&&!!document.queryCommandSupported(_t)}),Ee}}]),w}(c()),Xi=Ji},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(c,s){for(;c&&c.nodeType!==o;){if(typeof c.matches=="function"&&c.matches(s))return c;c=c.parentNode}}n.exports=a},438:function(n,o,i){var a=i(828);function c(f,l,p,d,h){var b=u.apply(this,arguments);return f.addEventListener(p,b,h),{destroy:function(){f.removeEventListener(p,b,h)}}}function s(f,l,p,d,h){return typeof f.addEventListener=="function"?c.apply(null,arguments):typeof p=="function"?c.bind(null,document).apply(null,arguments):(typeof f=="string"&&(f=document.querySelectorAll(f)),Array.prototype.map.call(f,function(b){return c(b,l,p,d,h)}))}function u(f,l,p,d){return function(h){h.delegateTarget=a(h.target,l),h.delegateTarget&&d.call(f,h)}}n.exports=s},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(n,o,i){var a=i(879),c=i(438);function s(p,d,h){if(!p&&!d&&!h)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(h))throw new TypeError("Third argument must be a Function");if(a.node(p))return u(p,d,h);if(a.nodeList(p))return f(p,d,h);if(a.string(p))return l(p,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function u(p,d,h){return p.addEventListener(d,h),{destroy:function(){p.removeEventListener(d,h)}}}function f(p,d,h){return Array.prototype.forEach.call(p,function(b){b.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(p,function(b){b.removeEventListener(d,h)})}}}function l(p,d,h){return c(document.body,p,d,h)}n.exports=s},817:function(n){function o(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var c=i.hasAttribute("readonly");c||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),c||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var s=window.getSelection(),u=document.createRange();u.selectNodeContents(i),s.removeAllRanges(),s.addRange(u),a=s.toString()}return a}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,a,c){var s=this.e||(this.e={});return(s[i]||(s[i]=[])).push({fn:a,ctx:c}),this},once:function(i,a,c){var s=this;function u(){s.off(i,u),a.apply(c,arguments)}return u._=a,this.on(i,u,c)},emit:function(i){var a=[].slice.call(arguments,1),c=((this.e||(this.e={}))[i]||[]).slice(),s=0,u=c.length;for(s;s{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var ys=/["'&<>]/;vi.exports=xs;function xs(e){var t=""+e,r=ys.exec(t);if(!r)return t;var n,o="",i=0,a=0;for(i=r.index;i0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=n.hasError,i=n.isStopped,a=n.observers;return o||i?Er:(a.push(r),new Le(function(){return ke(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,a=n.isStopped;o?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new H;return r.source=this,r},t.create=function(r,n){return new zn(r,n)},t}(H);var zn=function(e){te(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Er},t}(O);var vt={now:function(){return(vt.delegate||Date).now()},delegate:void 0};var gt=function(e){te(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=vt);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,a=n._infiniteTimeWindow,c=n._timestampProvider,s=n._windowTime;o||(i.push(r),!a&&i.push(c.now()+s)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,a=o._buffer,c=a.slice(),s=0;s0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=nt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){if(o===void 0&&(o=0),o!=null&&o>0||o==null&&this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);r.actions.some(function(i){return i.id===n})||(nt.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Ft);var Kn=function(e){te(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Ut);var _e=new Kn(Qn);var z=new H(function(e){return e.complete()});function Wt(e){return e&&E(e.schedule)}function Cr(e){return e[e.length-1]}function je(e){return E(Cr(e))?e.pop():void 0}function ye(e){return Wt(Cr(e))?e.pop():void 0}function Dt(e,t){return typeof Cr(e)=="number"?e.pop():t}var ot=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Vt(e){return E(e==null?void 0:e.then)}function Nt(e){return E(e[rt])}function zt(e){return Symbol.asyncIterator&&E(e==null?void 0:e[Symbol.asyncIterator])}function qt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function ma(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Qt=ma();function Kt(e){return E(e==null?void 0:e[Qt])}function Yt(e){return Pn(this,arguments,function(){var r,n,o,i;return Rt(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,kt(r.read())];case 3:return n=a.sent(),o=n.value,i=n.done,i?[4,kt(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,kt(o)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Bt(e){return E(e==null?void 0:e.getReader)}function V(e){if(e instanceof H)return e;if(e!=null){if(Nt(e))return da(e);if(ot(e))return ha(e);if(Vt(e))return ba(e);if(zt(e))return Yn(e);if(Kt(e))return va(e);if(Bt(e))return ga(e)}throw qt(e)}function da(e){return new H(function(t){var r=e[rt]();if(E(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function ha(e){return new H(function(t){for(var r=0;r=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new O}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,a=i===void 0?!0:i,c=e.resetOnRefCountZero,s=c===void 0?!0:c;return function(u){var f=null,l=null,p=null,d=0,h=!1,b=!1,j=function(){l==null||l.unsubscribe(),l=null},K=function(){j(),f=p=null,h=b=!1},F=function(){var _=f;K(),_==null||_.unsubscribe()};return v(function(_,$e){d++,!b&&!h&&j();var de=p=p!=null?p:r();$e.add(function(){d--,d===0&&!b&&!h&&(l=Fr(F,s))}),de.subscribe($e),f||(f=new tt({next:function(Je){return de.next(Je)},error:function(Je){b=!0,j(),l=Fr(K,o,Je),de.error(Je)},complete:function(){h=!0,j(),l=Fr(K,a),de.complete()}}),re(_).subscribe(f))})(u)}}function Fr(e,t){for(var r=[],n=2;ne.next(document)),e}function G(e,t=document){return Array.from(t.querySelectorAll(e))}function B(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function De(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function er(e){return C(y(document.body,"focusin"),y(document.body,"focusout")).pipe(Be(1),m(()=>{let t=De();return typeof t!="undefined"?e.contains(t):!1}),q(e===De()),Y())}function Ve(e){return{x:e.offsetLeft,y:e.offsetTop}}function ho(e){return C(y(window,"load"),y(window,"resize")).pipe(He(0,_e),m(()=>Ve(e)),q(Ve(e)))}function bo(e){return{x:e.scrollLeft,y:e.scrollTop}}function tr(e){return C(y(e,"scroll"),y(window,"resize")).pipe(He(0,_e),m(()=>bo(e)),q(bo(e)))}var go=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!zr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),Wa?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!zr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=Ua.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),yo=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),So=typeof WeakMap!="undefined"?new WeakMap:new go,wo=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=Da.getInstance(),n=new Ja(t,r,this);So.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){wo.prototype[e]=function(){var t;return(t=So.get(this))[e].apply(t,arguments)}});var Xa=function(){return typeof rr.ResizeObserver!="undefined"?rr.ResizeObserver:wo}(),Eo=Xa;var Oo=new O,Za=P(()=>L(new Eo(e=>{for(let t of e)Oo.next(t)}))).pipe(x(e=>C(xe,L(e)).pipe(R(()=>e.disconnect()))),X(1));function Ae(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ve(e){return Za.pipe(S(t=>t.observe(e)),x(t=>Oo.pipe(M(({target:r})=>r===e),R(()=>t.unobserve(e)),m(()=>Ae(e)))),q(Ae(e)))}function ir(e){return{width:e.scrollWidth,height:e.scrollHeight}}var es=new O,Ev=P(()=>L(new IntersectionObserver(e=>{for(let t of e)es.next(t)},{threshold:1}))).pipe(x(e=>C(xe,L(e)).pipe(R(()=>e.disconnect()))),X(1));function _o(e,t=16){return tr(e).pipe(m(({y:r})=>{let n=Ae(e),o=ir(e);return r>=o.height-n.height-t}),Y())}var ar={drawer:B("[data-md-toggle=drawer]"),search:B("[data-md-toggle=search]")};function To(e){return ar[e].checked}function Ne(e,t){ar[e].checked!==t&&ar[e].click()}function sr(e){let t=ar[e];return y(t,"change").pipe(m(()=>t.checked),q(t.checked))}function ts(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Mo(){return y(window,"keydown").pipe(M(e=>!(e.metaKey||e.ctrlKey)),m(e=>({mode:To("search")?"search":"global",type:e.key,claim(){e.preventDefault(),e.stopPropagation()}})),M(({mode:e,type:t})=>{if(e==="global"){let r=De();if(typeof r!="undefined")return!ts(r,t)}return!0}),pe())}function Se(){return new URL(location.href)}function cr(e){location.href=e.href}function Lo(){return new O}function Ao(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Ao(e,r)}function A(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="boolean"?n.setAttribute(o,t[o]):t[o]&&n.setAttribute(o,"");for(let o of r)Ao(n,o);return n}function Co(e,t){let r=t;if(e.length>r){for(;e[r]!==" "&&--r>0;);return`${e.substring(0,r)}...`}return e}function ur(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function Ro(){return location.hash.substring(1)}function ko(e){let t=A("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function rs(){return y(window,"hashchange").pipe(m(Ro),q(Ro()),M(e=>e.length>0),X(1))}function Ho(){return rs().pipe(m(e=>ce(`[id="${e}"]`)),M(e=>typeof e!="undefined"))}function qr(e){let t=matchMedia(e);return Xt(r=>t.addListener(()=>r(t.matches))).pipe(q(t.matches))}function Po(){let e=matchMedia("print");return C(y(window,"beforeprint").pipe(Z(!0)),y(window,"afterprint").pipe(Z(!1))).pipe(q(e.matches))}function Qr(e,t){return e.pipe(x(r=>r?t():z))}function fr(e,t={credentials:"same-origin"}){return re(fetch(`${e}`,t)).pipe(M(r=>r.status===200),We(()=>z))}function Ce(e,t){return fr(e,t).pipe(x(r=>r.json()),X(1))}function Io(e,t){let r=new DOMParser;return fr(e,t).pipe(x(n=>n.text()),m(n=>r.parseFromString(n,"text/xml")),X(1))}function $o(e){let t=A("script",{src:e});return P(()=>(document.head.appendChild(t),C(y(t,"load"),y(t,"error").pipe(x(()=>Rr(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(Z(void 0),R(()=>document.head.removeChild(t)),ae(1))))}function jo(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function Fo(){return C(y(window,"scroll",{passive:!0}),y(window,"resize",{passive:!0})).pipe(m(jo),q(jo()))}function Uo(){return{width:innerWidth,height:innerHeight}}function Wo(){return y(window,"resize",{passive:!0}).pipe(m(Uo),q(Uo()))}function Do(){return Q([Fo(),Wo()]).pipe(m(([e,t])=>({offset:e,size:t})),X(1))}function pr(e,{viewport$:t,header$:r}){let n=t.pipe(J("size")),o=Q([n,r]).pipe(m(()=>Ve(e)));return Q([r,t,o]).pipe(m(([{height:i},{offset:a,size:c},{x:s,y:u}])=>({offset:{x:a.x-s,y:a.y-u+i},size:c})))}function Vo(e,{tx$:t}){let r=y(e,"message").pipe(m(({data:n})=>n));return t.pipe(wt(()=>r,{leading:!0,trailing:!0}),S(n=>e.postMessage(n)),Ur(r),pe())}var ns=B("#__config"),pt=JSON.parse(ns.textContent);pt.base=`${new URL(pt.base,Se())}`;function me(){return pt}function ie(e){return pt.features.includes(e)}function ee(e,t){return typeof t!="undefined"?pt.translations[e].replace("#",t.toString()):pt.translations[e]}function Re(e,t=document){return B(`[data-md-component=${e}]`,t)}function ne(e,t=document){return G(`[data-md-component=${e}]`,t)}var Zo=qe(Yr());function No(e){return A("aside",{class:"md-annotation",tabIndex:0},A("div",{class:"md-annotation__inner md-tooltip"},A("div",{class:"md-tooltip__inner md-typeset"})),A("span",{class:"md-annotation__index"},A("span",{"data-md-annotation-id":e})))}function zo(e){return A("button",{class:"md-clipboard md-icon",title:ee("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}function Br(e,t){let r=t&2,n=t&1,o=Object.keys(e.terms).filter(a=>!e.terms[a]).reduce((a,c)=>[...a,A("del",null,c)," "],[]).slice(0,-1),i=new URL(e.location);return ie("search.highlight")&&i.searchParams.set("h",Object.entries(e.terms).filter(([,a])=>a).reduce((a,[c])=>`${a} ${c}`.trim(),"")),A("a",{href:`${i}`,class:"md-search-result__link",tabIndex:-1},A("article",{class:["md-search-result__article",...r?["md-search-result__article--document"]:[]].join(" "),"data-md-score":e.score.toFixed(2)},r>0&&A("div",{class:"md-search-result__icon md-icon"}),A("h1",{class:"md-search-result__title"},e.title),n>0&&e.text.length>0&&A("p",{class:"md-search-result__teaser"},Co(e.text,320)),e.tags&&e.tags.map(a=>A("span",{class:"md-tag"},a)),n>0&&o.length>0&&A("p",{class:"md-search-result__terms"},ee("search.result.term.missing"),": ",o)))}function qo(e){let t=e[0].score,r=[...e],n=r.findIndex(u=>!u.location.includes("#")),[o]=r.splice(n,1),i=r.findIndex(u=>u.scoreBr(u,1)),...c.length?[A("details",{class:"md-search-result__more"},A("summary",{tabIndex:-1},c.length>0&&c.length===1?ee("search.result.more.one"):ee("search.result.more.other",c.length)),c.map(u=>Br(u,1)))]:[]];return A("li",{class:"md-search-result__item"},s)}function Qo(e){return A("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>A("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?ur(r):r)))}function Ko(e){return A("div",{class:"md-typeset__scrollwrap"},A("div",{class:"md-typeset__table"},e))}function os(e){let t=me(),r=new URL(`../${e.version}/`,t.base);return A("li",{class:"md-version__item"},A("a",{href:r.toString(),class:"md-version__link"},e.title))}function Yo(e,t){return A("div",{class:"md-version"},A("button",{class:"md-version__current","aria-label":ee("select.version.title")},t.title),A("ul",{class:"md-version__list"},e.map(os)))}function is(e,t){let r=P(()=>Q([ho(e),tr(t)])).pipe(m(([{x:n,y:o},i])=>{let{width:a}=Ae(e);return{x:n-i.x+a/2,y:o-i.y}}));return er(e).pipe(x(n=>r.pipe(m(o=>({active:n,offset:o})),ae(+!n||1/0))))}function Bo(e,t){return P(()=>{let r=new O;r.subscribe({next({offset:i}){e.style.setProperty("--md-tooltip-x",`${i.x}px`),e.style.setProperty("--md-tooltip-y",`${i.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),r.pipe(Vr(500,_e),m(()=>t.getBoundingClientRect()),m(({x:i})=>i)).subscribe({next(i){i?e.style.setProperty("--md-tooltip-0",`${-i}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}});let n=B(":scope > :last-child",e),o=y(n,"mousedown",{once:!0});return r.pipe(x(({active:i})=>i?o:z),S(i=>i.preventDefault())).subscribe(()=>e.blur()),is(e,t).pipe(S(i=>r.next(i)),R(()=>r.complete()),m(i=>$({ref:e},i)))})}function as(e){let t=[];for(let r of G(".c, .c1, .cm",e)){let n,o=r.firstChild;for(;n=/\((\d+)\)/.exec(o.textContent);){let i=o.splitText(n.index);o=i.splitText(n[0].length),t.push(i)}}return t}function Go(e,t){t.append(...Array.from(e.childNodes))}function Jo(e,t,{print$:r}){let n=new Map;for(let o of as(t)){let[,i]=o.textContent.match(/\((\d+)\)/);ce(`li:nth-child(${i})`,e)&&(n.set(+i,No(+i)),o.replaceWith(n.get(+i)))}return n.size===0?z:P(()=>{let o=new O;return r.pipe(se(o.pipe(fe(1)))).subscribe(i=>{e.hidden=!i;for(let[a,c]of n){let s=B(".md-typeset",c),u=B(`li:nth-child(${a})`,e);i?Go(s,u):Go(u,s)}}),C(...[...n].map(([,i])=>Bo(i,t))).pipe(R(()=>o.complete()),pe())})}var ss=0;function ei(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return ei(t)}}function Xo(e){return ve(e).pipe(m(({width:t})=>({scrollable:ir(e).width>t})),J("scrollable"))}function ti(e,t){let{matches:r}=matchMedia("(hover)");return P(()=>{let n=new O;if(n.subscribe(({scrollable:i})=>{i&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")}),Zo.default.isSupported()){let i=e.closest("pre");i.id=`__code_${++ss}`,i.insertBefore(zo(i.id),e)}let o=e.closest([":not(td):not(.code) > .highlight",".highlighttable"].join(", "));if(o instanceof HTMLElement){let i=ei(o);if(typeof i!="undefined"&&(o.classList.contains("annotate")||ie("content.code.annotate"))){let a=Jo(i,e,t);return Xo(e).pipe(S(c=>n.next(c)),R(()=>n.complete()),m(c=>$({ref:e},c)),Ge(ve(o).pipe(se(n.pipe(fe(1))),m(({width:c,height:s})=>c&&s),Y(),x(c=>c?a:z))))}}return Xo(e).pipe(S(i=>n.next(i)),R(()=>n.complete()),m(i=>$({ref:e},i)))})}var ri=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:transparent}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color)}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}#compositionEnd,#compositionStart,#dependencyEnd,#dependencyStart,#extensionEnd,#extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}#aggregationEnd,#aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}#ONE_OR_MORE_END *,#ONE_OR_MORE_START *,#ONLY_ONE_END *,#ONLY_ONE_START *,#ZERO_OR_MORE_END *,#ZERO_OR_MORE_START *,#ZERO_OR_ONE_END *,#ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}#ZERO_OR_MORE_END circle,#ZERO_OR_MORE_START circle,.actor{fill:var(--md-mermaid-label-bg-color)}.actor{stroke:var(--md-mermaid-node-fg-color)}text.actor>tspan{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-default-fg-color--lighter)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-edge-color)}.loopText>tspan,.messageText{fill:var(--md-mermaid-edge-color);stroke:none;font-family:var(--md-mermaid-font-family)!important}#arrowhead path{fill:var(--md-mermaid-edge-color);stroke:none}.loopLine{stroke:var(--md-mermaid-node-fg-color)}.labelBox,.loopLine{fill:var(--md-mermaid-node-bg-color)}.labelBox{stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-node-fg-color);font-family:var(--md-mermaid-font-family)}";var Gr,us=0;function fs(){return typeof mermaid=="undefined"?$o("https://unpkg.com/mermaid@8.13.3/dist/mermaid.min.js"):L(void 0)}function ni(e){return e.classList.remove("mermaid"),Gr||(Gr=fs().pipe(S(()=>mermaid.initialize({startOnLoad:!1,themeCSS:ri})),Z(void 0),X(1))),Gr.subscribe(()=>{e.classList.add("mermaid");let t=`__mermaid_${us++}`,r=A("div",{class:"mermaid"});mermaid.mermaidAPI.render(t,e.textContent,n=>{let o=r.attachShadow({mode:"closed"});o.innerHTML=n,e.replaceWith(r)})}),Gr.pipe(Z({ref:e}))}function ps(e,{target$:t,print$:r}){let n=!0;return C(t.pipe(m(o=>o.closest("details:not([open])")),M(o=>e===o),Z({action:"open",reveal:!0})),r.pipe(M(o=>o||!n),S(()=>n=e.open),m(o=>({action:o?"open":"close"}))))}function oi(e,t){return P(()=>{let r=new O;return r.subscribe(({action:n,reveal:o})=>{n==="open"?e.setAttribute("open",""):e.removeAttribute("open"),o&&e.scrollIntoView()}),ps(e,t).pipe(S(n=>r.next(n)),R(()=>r.complete()),m(n=>$({ref:e},n)))})}var ii=A("table");function ai(e){return e.replaceWith(ii),ii.replaceWith(Ko(e)),L({ref:e})}function ls(e){let t=G(":scope > input",e);return C(...t.map(r=>y(r,"change").pipe(Z({active:B(`label[for=${r.id}]`)})))).pipe(q({active:B(`label[for=${t[0].id}]`)}))}function si(e){let t=B(".tabbed-labels",e);return P(()=>{let r=new O;return Q([r,ve(e)]).pipe(He(1,_e),se(r.pipe(fe(1)))).subscribe({next([{active:n}]){let o=Ve(n),{width:i}=Ae(n);e.style.setProperty("--md-indicator-x",`${o.x}px`),e.style.setProperty("--md-indicator-width",`${i}px`),t.scrollTo({behavior:"smooth",left:o.x})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),ls(e).pipe(S(n=>r.next(n)),R(()=>r.complete()),m(n=>$({ref:e},n)))})}function ci(e,{target$:t,print$:r}){return C(...G("pre:not(.mermaid) > code",e).map(n=>ti(n,{print$:r})),...G("pre.mermaid",e).map(n=>ni(n)),...G("table:not([class])",e).map(n=>ai(n)),...G("details",e).map(n=>oi(n,{target$:t,print$:r})),...G("[data-tabs]",e).map(n=>si(n)))}function ms(e,{alert$:t}){return t.pipe(x(r=>C(L(!0),L(!1).pipe(Ie(2e3))).pipe(m(n=>({message:r,active:n})))))}function ui(e,t){let r=B(".md-typeset",e);return P(()=>{let n=new O;return n.subscribe(({message:o,active:i})=>{r.textContent=o,i?e.setAttribute("data-md-state","open"):e.removeAttribute("data-md-state")}),ms(e,t).pipe(S(o=>n.next(o)),R(()=>n.complete()),m(o=>$({ref:e},o)))})}function ds({viewport$:e}){if(!ie("header.autohide"))return L(!1);let t=e.pipe(m(({offset:{y:o}})=>o),Te(2,1),m(([o,i])=>[oMath.abs(i-o.y)>100),m(([,[o]])=>o),Y()),n=sr("search");return Q([e,n]).pipe(m(([{offset:o},i])=>o.y>400&&!i),Y(),x(o=>o?r:L(!1)),q(!1))}function fi(e,t){return P(()=>{let r=getComputedStyle(e);return L(r.position==="sticky"||r.position==="-webkit-sticky")}).pipe(st(ve(e),ds(t)),m(([r,{height:n},o])=>({height:r?n:0,sticky:r,hidden:o})),Y((r,n)=>r.sticky===n.sticky&&r.height===n.height&&r.hidden===n.hidden),X(1))}function pi(e,{header$:t,main$:r}){return P(()=>{let n=new O;return n.pipe(J("active"),st(t)).subscribe(([{active:o},{hidden:i}])=>{o?e.setAttribute("data-md-state",i?"hidden":"shadow"):e.removeAttribute("data-md-state")}),r.subscribe(n),t.pipe(se(n.pipe(fe(1))),m(o=>$({ref:e},o)))})}function hs(e,{viewport$:t,header$:r}){return pr(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:n}})=>{let{height:o}=Ae(e);return{active:n>=o}}),J("active"))}function li(e,t){return P(()=>{let r=new O;r.subscribe(({active:o})=>{o?e.setAttribute("data-md-state","active"):e.removeAttribute("data-md-state")});let n=ce("article h1");return typeof n=="undefined"?z:hs(n,t).pipe(S(o=>r.next(o)),R(()=>r.complete()),m(o=>$({ref:e},o)))})}function mi(e,{viewport$:t,header$:r}){let n=r.pipe(m(({height:i})=>i),Y()),o=n.pipe(x(()=>ve(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),J("bottom"))));return Q([n,o,t]).pipe(m(([i,{top:a,bottom:c},{offset:{y:s},size:{height:u}}])=>(u=Math.max(0,u-Math.max(0,a-s,i)-Math.max(0,u+s-c)),{offset:a-i,height:u,active:a-i<=s})),Y((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function bs(e){let t=__md_get("__palette")||{index:e.findIndex(r=>matchMedia(r.getAttribute("data-md-color-media")).matches)};return L(...e).pipe(oe(r=>y(r,"change").pipe(Z(r))),q(e[Math.max(0,t.index)]),m(r=>({index:e.indexOf(r),color:{scheme:r.getAttribute("data-md-color-scheme"),primary:r.getAttribute("data-md-color-primary"),accent:r.getAttribute("data-md-color-accent")}})),X(1))}function di(e){return P(()=>{let t=new O;t.subscribe(n=>{for(let[o,i]of Object.entries(n.color))document.body.setAttribute(`data-md-color-${o}`,i);for(let o=0;ot.next(n)),R(()=>t.complete()),m(n=>$({ref:e},n)))})}var Jr=qe(Yr());function vs(e){e.setAttribute("data-md-copying","");let t=e.innerText;return e.removeAttribute("data-md-copying"),t}function hi({alert$:e}){Jr.default.isSupported()&&new H(t=>{new Jr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||vs(B(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(S(t=>{t.trigger.focus()}),Z(ee("clipboard.copied"))).subscribe(e)}function gs(e){if(e.length<2)return[""];let[t,r]=[...e].sort((o,i)=>o.length-i.length).map(o=>o.replace(/[^/]+$/,"")),n=0;if(t===r)n=t.length;else for(;t.charCodeAt(n)===r.charCodeAt(n);)n++;return e.map(o=>o.replace(t.slice(0,n),""))}function lr(e){let t=__md_get("__sitemap",sessionStorage,e);if(t)return L(t);{let r=me();return Io(new URL("sitemap.xml",e||r.base)).pipe(m(n=>gs(G("loc",n).map(o=>o.textContent))),Pe([]),S(n=>__md_set("__sitemap",n,sessionStorage,e)))}}function bi({document$:e,location$:t,viewport$:r}){let n=me();if(location.protocol==="file:")return;"scrollRestoration"in history&&(history.scrollRestoration="manual",y(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}));let o=ce("link[rel=icon]");typeof o!="undefined"&&(o.href=o.href);let i=lr().pipe(m(u=>u.map(f=>`${new URL(f,n.base)}`)),x(u=>y(document.body,"click").pipe(M(f=>!f.metaKey&&!f.ctrlKey),x(f=>{if(f.target instanceof Element){let l=f.target.closest("a");if(l&&!l.target){let p=new URL(l.href);if(p.search="",p.hash="",p.pathname!==location.pathname&&u.includes(p.toString()))return f.preventDefault(),L({url:new URL(l.href)})}}return xe}))),pe()),a=y(window,"popstate").pipe(M(u=>u.state!==null),m(u=>({url:new URL(location.href),offset:u.state})),pe());C(i,a).pipe(Y((u,f)=>u.url.href===f.url.href),m(({url:u})=>u)).subscribe(t);let c=t.pipe(J("pathname"),x(u=>fr(u.href).pipe(We(()=>(cr(u),xe)))),pe());i.pipe(ct(c)).subscribe(({url:u})=>{history.pushState({},"",`${u}`)});let s=new DOMParser;c.pipe(x(u=>u.text()),m(u=>s.parseFromString(u,"text/html"))).subscribe(e),e.pipe(ut(1)).subscribe(u=>{for(let f of["title","link[rel=canonical]","meta[name=author]","meta[name=description]","[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=logo]","[data-md-component=skip]",...ie("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let l=ce(f),p=ce(f,u);typeof l!="undefined"&&typeof p!="undefined"&&l.replaceWith(p)}}),e.pipe(ut(1),m(()=>Re("container")),x(u=>L(...G("script",u))),Pr(u=>{let f=A("script");if(u.src){for(let l of u.getAttributeNames())f.setAttribute(l,u.getAttribute(l));return u.replaceWith(f),new H(l=>{f.onload=()=>l.complete()})}else return f.textContent=u.textContent,u.replaceWith(f),z})).subscribe(),C(i,a).pipe(ct(e)).subscribe(({url:u,offset:f})=>{u.hash&&!f?ko(u.hash):window.scrollTo(0,(f==null?void 0:f.y)||0)}),r.pipe(St(i),Be(250),J("offset")).subscribe(({offset:u})=>{history.replaceState(u,"")}),C(i,a).pipe(Te(2,1),M(([u,f])=>u.url.pathname===f.url.pathname),m(([,u])=>u)).subscribe(({offset:u})=>{window.scrollTo(0,(u==null?void 0:u.y)||0)})}var Ss=qe(Xr());var gi=qe(Xr());function Zr(e,t){let r=new RegExp(e.separator,"img"),n=(o,i,a)=>`${i}${a}`;return o=>{o=o.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator})(${o.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(t?(0,gi.default)(a):a).replace(i,n).replace(/<\/mark>(\s+)]*>/img,"$1")}}function yi(e){return e.split(/"([^"]+)"/g).map((t,r)=>r&1?t.replace(/^\b|^(?![^\x00-\x7F]|$)|\s+/g," +"):t).join("").replace(/"|(?:^|\s+)[*+\-:^~]+(?=\s+|$)/g,"").trim()}function lt(e){return e.type===1}function xi(e){return e.type===2}function mt(e){return e.type===3}function Es({config:e,docs:t}){e.lang.length===1&&e.lang[0]==="en"&&(e.lang=[ee("search.config.lang")]),e.separator==="[\\s\\-]+"&&(e.separator=ee("search.config.separator"));let n={pipeline:ee("search.config.pipeline").split(/\s*,\s*/).filter(Boolean),suggestions:ie("search.suggest")};return{config:e,docs:t,options:n}}function Si(e,t){let r=me(),n=new Worker(e),o=new O,i=Vo(n,{tx$:o}).pipe(m(a=>{if(mt(a))for(let c of a.data.items)for(let s of c)s.location=`${new URL(s.location,r.base)}`;return a}),pe());return re(t).pipe(m(a=>({type:0,data:Es(a)}))).subscribe(o.next.bind(o)),{tx$:o,rx$:i}}function wi(){let e=me(),t=Ce(new URL("../versions.json",e.base)),r=t.pipe(m(n=>{let[,o]=e.base.match(/([^/]+)\/?$/);return n.find(({version:i,aliases:a})=>i===o||a.includes(o))||n[0]}));Q([t,r]).pipe(m(([n,o])=>new Map(n.filter(i=>i!==o).map(i=>[`${new URL(`../${i.version}/`,e.base)}`,i]))),x(n=>y(document.body,"click").pipe(M(o=>!o.metaKey&&!o.ctrlKey),x(o=>{if(o.target instanceof Element){let i=o.target.closest("a");if(i&&!i.target&&n.has(i.href))return o.preventDefault(),L(i.href)}return z}),x(o=>{let{version:i}=n.get(o);return lr(new URL(o)).pipe(m(a=>{let s=Se().href.replace(e.base,"");return a.includes(s)?new URL(`../${i}/${s}`,e.base):new URL(o)}))})))).subscribe(n=>cr(n)),Q([t,r]).subscribe(([n,o])=>{var a;if(B(".md-header__topic").appendChild(Yo(n,o)),__md_get("__outdated",sessionStorage)===null){let c=((a=e.version)==null?void 0:a.default)||"latest",s=!o.aliases.includes(c);if(__md_set("__outdated",s,sessionStorage),s)for(let u of ne("outdated"))u.hidden=!1}})}function Os(e,{rx$:t}){let r=(__search==null?void 0:__search.transform)||yi,{searchParams:n}=Se();n.has("q")&&Ne("search",!0);let o=t.pipe(M(lt),ae(1),m(()=>n.get("q")||""));o.subscribe(c=>{c&&(e.value=c)});let i=er(e),a=C(y(e,"keyup"),y(e,"focus").pipe(Ie(1)),o).pipe(m(()=>r(e.value)),q(""),Y());return Q([a,i]).pipe(m(([c,s])=>({value:c,focus:s})),X(1))}function Ei(e,{tx$:t,rx$:r}){let n=new O;return n.pipe(J("value"),m(({value:o})=>({type:2,data:o}))).subscribe(t.next.bind(t)),n.pipe(J("focus")).subscribe(({focus:o})=>{o?(Ne("search",o),e.placeholder=""):e.placeholder=ee("search.placeholder")}),y(e.form,"reset").pipe(se(n.pipe(fe(1)))).subscribe(()=>e.focus()),Os(e,{tx$:t,rx$:r}).pipe(S(o=>n.next(o)),R(()=>n.complete()),m(o=>$({ref:e},o)))}function Oi(e,{rx$:t},{query$:r}){let n=new O,o=_o(e.parentElement).pipe(M(Boolean)),i=B(":scope > :first-child",e),a=B(":scope > :last-child",e),c=t.pipe(M(lt),ae(1));return n.pipe(Me(r),St(c)).subscribe(([{items:u},{value:f}])=>{if(f)switch(u.length){case 0:i.textContent=ee("search.result.none");break;case 1:i.textContent=ee("search.result.one");break;default:i.textContent=ee("search.result.other",ur(u.length))}else i.textContent=ee("search.result.placeholder")}),n.pipe(S(()=>a.innerHTML=""),x(({items:u})=>C(L(...u.slice(0,10)),L(...u.slice(10)).pipe(Te(4),Nr(o),x(([f])=>L(...f)))))).subscribe(u=>a.appendChild(qo(u))),t.pipe(M(mt),m(({data:u})=>u)).pipe(S(u=>n.next(u)),R(()=>n.complete()),m(u=>$({ref:e},u)))}function _s(e,{query$:t}){return t.pipe(m(({value:r})=>{let n=Se();return n.hash="",n.searchParams.delete("h"),n.searchParams.set("q",r),{url:n}}))}function _i(e,t){let r=new O;return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),y(e,"click").subscribe(n=>n.preventDefault()),_s(e,t).pipe(S(n=>r.next(n)),R(()=>r.complete()),m(n=>$({ref:e},n)))}function Ti(e,{rx$:t},{keyboard$:r}){let n=new O,o=Re("search-query"),i=C(y(o,"keydown"),y(o,"focus")).pipe(Ke(ge),m(()=>o.value),Y());return n.pipe(st(i),m(([{suggestions:c},s])=>{let u=s.split(/([\s-]+)/);if((c==null?void 0:c.length)&&u[u.length-1]){let f=c[c.length-1];f.startsWith(u[u.length-1])&&(u[u.length-1]=f)}else u.length=0;return u})).subscribe(c=>e.innerHTML=c.join("").replace(/\s/g," ")),r.pipe(M(({mode:c})=>c==="search")).subscribe(c=>{switch(c.type){case"ArrowRight":e.innerText.length&&o.selectionStart===o.value.length&&(o.value=e.innerText);break}}),t.pipe(M(mt),m(({data:c})=>c)).pipe(S(c=>n.next(c)),R(()=>n.complete()),m(()=>({ref:e})))}function Mi(e,{index$:t,keyboard$:r}){let n=me();try{let o=(__search==null?void 0:__search.worker)||n.search,i=Si(o,t),a=Re("search-query",e),c=Re("search-result",e),{tx$:s,rx$:u}=i;s.pipe(M(xi),ct(u.pipe(M(lt))),ae(1)).subscribe(s.next.bind(s)),r.pipe(M(({mode:p})=>p==="search")).subscribe(p=>{let d=De();switch(p.type){case"Enter":if(d===a){let h=new Map;for(let b of G(":first-child [href]",c)){let j=b.firstElementChild;h.set(b,parseFloat(j.getAttribute("data-md-score")))}if(h.size){let[[b]]=[...h].sort(([,j],[,K])=>K-j);b.click()}p.claim()}break;case"Escape":case"Tab":Ne("search",!1),a.blur();break;case"ArrowUp":case"ArrowDown":if(typeof d=="undefined")a.focus();else{let h=[a,...G(":not(details) > [href], summary, details[open] [href]",c)],b=Math.max(0,(Math.max(0,h.indexOf(d))+h.length+(p.type==="ArrowUp"?-1:1))%h.length);h[b].focus()}p.claim();break;default:a!==De()&&a.focus()}}),r.pipe(M(({mode:p})=>p==="global")).subscribe(p=>{switch(p.type){case"f":case"s":case"/":a.focus(),a.select(),p.claim();break}});let f=Ei(a,i),l=Oi(c,i,{query$:f});return C(f,l).pipe(Ge(...ne("search-share",e).map(p=>_i(p,{query$:f})),...ne("search-suggest",e).map(p=>Ti(p,i,{keyboard$:r}))))}catch(o){return e.hidden=!0,xe}}function Li(e,{index$:t,location$:r}){return Q([t,r.pipe(q(Se()),M(n=>!!n.searchParams.get("h")))]).pipe(m(([n,o])=>Zr(n.config,!0)(o.searchParams.get("h"))),m(n=>{var a;let o=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let c=i.nextNode();c;c=i.nextNode())if((a=c.parentElement)==null?void 0:a.offsetHeight){let s=c.textContent,u=n(s);u.length>s.length&&o.set(c,u)}for(let[c,s]of o){let{childNodes:u}=A("span",null,s);c.replaceWith(...Array.from(u))}return{ref:e,nodes:o}}))}function Ts(e,{viewport$:t,main$:r}){let n=e.parentElement,o=n.offsetTop-n.parentElement.offsetTop;return Q([r,t]).pipe(m(([{offset:i,height:a},{offset:{y:c}}])=>(a=a+Math.min(o,Math.max(0,c-i))-o,{height:a,locked:c>=i+o})),Y((i,a)=>i.height===a.height&&i.locked===a.locked))}function en(e,n){var o=n,{header$:t}=o,r=sn(o,["header$"]);let i=B(".md-sidebar__scrollwrap",e),{y:a}=Ve(i);return P(()=>{let c=new O;return c.pipe(He(0,_e),Me(t)).subscribe({next([{height:s},{height:u}]){i.style.height=`${s-2*a}px`,e.style.top=`${u}px`},complete(){i.style.height="",e.style.top=""}}),Ts(e,r).pipe(S(s=>c.next(s)),R(()=>c.complete()),m(s=>$({ref:e},s)))})}function Ai(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return xt(Ce(`${r}/releases/latest`).pipe(m(n=>({version:n.tag_name})),Pe({})),Ce(r).pipe(m(n=>({stars:n.stargazers_count,forks:n.forks_count})),Pe({}))).pipe(m(([n,o])=>$($({},n),o)))}else{let r=`https://api.github.com/users/${e}`;return Ce(r).pipe(m(n=>({repositories:n.public_repos})),Pe({}))}}function Ci(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return Ce(r).pipe(m(({star_count:n,forks_count:o})=>({stars:n,forks:o})),Pe({}))}function Ri(e){let[t]=e.match(/(git(?:hub|lab))/i)||[];switch(t.toLowerCase()){case"github":let[,r,n]=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);return Ai(r,n);case"gitlab":let[,o,i]=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i);return Ci(o,i);default:return z}}var Ms;function Ls(e){return Ms||(Ms=P(()=>{let t=__md_get("__source",sessionStorage);return t?L(t):Ri(e.href).pipe(S(r=>__md_set("__source",r,sessionStorage)))}).pipe(We(()=>z),M(t=>Object.keys(t).length>0),m(t=>({facts:t})),X(1)))}function ki(e){let t=B(":scope > :last-child",e);return P(()=>{let r=new O;return r.subscribe(({facts:n})=>{t.appendChild(Qo(n)),t.setAttribute("data-md-state","done")}),Ls(e).pipe(S(n=>r.next(n)),R(()=>r.complete()),m(n=>$({ref:e},n)))})}function As(e,{viewport$:t,header$:r}){return ve(document.body).pipe(x(()=>pr(e,{header$:r,viewport$:t})),m(({offset:{y:n}})=>({hidden:n>=10})),J("hidden"))}function Hi(e,t){return P(()=>{let r=new O;return r.subscribe({next({hidden:n}){n?e.setAttribute("data-md-state","hidden"):e.removeAttribute("data-md-state")},complete(){e.removeAttribute("data-md-state")}}),(ie("navigation.tabs.sticky")?L({hidden:!1}):As(e,t)).pipe(S(n=>r.next(n)),R(()=>r.complete()),m(n=>$({ref:e},n)))})}function Cs(e,{viewport$:t,header$:r}){let n=new Map,o=G("[href^=\\#]",e);for(let c of o){let s=decodeURIComponent(c.hash.substring(1)),u=ce(`[id="${s}"]`);typeof u!="undefined"&&n.set(c,u)}let i=r.pipe(m(c=>24+c.height));return ve(document.body).pipe(J("height"),x(c=>P(()=>{let s=[];return L([...n].reduce((u,[f,l])=>{for(;s.length&&n.get(s[s.length-1]).tagName>=l.tagName;)s.pop();let p=l.offsetTop;for(;!p&&l.parentElement;)l=l.parentElement,p=l.offsetTop;return u.set([...s=[...s,f]].reverse(),p)},new Map))}).pipe(m(s=>new Map([...s].sort(([,u],[,f])=>u-f))),x(s=>Q([t,i]).pipe(jr(([u,f],[{offset:{y:l},size:p},d])=>{let h=l+p.height>=Math.floor(c.height);for(;f.length;){let[,b]=f[0];if(b-d=l&&!h)f=[u.pop(),...f];else break}return[u,f]},[[],[...s]]),Y((u,f)=>u[0]===f[0]&&u[1]===f[1])))))).pipe(m(([c,s])=>({prev:c.map(([u])=>u),next:s.map(([u])=>u)})),q({prev:[],next:[]}),Te(2,1),m(([c,s])=>c.prev.length{let n=new O;return n.subscribe(({prev:o,next:i})=>{for(let[a]of i)a.removeAttribute("data-md-state"),a.classList.remove("md-nav__link--active");for(let[a,[c]]of o.entries())c.setAttribute("data-md-state","blur"),c.classList.toggle("md-nav__link--active",a===o.length-1)}),ie("navigation.tracking")&&t.pipe(se(n.pipe(fe(1))),J("offset"),Be(250),Me(n)).subscribe(([,{prev:o}])=>{let i=Se(),a=o[o.length-1];if(a&&a.length){let[c]=a,{hash:s}=new URL(c.href);i.hash!==s&&(i.hash=s,history.replaceState({},"",`${i}`))}else i.hash="",history.replaceState({},"",`${i}`)}),Cs(e,{viewport$:t,header$:r}).pipe(S(o=>n.next(o)),R(()=>n.complete()),m(o=>$({ref:e},o)))})}function Rs(e,{viewport$:t,main$:r,target$:n}){let o=t.pipe(m(({offset:{y:a}})=>a),Te(2,1),m(([a,c])=>a>c&&c>0),Y()),i=r.pipe(m(({active:a})=>a));return Q([i,o]).pipe(m(([a,c])=>!(a&&c)),Y(),se(n.pipe(ut(1))),Zt(!0),$r({delay:250}),m(a=>({hidden:a})))}function Ii(e,{viewport$:t,header$:r,main$:n,target$:o}){let i=new O;return i.subscribe({next({hidden:a}){a?(e.setAttribute("data-md-state","hidden"),e.setAttribute("tabindex","-1"),e.blur()):(e.removeAttribute("data-md-state"),e.removeAttribute("tabindex"))},complete(){e.style.top="",e.setAttribute("data-md-state","hidden"),e.removeAttribute("tabindex")}}),r.pipe(se(i.pipe(Zt(0),fe(1))),J("height")).subscribe(({height:a})=>{e.style.top=`${a+16}px`}),Rs(e,{viewport$:t,main$:n,target$:o}).pipe(S(a=>i.next(a)),R(()=>i.complete()),m(a=>$({ref:e},a)))}function $i({document$:e,tablet$:t}){e.pipe(x(()=>L(...G("[data-md-state=indeterminate]"))),S(r=>{r.indeterminate=!0,r.checked=!1}),oe(r=>y(r,"change").pipe(Wr(()=>r.hasAttribute("data-md-state")),Z(r))),Me(t)).subscribe(([r,n])=>{r.removeAttribute("data-md-state"),n&&(r.checked=!1)})}function ks(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function ji({document$:e}){e.pipe(x(()=>L(...G("[data-md-scrollfix]"))),S(t=>t.removeAttribute("data-md-scrollfix")),M(ks),oe(t=>y(t,"touchstart").pipe(Z(t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Fi({viewport$:e,tablet$:t}){Q([sr("search"),t]).pipe(m(([r,n])=>r&&!n),x(r=>L(r).pipe(Ie(r?400:100))),Me(e)).subscribe(([r,{offset:{y:n}}])=>{if(r)document.body.setAttribute("data-md-state","lock"),document.body.style.top=`-${n}px`;else{let o=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-state"),document.body.style.top="",o&&window.scrollTo(0,o)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let n=e[r];typeof n!="object"?n=document.createTextNode(n):n.parentNode&&n.parentNode.removeChild(n),r?t.insertBefore(this.previousSibling,n):t.replaceChild(n,this)}}}));document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var dt=mo(),hr=Lo(),dr=Ho(),tn=Mo(),we=Do(),br=qr("(min-width: 960px)"),Wi=qr("(min-width: 1220px)"),Di=Po(),Vi=me(),Ni=document.forms.namedItem("search")?(__search==null?void 0:__search.index)||Ce(new URL("search/search_index.json",Vi.base)):xe,rn=new O;hi({alert$:rn});ie("navigation.instant")&&bi({document$:dt,location$:hr,viewport$:we});var Ui;((Ui=Vi.version)==null?void 0:Ui.provider)==="mike"&&wi();C(hr,dr).pipe(Ie(125)).subscribe(()=>{Ne("drawer",!1),Ne("search",!1)});tn.pipe(M(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=ce("[href][rel=prev]");typeof t!="undefined"&&t.click();break;case"n":case".":let r=ce("[href][rel=next]");typeof r!="undefined"&&r.click();break}});$i({document$:dt,tablet$:br});ji({document$:dt});Fi({viewport$:we,tablet$:br});var ze=fi(Re("header"),{viewport$:we}),mr=dt.pipe(m(()=>Re("main")),x(e=>mi(e,{viewport$:we,header$:ze})),X(1)),Hs=C(...ne("dialog").map(e=>ui(e,{alert$:rn})),...ne("header").map(e=>pi(e,{viewport$:we,header$:ze,main$:mr})),...ne("palette").map(e=>di(e)),...ne("search").map(e=>Mi(e,{index$:Ni,keyboard$:tn})),...ne("source").map(e=>ki(e))),Ps=P(()=>C(...ne("content").map(e=>ci(e,{target$:dr,print$:Di})),...ne("content").map(e=>ie("search.highlight")?Li(e,{index$:Ni,location$:hr}):z),...ne("header-title").map(e=>li(e,{viewport$:we,header$:ze})),...ne("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Qr(Wi,()=>en(e,{viewport$:we,header$:ze,main$:mr})):Qr(br,()=>en(e,{viewport$:we,header$:ze,main$:mr}))),...ne("tabs").map(e=>Hi(e,{viewport$:we,header$:ze})),...ne("toc").map(e=>Pi(e,{viewport$:we,header$:ze})),...ne("top").map(e=>Ii(e,{viewport$:we,header$:ze,main$:mr,target$:dr})))),zi=dt.pipe(x(()=>Ps),Ge(Hs),X(1));zi.subscribe();window.document$=dt;window.location$=hr;window.target$=dr;window.keyboard$=tn;window.viewport$=we;window.tablet$=br;window.screen$=Wi;window.print$=Di;window.alert$=rn;window.component$=zi;})(); +//# sourceMappingURL=bundle.8aa65030.min.js.map + diff --git a/site/assets/javascripts/bundle.8aa65030.min.js.map b/site/assets/javascripts/bundle.8aa65030.min.js.map new file mode 100644 index 0000000000..f8af3d8afd --- /dev/null +++ b/site/assets/javascripts/bundle.8aa65030.min.js.map @@ -0,0 +1,8 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/url-polyfill/url-polyfill.js", "node_modules/rxjs/node_modules/tslib/tslib.js", "node_modules/clipboard/dist/clipboard.js", "node_modules/escape-html/index.js", "node_modules/array-flat-polyfill/index.mjs", "src/assets/javascripts/bundle.ts", "node_modules/unfetch/polyfill/index.js", "node_modules/rxjs/node_modules/tslib/modules/index.js", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/concatMap.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/sample.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/switchMapTo.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/assets/javascripts/browser/document/index.ts", "src/assets/javascripts/browser/element/_/index.ts", "src/assets/javascripts/browser/element/focus/index.ts", "src/assets/javascripts/browser/element/offset/_/index.ts", "src/assets/javascripts/browser/element/offset/content/index.ts", "node_modules/resize-observer-polyfill/dist/ResizeObserver.es.js", "src/assets/javascripts/browser/element/size/_/index.ts", "src/assets/javascripts/browser/element/size/content/index.ts", "src/assets/javascripts/browser/element/visibility/index.ts", "src/assets/javascripts/browser/toggle/index.ts", "src/assets/javascripts/browser/keyboard/index.ts", "src/assets/javascripts/browser/location/_/index.ts", "src/assets/javascripts/utilities/h/index.ts", "src/assets/javascripts/utilities/string/index.ts", "src/assets/javascripts/browser/location/hash/index.ts", "src/assets/javascripts/browser/media/index.ts", "src/assets/javascripts/browser/request/index.ts", "src/assets/javascripts/browser/script/index.ts", "src/assets/javascripts/browser/viewport/offset/index.ts", "src/assets/javascripts/browser/viewport/size/index.ts", "src/assets/javascripts/browser/viewport/_/index.ts", "src/assets/javascripts/browser/viewport/at/index.ts", "src/assets/javascripts/browser/worker/index.ts", "src/assets/javascripts/_/index.ts", "src/assets/javascripts/components/_/index.ts", "src/assets/javascripts/components/content/code/_/index.ts", "src/assets/javascripts/templates/annotation/index.tsx", "src/assets/javascripts/templates/clipboard/index.tsx", "src/assets/javascripts/templates/search/index.tsx", "src/assets/javascripts/templates/source/index.tsx", "src/assets/javascripts/templates/table/index.tsx", "src/assets/javascripts/templates/version/index.tsx", "src/assets/javascripts/components/content/annotation/_/index.ts", "src/assets/javascripts/components/content/annotation/list/index.ts", "src/assets/javascripts/components/content/code/mermaid/index.ts", "src/assets/javascripts/components/content/details/index.ts", "src/assets/javascripts/components/content/table/index.ts", "src/assets/javascripts/components/content/tabs/index.ts", "src/assets/javascripts/components/content/_/index.ts", "src/assets/javascripts/components/dialog/index.ts", "src/assets/javascripts/components/header/_/index.ts", "src/assets/javascripts/components/header/title/index.ts", "src/assets/javascripts/components/main/index.ts", "src/assets/javascripts/components/palette/index.ts", "src/assets/javascripts/integrations/clipboard/index.ts", "src/assets/javascripts/integrations/sitemap/index.ts", "src/assets/javascripts/integrations/instant/index.ts", "src/assets/javascripts/integrations/search/document/index.ts", "src/assets/javascripts/integrations/search/highlighter/index.ts", "src/assets/javascripts/integrations/search/query/transform/index.ts", "src/assets/javascripts/integrations/search/worker/message/index.ts", "src/assets/javascripts/integrations/search/worker/_/index.ts", "src/assets/javascripts/integrations/version/index.ts", "src/assets/javascripts/components/search/query/index.ts", "src/assets/javascripts/components/search/result/index.ts", "src/assets/javascripts/components/search/share/index.ts", "src/assets/javascripts/components/search/suggest/index.ts", "src/assets/javascripts/components/search/_/index.ts", "src/assets/javascripts/components/search/highlight/index.ts", "src/assets/javascripts/components/sidebar/index.ts", "src/assets/javascripts/components/source/facts/github/index.ts", "src/assets/javascripts/components/source/facts/gitlab/index.ts", "src/assets/javascripts/components/source/facts/_/index.ts", "src/assets/javascripts/components/source/_/index.ts", "src/assets/javascripts/components/tabs/index.ts", "src/assets/javascripts/components/toc/index.ts", "src/assets/javascripts/components/top/index.ts", "src/assets/javascripts/patches/indeterminate/index.ts", "src/assets/javascripts/patches/scrollfix/index.ts", "src/assets/javascripts/patches/scrolllock/index.ts", "src/assets/javascripts/polyfills/index.ts"], + "sourceRoot": "../../../..", + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "(function(global) {\r\n /**\r\n * Polyfill URLSearchParams\r\n *\r\n * Inspired from : https://github.com/WebReflection/url-search-params/blob/master/src/url-search-params.js\r\n */\r\n\r\n var checkIfIteratorIsSupported = function() {\r\n try {\r\n return !!Symbol.iterator;\r\n } catch (error) {\r\n return false;\r\n }\r\n };\r\n\r\n\r\n var iteratorSupported = checkIfIteratorIsSupported();\r\n\r\n var createIterator = function(items) {\r\n var iterator = {\r\n next: function() {\r\n var value = items.shift();\r\n return { done: value === void 0, value: value };\r\n }\r\n };\r\n\r\n if (iteratorSupported) {\r\n iterator[Symbol.iterator] = function() {\r\n return iterator;\r\n };\r\n }\r\n\r\n return iterator;\r\n };\r\n\r\n /**\r\n * Search param name and values should be encoded according to https://url.spec.whatwg.org/#urlencoded-serializing\r\n * encodeURIComponent() produces the same result except encoding spaces as `%20` instead of `+`.\r\n */\r\n var serializeParam = function(value) {\r\n return encodeURIComponent(value).replace(/%20/g, '+');\r\n };\r\n\r\n var deserializeParam = function(value) {\r\n return decodeURIComponent(String(value).replace(/\\+/g, ' '));\r\n };\r\n\r\n var polyfillURLSearchParams = function() {\r\n\r\n var URLSearchParams = function(searchString) {\r\n Object.defineProperty(this, '_entries', { writable: true, value: {} });\r\n var typeofSearchString = typeof searchString;\r\n\r\n if (typeofSearchString === 'undefined') {\r\n // do nothing\r\n } else if (typeofSearchString === 'string') {\r\n if (searchString !== '') {\r\n this._fromString(searchString);\r\n }\r\n } else if (searchString instanceof URLSearchParams) {\r\n var _this = this;\r\n searchString.forEach(function(value, name) {\r\n _this.append(name, value);\r\n });\r\n } else if ((searchString !== null) && (typeofSearchString === 'object')) {\r\n if (Object.prototype.toString.call(searchString) === '[object Array]') {\r\n for (var i = 0; i < searchString.length; i++) {\r\n var entry = searchString[i];\r\n if ((Object.prototype.toString.call(entry) === '[object Array]') || (entry.length !== 2)) {\r\n this.append(entry[0], entry[1]);\r\n } else {\r\n throw new TypeError('Expected [string, any] as entry at index ' + i + ' of URLSearchParams\\'s input');\r\n }\r\n }\r\n } else {\r\n for (var key in searchString) {\r\n if (searchString.hasOwnProperty(key)) {\r\n this.append(key, searchString[key]);\r\n }\r\n }\r\n }\r\n } else {\r\n throw new TypeError('Unsupported input\\'s type for URLSearchParams');\r\n }\r\n };\r\n\r\n var proto = URLSearchParams.prototype;\r\n\r\n proto.append = function(name, value) {\r\n if (name in this._entries) {\r\n this._entries[name].push(String(value));\r\n } else {\r\n this._entries[name] = [String(value)];\r\n }\r\n };\r\n\r\n proto.delete = function(name) {\r\n delete this._entries[name];\r\n };\r\n\r\n proto.get = function(name) {\r\n return (name in this._entries) ? this._entries[name][0] : null;\r\n };\r\n\r\n proto.getAll = function(name) {\r\n return (name in this._entries) ? this._entries[name].slice(0) : [];\r\n };\r\n\r\n proto.has = function(name) {\r\n return (name in this._entries);\r\n };\r\n\r\n proto.set = function(name, value) {\r\n this._entries[name] = [String(value)];\r\n };\r\n\r\n proto.forEach = function(callback, thisArg) {\r\n var entries;\r\n for (var name in this._entries) {\r\n if (this._entries.hasOwnProperty(name)) {\r\n entries = this._entries[name];\r\n for (var i = 0; i < entries.length; i++) {\r\n callback.call(thisArg, entries[i], name, this);\r\n }\r\n }\r\n }\r\n };\r\n\r\n proto.keys = function() {\r\n var items = [];\r\n this.forEach(function(value, name) {\r\n items.push(name);\r\n });\r\n return createIterator(items);\r\n };\r\n\r\n proto.values = function() {\r\n var items = [];\r\n this.forEach(function(value) {\r\n items.push(value);\r\n });\r\n return createIterator(items);\r\n };\r\n\r\n proto.entries = function() {\r\n var items = [];\r\n this.forEach(function(value, name) {\r\n items.push([name, value]);\r\n });\r\n return createIterator(items);\r\n };\r\n\r\n if (iteratorSupported) {\r\n proto[Symbol.iterator] = proto.entries;\r\n }\r\n\r\n proto.toString = function() {\r\n var searchArray = [];\r\n this.forEach(function(value, name) {\r\n searchArray.push(serializeParam(name) + '=' + serializeParam(value));\r\n });\r\n return searchArray.join('&');\r\n };\r\n\r\n\r\n global.URLSearchParams = URLSearchParams;\r\n };\r\n\r\n var checkIfURLSearchParamsSupported = function() {\r\n try {\r\n var URLSearchParams = global.URLSearchParams;\r\n\r\n return (\r\n (new URLSearchParams('?a=1').toString() === 'a=1') &&\r\n (typeof URLSearchParams.prototype.set === 'function') &&\r\n (typeof URLSearchParams.prototype.entries === 'function')\r\n );\r\n } catch (e) {\r\n return false;\r\n }\r\n };\r\n\r\n if (!checkIfURLSearchParamsSupported()) {\r\n polyfillURLSearchParams();\r\n }\r\n\r\n var proto = global.URLSearchParams.prototype;\r\n\r\n if (typeof proto.sort !== 'function') {\r\n proto.sort = function() {\r\n var _this = this;\r\n var items = [];\r\n this.forEach(function(value, name) {\r\n items.push([name, value]);\r\n if (!_this._entries) {\r\n _this.delete(name);\r\n }\r\n });\r\n items.sort(function(a, b) {\r\n if (a[0] < b[0]) {\r\n return -1;\r\n } else if (a[0] > b[0]) {\r\n return +1;\r\n } else {\r\n return 0;\r\n }\r\n });\r\n if (_this._entries) { // force reset because IE keeps keys index\r\n _this._entries = {};\r\n }\r\n for (var i = 0; i < items.length; i++) {\r\n this.append(items[i][0], items[i][1]);\r\n }\r\n };\r\n }\r\n\r\n if (typeof proto._fromString !== 'function') {\r\n Object.defineProperty(proto, '_fromString', {\r\n enumerable: false,\r\n configurable: false,\r\n writable: false,\r\n value: function(searchString) {\r\n if (this._entries) {\r\n this._entries = {};\r\n } else {\r\n var keys = [];\r\n this.forEach(function(value, name) {\r\n keys.push(name);\r\n });\r\n for (var i = 0; i < keys.length; i++) {\r\n this.delete(keys[i]);\r\n }\r\n }\r\n\r\n searchString = searchString.replace(/^\\?/, '');\r\n var attributes = searchString.split('&');\r\n var attribute;\r\n for (var i = 0; i < attributes.length; i++) {\r\n attribute = attributes[i].split('=');\r\n this.append(\r\n deserializeParam(attribute[0]),\r\n (attribute.length > 1) ? deserializeParam(attribute[1]) : ''\r\n );\r\n }\r\n }\r\n });\r\n }\r\n\r\n // HTMLAnchorElement\r\n\r\n})(\r\n (typeof global !== 'undefined') ? global\r\n : ((typeof window !== 'undefined') ? window\r\n : ((typeof self !== 'undefined') ? self : this))\r\n);\r\n\r\n(function(global) {\r\n /**\r\n * Polyfill URL\r\n *\r\n * Inspired from : https://github.com/arv/DOM-URL-Polyfill/blob/master/src/url.js\r\n */\r\n\r\n var checkIfURLIsSupported = function() {\r\n try {\r\n var u = new global.URL('b', 'http://a');\r\n u.pathname = 'c d';\r\n return (u.href === 'http://a/c%20d') && u.searchParams;\r\n } catch (e) {\r\n return false;\r\n }\r\n };\r\n\r\n\r\n var polyfillURL = function() {\r\n var _URL = global.URL;\r\n\r\n var URL = function(url, base) {\r\n if (typeof url !== 'string') url = String(url);\r\n if (base && typeof base !== 'string') base = String(base);\r\n\r\n // Only create another document if the base is different from current location.\r\n var doc = document, baseElement;\r\n if (base && (global.location === void 0 || base !== global.location.href)) {\r\n base = base.toLowerCase();\r\n doc = document.implementation.createHTMLDocument('');\r\n baseElement = doc.createElement('base');\r\n baseElement.href = base;\r\n doc.head.appendChild(baseElement);\r\n try {\r\n if (baseElement.href.indexOf(base) !== 0) throw new Error(baseElement.href);\r\n } catch (err) {\r\n throw new Error('URL unable to set base ' + base + ' due to ' + err);\r\n }\r\n }\r\n\r\n var anchorElement = doc.createElement('a');\r\n anchorElement.href = url;\r\n if (baseElement) {\r\n doc.body.appendChild(anchorElement);\r\n anchorElement.href = anchorElement.href; // force href to refresh\r\n }\r\n\r\n var inputElement = doc.createElement('input');\r\n inputElement.type = 'url';\r\n inputElement.value = url;\r\n\r\n if (anchorElement.protocol === ':' || !/:/.test(anchorElement.href) || (!inputElement.checkValidity() && !base)) {\r\n throw new TypeError('Invalid URL');\r\n }\r\n\r\n Object.defineProperty(this, '_anchorElement', {\r\n value: anchorElement\r\n });\r\n\r\n\r\n // create a linked searchParams which reflect its changes on URL\r\n var searchParams = new global.URLSearchParams(this.search);\r\n var enableSearchUpdate = true;\r\n var enableSearchParamsUpdate = true;\r\n var _this = this;\r\n ['append', 'delete', 'set'].forEach(function(methodName) {\r\n var method = searchParams[methodName];\r\n searchParams[methodName] = function() {\r\n method.apply(searchParams, arguments);\r\n if (enableSearchUpdate) {\r\n enableSearchParamsUpdate = false;\r\n _this.search = searchParams.toString();\r\n enableSearchParamsUpdate = true;\r\n }\r\n };\r\n });\r\n\r\n Object.defineProperty(this, 'searchParams', {\r\n value: searchParams,\r\n enumerable: true\r\n });\r\n\r\n var search = void 0;\r\n Object.defineProperty(this, '_updateSearchParams', {\r\n enumerable: false,\r\n configurable: false,\r\n writable: false,\r\n value: function() {\r\n if (this.search !== search) {\r\n search = this.search;\r\n if (enableSearchParamsUpdate) {\r\n enableSearchUpdate = false;\r\n this.searchParams._fromString(this.search);\r\n enableSearchUpdate = true;\r\n }\r\n }\r\n }\r\n });\r\n };\r\n\r\n var proto = URL.prototype;\r\n\r\n var linkURLWithAnchorAttribute = function(attributeName) {\r\n Object.defineProperty(proto, attributeName, {\r\n get: function() {\r\n return this._anchorElement[attributeName];\r\n },\r\n set: function(value) {\r\n this._anchorElement[attributeName] = value;\r\n },\r\n enumerable: true\r\n });\r\n };\r\n\r\n ['hash', 'host', 'hostname', 'port', 'protocol']\r\n .forEach(function(attributeName) {\r\n linkURLWithAnchorAttribute(attributeName);\r\n });\r\n\r\n Object.defineProperty(proto, 'search', {\r\n get: function() {\r\n return this._anchorElement['search'];\r\n },\r\n set: function(value) {\r\n this._anchorElement['search'] = value;\r\n this._updateSearchParams();\r\n },\r\n enumerable: true\r\n });\r\n\r\n Object.defineProperties(proto, {\r\n\r\n 'toString': {\r\n get: function() {\r\n var _this = this;\r\n return function() {\r\n return _this.href;\r\n };\r\n }\r\n },\r\n\r\n 'href': {\r\n get: function() {\r\n return this._anchorElement.href.replace(/\\?$/, '');\r\n },\r\n set: function(value) {\r\n this._anchorElement.href = value;\r\n this._updateSearchParams();\r\n },\r\n enumerable: true\r\n },\r\n\r\n 'pathname': {\r\n get: function() {\r\n return this._anchorElement.pathname.replace(/(^\\/?)/, '/');\r\n },\r\n set: function(value) {\r\n this._anchorElement.pathname = value;\r\n },\r\n enumerable: true\r\n },\r\n\r\n 'origin': {\r\n get: function() {\r\n // get expected port from protocol\r\n var expectedPort = { 'http:': 80, 'https:': 443, 'ftp:': 21 }[this._anchorElement.protocol];\r\n // add port to origin if, expected port is different than actual port\r\n // and it is not empty f.e http://foo:8080\r\n // 8080 != 80 && 8080 != ''\r\n var addPortToOrigin = this._anchorElement.port != expectedPort &&\r\n this._anchorElement.port !== '';\r\n\r\n return this._anchorElement.protocol +\r\n '//' +\r\n this._anchorElement.hostname +\r\n (addPortToOrigin ? (':' + this._anchorElement.port) : '');\r\n },\r\n enumerable: true\r\n },\r\n\r\n 'password': { // TODO\r\n get: function() {\r\n return '';\r\n },\r\n set: function(value) {\r\n },\r\n enumerable: true\r\n },\r\n\r\n 'username': { // TODO\r\n get: function() {\r\n return '';\r\n },\r\n set: function(value) {\r\n },\r\n enumerable: true\r\n },\r\n });\r\n\r\n URL.createObjectURL = function(blob) {\r\n return _URL.createObjectURL.apply(_URL, arguments);\r\n };\r\n\r\n URL.revokeObjectURL = function(url) {\r\n return _URL.revokeObjectURL.apply(_URL, arguments);\r\n };\r\n\r\n global.URL = URL;\r\n\r\n };\r\n\r\n if (!checkIfURLIsSupported()) {\r\n polyfillURL();\r\n }\r\n\r\n if ((global.location !== void 0) && !('origin' in global.location)) {\r\n var getOrigin = function() {\r\n return global.location.protocol + '//' + global.location.hostname + (global.location.port ? (':' + global.location.port) : '');\r\n };\r\n\r\n try {\r\n Object.defineProperty(global.location, 'origin', {\r\n get: getOrigin,\r\n enumerable: true\r\n });\r\n } catch (e) {\r\n setInterval(function() {\r\n global.location.origin = getOrigin();\r\n }, 100);\r\n }\r\n }\r\n\r\n})(\r\n (typeof global !== 'undefined') ? global\r\n : ((typeof window !== 'undefined') ? window\r\n : ((typeof self !== 'undefined') ? self : this))\r\n);\r\n", "/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global global, define, System, Reflect, Promise */\r\nvar __extends;\r\nvar __assign;\r\nvar __rest;\r\nvar __decorate;\r\nvar __param;\r\nvar __metadata;\r\nvar __awaiter;\r\nvar __generator;\r\nvar __exportStar;\r\nvar __values;\r\nvar __read;\r\nvar __spread;\r\nvar __spreadArrays;\r\nvar __spreadArray;\r\nvar __await;\r\nvar __asyncGenerator;\r\nvar __asyncDelegator;\r\nvar __asyncValues;\r\nvar __makeTemplateObject;\r\nvar __importStar;\r\nvar __importDefault;\r\nvar __classPrivateFieldGet;\r\nvar __classPrivateFieldSet;\r\nvar __createBinding;\r\n(function (factory) {\r\n var root = typeof global === \"object\" ? global : typeof self === \"object\" ? self : typeof this === \"object\" ? this : {};\r\n if (typeof define === \"function\" && define.amd) {\r\n define(\"tslib\", [\"exports\"], function (exports) { factory(createExporter(root, createExporter(exports))); });\r\n }\r\n else if (typeof module === \"object\" && typeof module.exports === \"object\") {\r\n factory(createExporter(root, createExporter(module.exports)));\r\n }\r\n else {\r\n factory(createExporter(root));\r\n }\r\n function createExporter(exports, previous) {\r\n if (exports !== root) {\r\n if (typeof Object.create === \"function\") {\r\n Object.defineProperty(exports, \"__esModule\", { value: true });\r\n }\r\n else {\r\n exports.__esModule = true;\r\n }\r\n }\r\n return function (id, v) { return exports[id] = previous ? previous(id, v) : v; };\r\n }\r\n})\r\n(function (exporter) {\r\n var extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n\r\n __extends = function (d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n };\r\n\r\n __assign = Object.assign || function (t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n };\r\n\r\n __rest = function (s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n };\r\n\r\n __decorate = function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n };\r\n\r\n __param = function (paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n };\r\n\r\n __metadata = function (metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n };\r\n\r\n __awaiter = function (thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n };\r\n\r\n __generator = function (thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n };\r\n\r\n __exportStar = function(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n };\r\n\r\n __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n }) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n });\r\n\r\n __values = function (o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n };\r\n\r\n __read = function (o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n };\r\n\r\n /** @deprecated */\r\n __spread = function () {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n };\r\n\r\n /** @deprecated */\r\n __spreadArrays = function () {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n };\r\n\r\n __spreadArray = function (to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n };\r\n\r\n __await = function (v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n };\r\n\r\n __asyncGenerator = function (thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n };\r\n\r\n __asyncDelegator = function (o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n };\r\n\r\n __asyncValues = function (o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n };\r\n\r\n __makeTemplateObject = function (cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n };\r\n\r\n var __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n }) : function(o, v) {\r\n o[\"default\"] = v;\r\n };\r\n\r\n __importStar = function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n };\r\n\r\n __importDefault = function (mod) {\r\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n };\r\n\r\n __classPrivateFieldGet = function (receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n };\r\n\r\n __classPrivateFieldSet = function (receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n };\r\n\r\n exporter(\"__extends\", __extends);\r\n exporter(\"__assign\", __assign);\r\n exporter(\"__rest\", __rest);\r\n exporter(\"__decorate\", __decorate);\r\n exporter(\"__param\", __param);\r\n exporter(\"__metadata\", __metadata);\r\n exporter(\"__awaiter\", __awaiter);\r\n exporter(\"__generator\", __generator);\r\n exporter(\"__exportStar\", __exportStar);\r\n exporter(\"__createBinding\", __createBinding);\r\n exporter(\"__values\", __values);\r\n exporter(\"__read\", __read);\r\n exporter(\"__spread\", __spread);\r\n exporter(\"__spreadArrays\", __spreadArrays);\r\n exporter(\"__spreadArray\", __spreadArray);\r\n exporter(\"__await\", __await);\r\n exporter(\"__asyncGenerator\", __asyncGenerator);\r\n exporter(\"__asyncDelegator\", __asyncDelegator);\r\n exporter(\"__asyncValues\", __asyncValues);\r\n exporter(\"__makeTemplateObject\", __makeTemplateObject);\r\n exporter(\"__importStar\", __importStar);\r\n exporter(\"__importDefault\", __importDefault);\r\n exporter(\"__classPrivateFieldGet\", __classPrivateFieldGet);\r\n exporter(\"__classPrivateFieldSet\", __classPrivateFieldSet);\r\n});\r\n", "/*!\n * clipboard.js v2.0.10\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n var fakeElement = createFakeElement(target);\n options.container.appendChild(fakeElement);\n selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n document.activeElement.blur();\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "Array.prototype.flat||Object.defineProperty(Array.prototype,\"flat\",{configurable:!0,value:function r(){var t=isNaN(arguments[0])?1:Number(arguments[0]);return t?Array.prototype.reduce.call(this,function(a,e){return Array.isArray(e)?a.push.apply(a,r.call(e,t-1)):a.push(e),a},[]):Array.prototype.slice.call(this)},writable:!0}),Array.prototype.flatMap||Object.defineProperty(Array.prototype,\"flatMap\",{configurable:!0,value:function(r){return Array.prototype.map.apply(this,arguments).flat()},writable:!0})\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"array-flat-polyfill\"\nimport \"focus-visible\"\nimport \"unfetch/polyfill\"\nimport \"url-polyfill\"\n\nimport {\n EMPTY,\n NEVER,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getOptionalElement,\n requestJSON,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountBackToTop,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantLoading,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget()\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? __search?.index || requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up instant loading, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantLoading({ document$, location$, viewport$ })\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector()\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"[href][rel=prev]\")\n if (typeof prev !== \"undefined\")\n prev.click()\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"[href][rel=next]\")\n if (typeof next !== \"undefined\")\n next.click()\n break\n }\n })\n\n/* Set up patches */\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, { viewport$, header$ })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.component$ = component$ /* Component observable */\n", "self.fetch||(self.fetch=function(e,n){return n=n||{},new Promise(function(t,s){var r=new XMLHttpRequest,o=[],u=[],i={},a=function(){return{ok:2==(r.status/100|0),statusText:r.statusText,status:r.status,url:r.responseURL,text:function(){return Promise.resolve(r.responseText)},json:function(){return Promise.resolve(r.responseText).then(JSON.parse)},blob:function(){return Promise.resolve(new Blob([r.response]))},clone:a,headers:{keys:function(){return o},entries:function(){return u},get:function(e){return i[e.toLowerCase()]},has:function(e){return e.toLowerCase()in i}}}};for(var c in r.open(n.method||\"get\",e,!0),r.onload=function(){r.getAllResponseHeaders().replace(/^(.*?):[^\\S\\n]*([\\s\\S]*?)$/gm,function(e,n,t){o.push(n=n.toLowerCase()),u.push([n,t]),i[n]=i[n]?i[n]+\",\"+t:t}),t(a())},r.onerror=s,r.withCredentials=\"include\"==n.credentials,n.headers)r.setRequestHeader(c,n.headers[c]);r.send(n.body||null)})});\n", "import tslib from '../tslib.js';\r\nconst {\r\n __extends,\r\n __assign,\r\n __rest,\r\n __decorate,\r\n __param,\r\n __metadata,\r\n __awaiter,\r\n __generator,\r\n __exportStar,\r\n __createBinding,\r\n __values,\r\n __read,\r\n __spread,\r\n __spreadArrays,\r\n __spreadArray,\r\n __await,\r\n __asyncGenerator,\r\n __asyncDelegator,\r\n __asyncValues,\r\n __makeTemplateObject,\r\n __importStar,\r\n __importDefault,\r\n __classPrivateFieldGet,\r\n __classPrivateFieldSet,\r\n} = tslib;\r\nexport {\r\n __extends,\r\n __assign,\r\n __rest,\r\n __decorate,\r\n __param,\r\n __metadata,\r\n __awaiter,\r\n __generator,\r\n __exportStar,\r\n __createBinding,\r\n __values,\r\n __read,\r\n __spread,\r\n __spreadArrays,\r\n __spreadArray,\r\n __await,\r\n __asyncGenerator,\r\n __asyncDelegator,\r\n __asyncValues,\r\n __makeTemplateObject,\r\n __importStar,\r\n __importDefault,\r\n __classPrivateFieldGet,\r\n __classPrivateFieldSet,\r\n};\r\n", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n ReplaySubject,\n Subject,\n fromEvent\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch document\n *\n * Documents are implemented as subjects, so all downstream observables are\n * automatically updated when a new document is emitted.\n *\n * @returns Document subject\n */\nexport function watchDocument(): Subject {\n const document$ = new ReplaySubject(1)\n fromEvent(document, \"DOMContentLoaded\", { once: true })\n .subscribe(() => document$.next(document))\n\n /* Return document */\n return document$\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve all elements matching the query selector\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Elements\n */\nexport function getElements(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T][]\n\nexport function getElements(\n selector: string, node?: ParentNode\n): T[]\n\nexport function getElements(\n selector: string, node: ParentNode = document\n): T[] {\n return Array.from(node.querySelectorAll(selector))\n}\n\n/**\n * Retrieve an element matching a query selector or throw a reference error\n *\n * Note that this function assumes that the element is present. If unsure if an\n * element is existent, use the `getOptionalElement` function instead.\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Element\n */\nexport function getElement(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T]\n\nexport function getElement(\n selector: string, node?: ParentNode\n): T\n\nexport function getElement(\n selector: string, node: ParentNode = document\n): T {\n const el = getOptionalElement(selector, node)\n if (typeof el === \"undefined\")\n throw new ReferenceError(\n `Missing element: expected \"${selector}\" to be present`\n )\n\n /* Return element */\n return el\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Retrieve an optional element matching the query selector\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Element or nothing\n */\nexport function getOptionalElement(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T] | undefined\n\nexport function getOptionalElement(\n selector: string, node?: ParentNode\n): T | undefined\n\nexport function getOptionalElement(\n selector: string, node: ParentNode = document\n): T | undefined {\n return node.querySelector(selector) || undefined\n}\n\n/**\n * Retrieve the currently active element\n *\n * @returns Element or nothing\n */\nexport function getActiveElement(): HTMLElement | undefined {\n return document.activeElement instanceof HTMLElement\n ? document.activeElement || undefined\n : undefined\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n debounceTime,\n distinctUntilChanged,\n fromEvent,\n map,\n merge,\n startWith\n} from \"rxjs\"\n\nimport { getActiveElement } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch element focus\n *\n * Previously, this function used `focus` and `blur` events to determine whether\n * an element is focused, but this doesn't work if there are focusable elements\n * within the elements itself. A better solutions are `focusin` and `focusout`\n * events, which bubble up the tree and allow for more fine-grained control.\n *\n * `debounceTime` is necessary, because when a focus change happens inside an\n * element, the observable would first emit `false` and then `true` again.\n *\n * @param el - Element\n *\n * @returns Element focus observable\n */\nexport function watchElementFocus(\n el: HTMLElement\n): Observable {\n return merge(\n fromEvent(document.body, \"focusin\"),\n fromEvent(document.body, \"focusout\")\n )\n .pipe(\n debounceTime(1),\n map(() => {\n const active = getActiveElement()\n return typeof active !== \"undefined\"\n ? el.contains(active)\n : false\n }),\n startWith(el === getActiveElement()),\n distinctUntilChanged()\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n animationFrameScheduler,\n auditTime,\n fromEvent,\n map,\n merge,\n startWith\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Element offset\n */\nexport interface ElementOffset {\n x: number /* Horizontal offset */\n y: number /* Vertical offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element offset\n *\n * @param el - Element\n *\n * @returns Element offset\n */\nexport function getElementOffset(\n el: HTMLElement\n): ElementOffset {\n return {\n x: el.offsetLeft,\n y: el.offsetTop\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element offset\n *\n * @param el - Element\n *\n * @returns Element offset observable\n */\nexport function watchElementOffset(\n el: HTMLElement\n): Observable {\n return merge(\n fromEvent(window, \"load\"),\n fromEvent(window, \"resize\")\n )\n .pipe(\n auditTime(0, animationFrameScheduler),\n map(() => getElementOffset(el)),\n startWith(getElementOffset(el))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n animationFrameScheduler,\n auditTime,\n fromEvent,\n map,\n merge,\n startWith\n} from \"rxjs\"\n\nimport { ElementOffset } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element content offset (= scroll offset)\n *\n * @param el - Element\n *\n * @returns Element content offset\n */\nexport function getElementContentOffset(\n el: HTMLElement\n): ElementOffset {\n return {\n x: el.scrollLeft,\n y: el.scrollTop\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element content offset\n *\n * @param el - Element\n *\n * @returns Element content offset observable\n */\nexport function watchElementContentOffset(\n el: HTMLElement\n): Observable {\n return merge(\n fromEvent(el, \"scroll\"),\n fromEvent(window, \"resize\")\n )\n .pipe(\n auditTime(0, animationFrameScheduler),\n map(() => getElementContentOffset(el)),\n startWith(getElementContentOffset(el))\n )\n}\n", "/**\r\n * A collection of shims that provide minimal functionality of the ES6 collections.\r\n *\r\n * These implementations are not meant to be used outside of the ResizeObserver\r\n * modules as they cover only a limited range of use cases.\r\n */\r\n/* eslint-disable require-jsdoc, valid-jsdoc */\r\nvar MapShim = (function () {\r\n if (typeof Map !== 'undefined') {\r\n return Map;\r\n }\r\n /**\r\n * Returns index in provided array that matches the specified key.\r\n *\r\n * @param {Array} arr\r\n * @param {*} key\r\n * @returns {number}\r\n */\r\n function getIndex(arr, key) {\r\n var result = -1;\r\n arr.some(function (entry, index) {\r\n if (entry[0] === key) {\r\n result = index;\r\n return true;\r\n }\r\n return false;\r\n });\r\n return result;\r\n }\r\n return /** @class */ (function () {\r\n function class_1() {\r\n this.__entries__ = [];\r\n }\r\n Object.defineProperty(class_1.prototype, \"size\", {\r\n /**\r\n * @returns {boolean}\r\n */\r\n get: function () {\r\n return this.__entries__.length;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n /**\r\n * @param {*} key\r\n * @returns {*}\r\n */\r\n class_1.prototype.get = function (key) {\r\n var index = getIndex(this.__entries__, key);\r\n var entry = this.__entries__[index];\r\n return entry && entry[1];\r\n };\r\n /**\r\n * @param {*} key\r\n * @param {*} value\r\n * @returns {void}\r\n */\r\n class_1.prototype.set = function (key, value) {\r\n var index = getIndex(this.__entries__, key);\r\n if (~index) {\r\n this.__entries__[index][1] = value;\r\n }\r\n else {\r\n this.__entries__.push([key, value]);\r\n }\r\n };\r\n /**\r\n * @param {*} key\r\n * @returns {void}\r\n */\r\n class_1.prototype.delete = function (key) {\r\n var entries = this.__entries__;\r\n var index = getIndex(entries, key);\r\n if (~index) {\r\n entries.splice(index, 1);\r\n }\r\n };\r\n /**\r\n * @param {*} key\r\n * @returns {void}\r\n */\r\n class_1.prototype.has = function (key) {\r\n return !!~getIndex(this.__entries__, key);\r\n };\r\n /**\r\n * @returns {void}\r\n */\r\n class_1.prototype.clear = function () {\r\n this.__entries__.splice(0);\r\n };\r\n /**\r\n * @param {Function} callback\r\n * @param {*} [ctx=null]\r\n * @returns {void}\r\n */\r\n class_1.prototype.forEach = function (callback, ctx) {\r\n if (ctx === void 0) { ctx = null; }\r\n for (var _i = 0, _a = this.__entries__; _i < _a.length; _i++) {\r\n var entry = _a[_i];\r\n callback.call(ctx, entry[1], entry[0]);\r\n }\r\n };\r\n return class_1;\r\n }());\r\n})();\n\n/**\r\n * Detects whether window and document objects are available in current environment.\r\n */\r\nvar isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && window.document === document;\n\n// Returns global object of a current environment.\r\nvar global$1 = (function () {\r\n if (typeof global !== 'undefined' && global.Math === Math) {\r\n return global;\r\n }\r\n if (typeof self !== 'undefined' && self.Math === Math) {\r\n return self;\r\n }\r\n if (typeof window !== 'undefined' && window.Math === Math) {\r\n return window;\r\n }\r\n // eslint-disable-next-line no-new-func\r\n return Function('return this')();\r\n})();\n\n/**\r\n * A shim for the requestAnimationFrame which falls back to the setTimeout if\r\n * first one is not supported.\r\n *\r\n * @returns {number} Requests' identifier.\r\n */\r\nvar requestAnimationFrame$1 = (function () {\r\n if (typeof requestAnimationFrame === 'function') {\r\n // It's required to use a bounded function because IE sometimes throws\r\n // an \"Invalid calling object\" error if rAF is invoked without the global\r\n // object on the left hand side.\r\n return requestAnimationFrame.bind(global$1);\r\n }\r\n return function (callback) { return setTimeout(function () { return callback(Date.now()); }, 1000 / 60); };\r\n})();\n\n// Defines minimum timeout before adding a trailing call.\r\nvar trailingTimeout = 2;\r\n/**\r\n * Creates a wrapper function which ensures that provided callback will be\r\n * invoked only once during the specified delay period.\r\n *\r\n * @param {Function} callback - Function to be invoked after the delay period.\r\n * @param {number} delay - Delay after which to invoke callback.\r\n * @returns {Function}\r\n */\r\nfunction throttle (callback, delay) {\r\n var leadingCall = false, trailingCall = false, lastCallTime = 0;\r\n /**\r\n * Invokes the original callback function and schedules new invocation if\r\n * the \"proxy\" was called during current request.\r\n *\r\n * @returns {void}\r\n */\r\n function resolvePending() {\r\n if (leadingCall) {\r\n leadingCall = false;\r\n callback();\r\n }\r\n if (trailingCall) {\r\n proxy();\r\n }\r\n }\r\n /**\r\n * Callback invoked after the specified delay. It will further postpone\r\n * invocation of the original function delegating it to the\r\n * requestAnimationFrame.\r\n *\r\n * @returns {void}\r\n */\r\n function timeoutCallback() {\r\n requestAnimationFrame$1(resolvePending);\r\n }\r\n /**\r\n * Schedules invocation of the original function.\r\n *\r\n * @returns {void}\r\n */\r\n function proxy() {\r\n var timeStamp = Date.now();\r\n if (leadingCall) {\r\n // Reject immediately following calls.\r\n if (timeStamp - lastCallTime < trailingTimeout) {\r\n return;\r\n }\r\n // Schedule new call to be in invoked when the pending one is resolved.\r\n // This is important for \"transitions\" which never actually start\r\n // immediately so there is a chance that we might miss one if change\r\n // happens amids the pending invocation.\r\n trailingCall = true;\r\n }\r\n else {\r\n leadingCall = true;\r\n trailingCall = false;\r\n setTimeout(timeoutCallback, delay);\r\n }\r\n lastCallTime = timeStamp;\r\n }\r\n return proxy;\r\n}\n\n// Minimum delay before invoking the update of observers.\r\nvar REFRESH_DELAY = 20;\r\n// A list of substrings of CSS properties used to find transition events that\r\n// might affect dimensions of observed elements.\r\nvar transitionKeys = ['top', 'right', 'bottom', 'left', 'width', 'height', 'size', 'weight'];\r\n// Check if MutationObserver is available.\r\nvar mutationObserverSupported = typeof MutationObserver !== 'undefined';\r\n/**\r\n * Singleton controller class which handles updates of ResizeObserver instances.\r\n */\r\nvar ResizeObserverController = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of ResizeObserverController.\r\n *\r\n * @private\r\n */\r\n function ResizeObserverController() {\r\n /**\r\n * Indicates whether DOM listeners have been added.\r\n *\r\n * @private {boolean}\r\n */\r\n this.connected_ = false;\r\n /**\r\n * Tells that controller has subscribed for Mutation Events.\r\n *\r\n * @private {boolean}\r\n */\r\n this.mutationEventsAdded_ = false;\r\n /**\r\n * Keeps reference to the instance of MutationObserver.\r\n *\r\n * @private {MutationObserver}\r\n */\r\n this.mutationsObserver_ = null;\r\n /**\r\n * A list of connected observers.\r\n *\r\n * @private {Array}\r\n */\r\n this.observers_ = [];\r\n this.onTransitionEnd_ = this.onTransitionEnd_.bind(this);\r\n this.refresh = throttle(this.refresh.bind(this), REFRESH_DELAY);\r\n }\r\n /**\r\n * Adds observer to observers list.\r\n *\r\n * @param {ResizeObserverSPI} observer - Observer to be added.\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.addObserver = function (observer) {\r\n if (!~this.observers_.indexOf(observer)) {\r\n this.observers_.push(observer);\r\n }\r\n // Add listeners if they haven't been added yet.\r\n if (!this.connected_) {\r\n this.connect_();\r\n }\r\n };\r\n /**\r\n * Removes observer from observers list.\r\n *\r\n * @param {ResizeObserverSPI} observer - Observer to be removed.\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.removeObserver = function (observer) {\r\n var observers = this.observers_;\r\n var index = observers.indexOf(observer);\r\n // Remove observer if it's present in registry.\r\n if (~index) {\r\n observers.splice(index, 1);\r\n }\r\n // Remove listeners if controller has no connected observers.\r\n if (!observers.length && this.connected_) {\r\n this.disconnect_();\r\n }\r\n };\r\n /**\r\n * Invokes the update of observers. It will continue running updates insofar\r\n * it detects changes.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.refresh = function () {\r\n var changesDetected = this.updateObservers_();\r\n // Continue running updates if changes have been detected as there might\r\n // be future ones caused by CSS transitions.\r\n if (changesDetected) {\r\n this.refresh();\r\n }\r\n };\r\n /**\r\n * Updates every observer from observers list and notifies them of queued\r\n * entries.\r\n *\r\n * @private\r\n * @returns {boolean} Returns \"true\" if any observer has detected changes in\r\n * dimensions of it's elements.\r\n */\r\n ResizeObserverController.prototype.updateObservers_ = function () {\r\n // Collect observers that have active observations.\r\n var activeObservers = this.observers_.filter(function (observer) {\r\n return observer.gatherActive(), observer.hasActive();\r\n });\r\n // Deliver notifications in a separate cycle in order to avoid any\r\n // collisions between observers, e.g. when multiple instances of\r\n // ResizeObserver are tracking the same element and the callback of one\r\n // of them changes content dimensions of the observed target. Sometimes\r\n // this may result in notifications being blocked for the rest of observers.\r\n activeObservers.forEach(function (observer) { return observer.broadcastActive(); });\r\n return activeObservers.length > 0;\r\n };\r\n /**\r\n * Initializes DOM listeners.\r\n *\r\n * @private\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.connect_ = function () {\r\n // Do nothing if running in a non-browser environment or if listeners\r\n // have been already added.\r\n if (!isBrowser || this.connected_) {\r\n return;\r\n }\r\n // Subscription to the \"Transitionend\" event is used as a workaround for\r\n // delayed transitions. This way it's possible to capture at least the\r\n // final state of an element.\r\n document.addEventListener('transitionend', this.onTransitionEnd_);\r\n window.addEventListener('resize', this.refresh);\r\n if (mutationObserverSupported) {\r\n this.mutationsObserver_ = new MutationObserver(this.refresh);\r\n this.mutationsObserver_.observe(document, {\r\n attributes: true,\r\n childList: true,\r\n characterData: true,\r\n subtree: true\r\n });\r\n }\r\n else {\r\n document.addEventListener('DOMSubtreeModified', this.refresh);\r\n this.mutationEventsAdded_ = true;\r\n }\r\n this.connected_ = true;\r\n };\r\n /**\r\n * Removes DOM listeners.\r\n *\r\n * @private\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.disconnect_ = function () {\r\n // Do nothing if running in a non-browser environment or if listeners\r\n // have been already removed.\r\n if (!isBrowser || !this.connected_) {\r\n return;\r\n }\r\n document.removeEventListener('transitionend', this.onTransitionEnd_);\r\n window.removeEventListener('resize', this.refresh);\r\n if (this.mutationsObserver_) {\r\n this.mutationsObserver_.disconnect();\r\n }\r\n if (this.mutationEventsAdded_) {\r\n document.removeEventListener('DOMSubtreeModified', this.refresh);\r\n }\r\n this.mutationsObserver_ = null;\r\n this.mutationEventsAdded_ = false;\r\n this.connected_ = false;\r\n };\r\n /**\r\n * \"Transitionend\" event handler.\r\n *\r\n * @private\r\n * @param {TransitionEvent} event\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.onTransitionEnd_ = function (_a) {\r\n var _b = _a.propertyName, propertyName = _b === void 0 ? '' : _b;\r\n // Detect whether transition may affect dimensions of an element.\r\n var isReflowProperty = transitionKeys.some(function (key) {\r\n return !!~propertyName.indexOf(key);\r\n });\r\n if (isReflowProperty) {\r\n this.refresh();\r\n }\r\n };\r\n /**\r\n * Returns instance of the ResizeObserverController.\r\n *\r\n * @returns {ResizeObserverController}\r\n */\r\n ResizeObserverController.getInstance = function () {\r\n if (!this.instance_) {\r\n this.instance_ = new ResizeObserverController();\r\n }\r\n return this.instance_;\r\n };\r\n /**\r\n * Holds reference to the controller's instance.\r\n *\r\n * @private {ResizeObserverController}\r\n */\r\n ResizeObserverController.instance_ = null;\r\n return ResizeObserverController;\r\n}());\n\n/**\r\n * Defines non-writable/enumerable properties of the provided target object.\r\n *\r\n * @param {Object} target - Object for which to define properties.\r\n * @param {Object} props - Properties to be defined.\r\n * @returns {Object} Target object.\r\n */\r\nvar defineConfigurable = (function (target, props) {\r\n for (var _i = 0, _a = Object.keys(props); _i < _a.length; _i++) {\r\n var key = _a[_i];\r\n Object.defineProperty(target, key, {\r\n value: props[key],\r\n enumerable: false,\r\n writable: false,\r\n configurable: true\r\n });\r\n }\r\n return target;\r\n});\n\n/**\r\n * Returns the global object associated with provided element.\r\n *\r\n * @param {Object} target\r\n * @returns {Object}\r\n */\r\nvar getWindowOf = (function (target) {\r\n // Assume that the element is an instance of Node, which means that it\r\n // has the \"ownerDocument\" property from which we can retrieve a\r\n // corresponding global object.\r\n var ownerGlobal = target && target.ownerDocument && target.ownerDocument.defaultView;\r\n // Return the local global object if it's not possible extract one from\r\n // provided element.\r\n return ownerGlobal || global$1;\r\n});\n\n// Placeholder of an empty content rectangle.\r\nvar emptyRect = createRectInit(0, 0, 0, 0);\r\n/**\r\n * Converts provided string to a number.\r\n *\r\n * @param {number|string} value\r\n * @returns {number}\r\n */\r\nfunction toFloat(value) {\r\n return parseFloat(value) || 0;\r\n}\r\n/**\r\n * Extracts borders size from provided styles.\r\n *\r\n * @param {CSSStyleDeclaration} styles\r\n * @param {...string} positions - Borders positions (top, right, ...)\r\n * @returns {number}\r\n */\r\nfunction getBordersSize(styles) {\r\n var positions = [];\r\n for (var _i = 1; _i < arguments.length; _i++) {\r\n positions[_i - 1] = arguments[_i];\r\n }\r\n return positions.reduce(function (size, position) {\r\n var value = styles['border-' + position + '-width'];\r\n return size + toFloat(value);\r\n }, 0);\r\n}\r\n/**\r\n * Extracts paddings sizes from provided styles.\r\n *\r\n * @param {CSSStyleDeclaration} styles\r\n * @returns {Object} Paddings box.\r\n */\r\nfunction getPaddings(styles) {\r\n var positions = ['top', 'right', 'bottom', 'left'];\r\n var paddings = {};\r\n for (var _i = 0, positions_1 = positions; _i < positions_1.length; _i++) {\r\n var position = positions_1[_i];\r\n var value = styles['padding-' + position];\r\n paddings[position] = toFloat(value);\r\n }\r\n return paddings;\r\n}\r\n/**\r\n * Calculates content rectangle of provided SVG element.\r\n *\r\n * @param {SVGGraphicsElement} target - Element content rectangle of which needs\r\n * to be calculated.\r\n * @returns {DOMRectInit}\r\n */\r\nfunction getSVGContentRect(target) {\r\n var bbox = target.getBBox();\r\n return createRectInit(0, 0, bbox.width, bbox.height);\r\n}\r\n/**\r\n * Calculates content rectangle of provided HTMLElement.\r\n *\r\n * @param {HTMLElement} target - Element for which to calculate the content rectangle.\r\n * @returns {DOMRectInit}\r\n */\r\nfunction getHTMLElementContentRect(target) {\r\n // Client width & height properties can't be\r\n // used exclusively as they provide rounded values.\r\n var clientWidth = target.clientWidth, clientHeight = target.clientHeight;\r\n // By this condition we can catch all non-replaced inline, hidden and\r\n // detached elements. Though elements with width & height properties less\r\n // than 0.5 will be discarded as well.\r\n //\r\n // Without it we would need to implement separate methods for each of\r\n // those cases and it's not possible to perform a precise and performance\r\n // effective test for hidden elements. E.g. even jQuery's ':visible' filter\r\n // gives wrong results for elements with width & height less than 0.5.\r\n if (!clientWidth && !clientHeight) {\r\n return emptyRect;\r\n }\r\n var styles = getWindowOf(target).getComputedStyle(target);\r\n var paddings = getPaddings(styles);\r\n var horizPad = paddings.left + paddings.right;\r\n var vertPad = paddings.top + paddings.bottom;\r\n // Computed styles of width & height are being used because they are the\r\n // only dimensions available to JS that contain non-rounded values. It could\r\n // be possible to utilize the getBoundingClientRect if only it's data wasn't\r\n // affected by CSS transformations let alone paddings, borders and scroll bars.\r\n var width = toFloat(styles.width), height = toFloat(styles.height);\r\n // Width & height include paddings and borders when the 'border-box' box\r\n // model is applied (except for IE).\r\n if (styles.boxSizing === 'border-box') {\r\n // Following conditions are required to handle Internet Explorer which\r\n // doesn't include paddings and borders to computed CSS dimensions.\r\n //\r\n // We can say that if CSS dimensions + paddings are equal to the \"client\"\r\n // properties then it's either IE, and thus we don't need to subtract\r\n // anything, or an element merely doesn't have paddings/borders styles.\r\n if (Math.round(width + horizPad) !== clientWidth) {\r\n width -= getBordersSize(styles, 'left', 'right') + horizPad;\r\n }\r\n if (Math.round(height + vertPad) !== clientHeight) {\r\n height -= getBordersSize(styles, 'top', 'bottom') + vertPad;\r\n }\r\n }\r\n // Following steps can't be applied to the document's root element as its\r\n // client[Width/Height] properties represent viewport area of the window.\r\n // Besides, it's as well not necessary as the itself neither has\r\n // rendered scroll bars nor it can be clipped.\r\n if (!isDocumentElement(target)) {\r\n // In some browsers (only in Firefox, actually) CSS width & height\r\n // include scroll bars size which can be removed at this step as scroll\r\n // bars are the only difference between rounded dimensions + paddings\r\n // and \"client\" properties, though that is not always true in Chrome.\r\n var vertScrollbar = Math.round(width + horizPad) - clientWidth;\r\n var horizScrollbar = Math.round(height + vertPad) - clientHeight;\r\n // Chrome has a rather weird rounding of \"client\" properties.\r\n // E.g. for an element with content width of 314.2px it sometimes gives\r\n // the client width of 315px and for the width of 314.7px it may give\r\n // 314px. And it doesn't happen all the time. So just ignore this delta\r\n // as a non-relevant.\r\n if (Math.abs(vertScrollbar) !== 1) {\r\n width -= vertScrollbar;\r\n }\r\n if (Math.abs(horizScrollbar) !== 1) {\r\n height -= horizScrollbar;\r\n }\r\n }\r\n return createRectInit(paddings.left, paddings.top, width, height);\r\n}\r\n/**\r\n * Checks whether provided element is an instance of the SVGGraphicsElement.\r\n *\r\n * @param {Element} target - Element to be checked.\r\n * @returns {boolean}\r\n */\r\nvar isSVGGraphicsElement = (function () {\r\n // Some browsers, namely IE and Edge, don't have the SVGGraphicsElement\r\n // interface.\r\n if (typeof SVGGraphicsElement !== 'undefined') {\r\n return function (target) { return target instanceof getWindowOf(target).SVGGraphicsElement; };\r\n }\r\n // If it's so, then check that element is at least an instance of the\r\n // SVGElement and that it has the \"getBBox\" method.\r\n // eslint-disable-next-line no-extra-parens\r\n return function (target) { return (target instanceof getWindowOf(target).SVGElement &&\r\n typeof target.getBBox === 'function'); };\r\n})();\r\n/**\r\n * Checks whether provided element is a document element ().\r\n *\r\n * @param {Element} target - Element to be checked.\r\n * @returns {boolean}\r\n */\r\nfunction isDocumentElement(target) {\r\n return target === getWindowOf(target).document.documentElement;\r\n}\r\n/**\r\n * Calculates an appropriate content rectangle for provided html or svg element.\r\n *\r\n * @param {Element} target - Element content rectangle of which needs to be calculated.\r\n * @returns {DOMRectInit}\r\n */\r\nfunction getContentRect(target) {\r\n if (!isBrowser) {\r\n return emptyRect;\r\n }\r\n if (isSVGGraphicsElement(target)) {\r\n return getSVGContentRect(target);\r\n }\r\n return getHTMLElementContentRect(target);\r\n}\r\n/**\r\n * Creates rectangle with an interface of the DOMRectReadOnly.\r\n * Spec: https://drafts.fxtf.org/geometry/#domrectreadonly\r\n *\r\n * @param {DOMRectInit} rectInit - Object with rectangle's x/y coordinates and dimensions.\r\n * @returns {DOMRectReadOnly}\r\n */\r\nfunction createReadOnlyRect(_a) {\r\n var x = _a.x, y = _a.y, width = _a.width, height = _a.height;\r\n // If DOMRectReadOnly is available use it as a prototype for the rectangle.\r\n var Constr = typeof DOMRectReadOnly !== 'undefined' ? DOMRectReadOnly : Object;\r\n var rect = Object.create(Constr.prototype);\r\n // Rectangle's properties are not writable and non-enumerable.\r\n defineConfigurable(rect, {\r\n x: x, y: y, width: width, height: height,\r\n top: y,\r\n right: x + width,\r\n bottom: height + y,\r\n left: x\r\n });\r\n return rect;\r\n}\r\n/**\r\n * Creates DOMRectInit object based on the provided dimensions and the x/y coordinates.\r\n * Spec: https://drafts.fxtf.org/geometry/#dictdef-domrectinit\r\n *\r\n * @param {number} x - X coordinate.\r\n * @param {number} y - Y coordinate.\r\n * @param {number} width - Rectangle's width.\r\n * @param {number} height - Rectangle's height.\r\n * @returns {DOMRectInit}\r\n */\r\nfunction createRectInit(x, y, width, height) {\r\n return { x: x, y: y, width: width, height: height };\r\n}\n\n/**\r\n * Class that is responsible for computations of the content rectangle of\r\n * provided DOM element and for keeping track of it's changes.\r\n */\r\nvar ResizeObservation = /** @class */ (function () {\r\n /**\r\n * Creates an instance of ResizeObservation.\r\n *\r\n * @param {Element} target - Element to be observed.\r\n */\r\n function ResizeObservation(target) {\r\n /**\r\n * Broadcasted width of content rectangle.\r\n *\r\n * @type {number}\r\n */\r\n this.broadcastWidth = 0;\r\n /**\r\n * Broadcasted height of content rectangle.\r\n *\r\n * @type {number}\r\n */\r\n this.broadcastHeight = 0;\r\n /**\r\n * Reference to the last observed content rectangle.\r\n *\r\n * @private {DOMRectInit}\r\n */\r\n this.contentRect_ = createRectInit(0, 0, 0, 0);\r\n this.target = target;\r\n }\r\n /**\r\n * Updates content rectangle and tells whether it's width or height properties\r\n * have changed since the last broadcast.\r\n *\r\n * @returns {boolean}\r\n */\r\n ResizeObservation.prototype.isActive = function () {\r\n var rect = getContentRect(this.target);\r\n this.contentRect_ = rect;\r\n return (rect.width !== this.broadcastWidth ||\r\n rect.height !== this.broadcastHeight);\r\n };\r\n /**\r\n * Updates 'broadcastWidth' and 'broadcastHeight' properties with a data\r\n * from the corresponding properties of the last observed content rectangle.\r\n *\r\n * @returns {DOMRectInit} Last observed content rectangle.\r\n */\r\n ResizeObservation.prototype.broadcastRect = function () {\r\n var rect = this.contentRect_;\r\n this.broadcastWidth = rect.width;\r\n this.broadcastHeight = rect.height;\r\n return rect;\r\n };\r\n return ResizeObservation;\r\n}());\n\nvar ResizeObserverEntry = /** @class */ (function () {\r\n /**\r\n * Creates an instance of ResizeObserverEntry.\r\n *\r\n * @param {Element} target - Element that is being observed.\r\n * @param {DOMRectInit} rectInit - Data of the element's content rectangle.\r\n */\r\n function ResizeObserverEntry(target, rectInit) {\r\n var contentRect = createReadOnlyRect(rectInit);\r\n // According to the specification following properties are not writable\r\n // and are also not enumerable in the native implementation.\r\n //\r\n // Property accessors are not being used as they'd require to define a\r\n // private WeakMap storage which may cause memory leaks in browsers that\r\n // don't support this type of collections.\r\n defineConfigurable(this, { target: target, contentRect: contentRect });\r\n }\r\n return ResizeObserverEntry;\r\n}());\n\nvar ResizeObserverSPI = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of ResizeObserver.\r\n *\r\n * @param {ResizeObserverCallback} callback - Callback function that is invoked\r\n * when one of the observed elements changes it's content dimensions.\r\n * @param {ResizeObserverController} controller - Controller instance which\r\n * is responsible for the updates of observer.\r\n * @param {ResizeObserver} callbackCtx - Reference to the public\r\n * ResizeObserver instance which will be passed to callback function.\r\n */\r\n function ResizeObserverSPI(callback, controller, callbackCtx) {\r\n /**\r\n * Collection of resize observations that have detected changes in dimensions\r\n * of elements.\r\n *\r\n * @private {Array}\r\n */\r\n this.activeObservations_ = [];\r\n /**\r\n * Registry of the ResizeObservation instances.\r\n *\r\n * @private {Map}\r\n */\r\n this.observations_ = new MapShim();\r\n if (typeof callback !== 'function') {\r\n throw new TypeError('The callback provided as parameter 1 is not a function.');\r\n }\r\n this.callback_ = callback;\r\n this.controller_ = controller;\r\n this.callbackCtx_ = callbackCtx;\r\n }\r\n /**\r\n * Starts observing provided element.\r\n *\r\n * @param {Element} target - Element to be observed.\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.observe = function (target) {\r\n if (!arguments.length) {\r\n throw new TypeError('1 argument required, but only 0 present.');\r\n }\r\n // Do nothing if current environment doesn't have the Element interface.\r\n if (typeof Element === 'undefined' || !(Element instanceof Object)) {\r\n return;\r\n }\r\n if (!(target instanceof getWindowOf(target).Element)) {\r\n throw new TypeError('parameter 1 is not of type \"Element\".');\r\n }\r\n var observations = this.observations_;\r\n // Do nothing if element is already being observed.\r\n if (observations.has(target)) {\r\n return;\r\n }\r\n observations.set(target, new ResizeObservation(target));\r\n this.controller_.addObserver(this);\r\n // Force the update of observations.\r\n this.controller_.refresh();\r\n };\r\n /**\r\n * Stops observing provided element.\r\n *\r\n * @param {Element} target - Element to stop observing.\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.unobserve = function (target) {\r\n if (!arguments.length) {\r\n throw new TypeError('1 argument required, but only 0 present.');\r\n }\r\n // Do nothing if current environment doesn't have the Element interface.\r\n if (typeof Element === 'undefined' || !(Element instanceof Object)) {\r\n return;\r\n }\r\n if (!(target instanceof getWindowOf(target).Element)) {\r\n throw new TypeError('parameter 1 is not of type \"Element\".');\r\n }\r\n var observations = this.observations_;\r\n // Do nothing if element is not being observed.\r\n if (!observations.has(target)) {\r\n return;\r\n }\r\n observations.delete(target);\r\n if (!observations.size) {\r\n this.controller_.removeObserver(this);\r\n }\r\n };\r\n /**\r\n * Stops observing all elements.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.disconnect = function () {\r\n this.clearActive();\r\n this.observations_.clear();\r\n this.controller_.removeObserver(this);\r\n };\r\n /**\r\n * Collects observation instances the associated element of which has changed\r\n * it's content rectangle.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.gatherActive = function () {\r\n var _this = this;\r\n this.clearActive();\r\n this.observations_.forEach(function (observation) {\r\n if (observation.isActive()) {\r\n _this.activeObservations_.push(observation);\r\n }\r\n });\r\n };\r\n /**\r\n * Invokes initial callback function with a list of ResizeObserverEntry\r\n * instances collected from active resize observations.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.broadcastActive = function () {\r\n // Do nothing if observer doesn't have active observations.\r\n if (!this.hasActive()) {\r\n return;\r\n }\r\n var ctx = this.callbackCtx_;\r\n // Create ResizeObserverEntry instance for every active observation.\r\n var entries = this.activeObservations_.map(function (observation) {\r\n return new ResizeObserverEntry(observation.target, observation.broadcastRect());\r\n });\r\n this.callback_.call(ctx, entries, ctx);\r\n this.clearActive();\r\n };\r\n /**\r\n * Clears the collection of active observations.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.clearActive = function () {\r\n this.activeObservations_.splice(0);\r\n };\r\n /**\r\n * Tells whether observer has active observations.\r\n *\r\n * @returns {boolean}\r\n */\r\n ResizeObserverSPI.prototype.hasActive = function () {\r\n return this.activeObservations_.length > 0;\r\n };\r\n return ResizeObserverSPI;\r\n}());\n\n// Registry of internal observers. If WeakMap is not available use current shim\r\n// for the Map collection as it has all required methods and because WeakMap\r\n// can't be fully polyfilled anyway.\r\nvar observers = typeof WeakMap !== 'undefined' ? new WeakMap() : new MapShim();\r\n/**\r\n * ResizeObserver API. Encapsulates the ResizeObserver SPI implementation\r\n * exposing only those methods and properties that are defined in the spec.\r\n */\r\nvar ResizeObserver = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of ResizeObserver.\r\n *\r\n * @param {ResizeObserverCallback} callback - Callback that is invoked when\r\n * dimensions of the observed elements change.\r\n */\r\n function ResizeObserver(callback) {\r\n if (!(this instanceof ResizeObserver)) {\r\n throw new TypeError('Cannot call a class as a function.');\r\n }\r\n if (!arguments.length) {\r\n throw new TypeError('1 argument required, but only 0 present.');\r\n }\r\n var controller = ResizeObserverController.getInstance();\r\n var observer = new ResizeObserverSPI(callback, controller, this);\r\n observers.set(this, observer);\r\n }\r\n return ResizeObserver;\r\n}());\r\n// Expose public methods of ResizeObserver.\r\n[\r\n 'observe',\r\n 'unobserve',\r\n 'disconnect'\r\n].forEach(function (method) {\r\n ResizeObserver.prototype[method] = function () {\r\n var _a;\r\n return (_a = observers.get(this))[method].apply(_a, arguments);\r\n };\r\n});\n\nvar index = (function () {\r\n // Export existing implementation if available.\r\n if (typeof global$1.ResizeObserver !== 'undefined') {\r\n return global$1.ResizeObserver;\r\n }\r\n return ResizeObserver;\r\n})();\n\nexport default index;\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ResizeObserver from \"resize-observer-polyfill\"\nimport {\n NEVER,\n Observable,\n Subject,\n defer,\n filter,\n finalize,\n map,\n merge,\n of,\n shareReplay,\n startWith,\n switchMap,\n tap\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Element offset\n */\nexport interface ElementSize {\n width: number /* Element width */\n height: number /* Element height */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Resize observer entry subject\n */\nconst entry$ = new Subject()\n\n/**\n * Resize observer observable\n *\n * This observable will create a `ResizeObserver` on the first subscription\n * and will automatically terminate it when there are no more subscribers.\n * It's quite important to centralize observation in a single `ResizeObserver`,\n * as the performance difference can be quite dramatic, as the link shows.\n *\n * @see https://bit.ly/3iIYfEm - Google Groups on performance\n */\nconst observer$ = defer(() => of(\n new ResizeObserver(entries => {\n for (const entry of entries)\n entry$.next(entry)\n })\n))\n .pipe(\n switchMap(observer => merge(NEVER, of(observer))\n .pipe(\n finalize(() => observer.disconnect())\n )\n ),\n shareReplay(1)\n )\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element size\n *\n * @param el - Element\n *\n * @returns Element size\n */\nexport function getElementSize(\n el: HTMLElement\n): ElementSize {\n return {\n width: el.offsetWidth,\n height: el.offsetHeight\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element size\n *\n * This function returns an observable that subscribes to a single internal\n * instance of `ResizeObserver` upon subscription, and emit resize events until\n * termination. Note that this function should not be called with the same\n * element twice, as the first unsubscription will terminate observation.\n *\n * Sadly, we can't use the `DOMRect` objects returned by the observer, because\n * we need the emitted values to be consistent with `getElementSize`, which will\n * return the used values (rounded) and not actual values (unrounded). Thus, we\n * use the `offset*` properties. See the linked GitHub issue.\n *\n * @see https://bit.ly/3m0k3he - GitHub issue\n *\n * @param el - Element\n *\n * @returns Element size observable\n */\nexport function watchElementSize(\n el: HTMLElement\n): Observable {\n return observer$\n .pipe(\n tap(observer => observer.observe(el)),\n switchMap(observer => entry$\n .pipe(\n filter(({ target }) => target === el),\n finalize(() => observer.unobserve(el)),\n map(() => getElementSize(el))\n )\n ),\n startWith(getElementSize(el))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ElementSize } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element content size (= scroll width and height)\n *\n * @param el - Element\n *\n * @returns Element content size\n */\nexport function getElementContentSize(\n el: HTMLElement\n): ElementSize {\n return {\n width: el.scrollWidth,\n height: el.scrollHeight\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n NEVER,\n Observable,\n Subject,\n defer,\n distinctUntilChanged,\n filter,\n finalize,\n map,\n merge,\n of,\n shareReplay,\n switchMap,\n tap\n} from \"rxjs\"\n\nimport {\n getElementContentSize,\n getElementSize,\n watchElementContentOffset\n} from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Intersection observer entry subject\n */\nconst entry$ = new Subject()\n\n/**\n * Intersection observer observable\n *\n * This observable will create an `IntersectionObserver` on first subscription\n * and will automatically terminate it when there are no more subscribers.\n *\n * @see https://bit.ly/3iIYfEm - Google Groups on performance\n */\nconst observer$ = defer(() => of(\n new IntersectionObserver(entries => {\n for (const entry of entries)\n entry$.next(entry)\n }, {\n threshold: 1\n })\n))\n .pipe(\n switchMap(observer => merge(NEVER, of(observer))\n .pipe(\n finalize(() => observer.disconnect())\n )\n ),\n shareReplay(1)\n )\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch element visibility\n *\n * @param el - Element\n *\n * @returns Element visibility observable\n */\nexport function watchElementVisibility(\n el: HTMLElement\n): Observable {\n return observer$\n .pipe(\n tap(observer => observer.observe(el)),\n switchMap(observer => entry$\n .pipe(\n filter(({ target }) => target === el),\n finalize(() => observer.unobserve(el)),\n map(({ isIntersecting }) => isIntersecting)\n )\n )\n )\n}\n\n/**\n * Watch element boundary\n *\n * This function returns an observable which emits whether the bottom content\n * boundary (= scroll offset) of an element is within a certain threshold.\n *\n * @param el - Element\n * @param threshold - Threshold\n *\n * @returns Element boundary observable\n */\nexport function watchElementBoundary(\n el: HTMLElement, threshold = 16\n): Observable {\n return watchElementContentOffset(el)\n .pipe(\n map(({ y }) => {\n const visible = getElementSize(el)\n const content = getElementContentSize(el)\n return y >= (\n content.height - visible.height - threshold\n )\n }),\n distinctUntilChanged()\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n fromEvent,\n map,\n startWith\n} from \"rxjs\"\n\nimport { getElement } from \"../element\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Toggle\n */\nexport type Toggle =\n | \"drawer\" /* Toggle for drawer */\n | \"search\" /* Toggle for search */\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Toggle map\n */\nconst toggles: Record = {\n drawer: getElement(\"[data-md-toggle=drawer]\"),\n search: getElement(\"[data-md-toggle=search]\")\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve the value of a toggle\n *\n * @param name - Toggle\n *\n * @returns Toggle value\n */\nexport function getToggle(name: Toggle): boolean {\n return toggles[name].checked\n}\n\n/**\n * Set toggle\n *\n * Simulating a click event seems to be the most cross-browser compatible way\n * of changing the value while also emitting a `change` event. Before, Material\n * used `CustomEvent` to programmatically change the value of a toggle, but this\n * is a much simpler and cleaner solution which doesn't require a polyfill.\n *\n * @param name - Toggle\n * @param value - Toggle value\n */\nexport function setToggle(name: Toggle, value: boolean): void {\n if (toggles[name].checked !== value)\n toggles[name].click()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch toggle\n *\n * @param name - Toggle\n *\n * @returns Toggle value observable\n */\nexport function watchToggle(name: Toggle): Observable {\n const el = toggles[name]\n return fromEvent(el, \"change\")\n .pipe(\n map(() => el.checked),\n startWith(el.checked)\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n filter,\n fromEvent,\n map,\n share\n} from \"rxjs\"\n\nimport { getActiveElement } from \"../element\"\nimport { getToggle } from \"../toggle\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Keyboard mode\n */\nexport type KeyboardMode =\n | \"global\" /* Global */\n | \"search\" /* Search is open */\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Keyboard\n */\nexport interface Keyboard {\n mode: KeyboardMode /* Keyboard mode */\n type: string /* Key type */\n claim(): void /* Key claim */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Check whether an element may receive keyboard input\n *\n * @param el - Element\n * @param type - Key type\n *\n * @returns Test result\n */\nfunction isSusceptibleToKeyboard(\n el: HTMLElement, type: string\n): boolean {\n switch (el.constructor) {\n\n /* Input elements */\n case HTMLInputElement:\n /* @ts-expect-error - omit unnecessary type cast */\n if (el.type === \"radio\")\n return /^Arrow/.test(type)\n else\n return true\n\n /* Select element and textarea */\n case HTMLSelectElement:\n case HTMLTextAreaElement:\n return true\n\n /* Everything else */\n default:\n return el.isContentEditable\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch keyboard\n *\n * @returns Keyboard observable\n */\nexport function watchKeyboard(): Observable {\n return fromEvent(window, \"keydown\")\n .pipe(\n filter(ev => !(ev.metaKey || ev.ctrlKey)),\n map(ev => ({\n mode: getToggle(\"search\") ? \"search\" : \"global\",\n type: ev.key,\n claim() {\n ev.preventDefault()\n ev.stopPropagation()\n }\n } as Keyboard)),\n filter(({ mode, type }) => {\n if (mode === \"global\") {\n const active = getActiveElement()\n if (typeof active !== \"undefined\")\n return !isSusceptibleToKeyboard(active, type)\n }\n return true\n }),\n share()\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Subject } from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve location\n *\n * This function returns a `URL` object (and not `Location`) to normalize the\n * typings across the application. Furthermore, locations need to be tracked\n * without setting them and `Location` is a singleton which represents the\n * current location.\n *\n * @returns URL\n */\nexport function getLocation(): URL {\n return new URL(location.href)\n}\n\n/**\n * Set location\n *\n * @param url - URL to change to\n */\nexport function setLocation(url: URL): void {\n location.href = url.href\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch location\n *\n * @returns Location subject\n */\nexport function watchLocation(): Subject {\n return new Subject()\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { JSX as JSXInternal } from \"preact\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * HTML attributes\n */\ntype Attributes =\n & JSXInternal.HTMLAttributes\n & JSXInternal.SVGAttributes\n & Record\n\n/**\n * Child element\n */\ntype Child =\n | HTMLElement\n | Text\n | string\n | number\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Append a child node to an element\n *\n * @param el - Element\n * @param child - Child node(s)\n */\nfunction appendChild(el: HTMLElement, child: Child | Child[]): void {\n\n /* Handle primitive types (including raw HTML) */\n if (typeof child === \"string\" || typeof child === \"number\") {\n el.innerHTML += child.toString()\n\n /* Handle nodes */\n } else if (child instanceof Node) {\n el.appendChild(child)\n\n /* Handle nested children */\n } else if (Array.isArray(child)) {\n for (const node of child)\n appendChild(el, node)\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * JSX factory\n *\n * @template T - Element type\n *\n * @param tag - HTML tag\n * @param attributes - HTML attributes\n * @param children - Child elements\n *\n * @returns Element\n */\nexport function h(\n tag: T, attributes?: Attributes | null, ...children: Child[]\n): HTMLElementTagNameMap[T]\n\nexport function h(\n tag: string, attributes?: Attributes | null, ...children: Child[]\n): T\n\nexport function h(\n tag: string, attributes?: Attributes | null, ...children: Child[]\n): T {\n const el = document.createElement(tag)\n\n /* Set attributes, if any */\n if (attributes)\n for (const attr of Object.keys(attributes))\n if (typeof attributes[attr] !== \"boolean\")\n el.setAttribute(attr, attributes[attr])\n else if (attributes[attr])\n el.setAttribute(attr, \"\")\n\n /* Append child nodes */\n for (const child of children)\n appendChild(el, child)\n\n /* Return element */\n return el as T\n}\n\n/* ----------------------------------------------------------------------------\n * Namespace\n * ------------------------------------------------------------------------- */\n\nexport declare namespace h {\n namespace JSX {\n type Element = HTMLElement\n type IntrinsicElements = JSXInternal.IntrinsicElements\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Truncate a string after the given number of characters\n *\n * This is not a very reasonable approach, since the summaries kind of suck.\n * It would be better to create something more intelligent, highlighting the\n * search occurrences and making a better summary out of it, but this note was\n * written three years ago, so who knows if we'll ever fix it.\n *\n * @param value - Value to be truncated\n * @param n - Number of characters\n *\n * @returns Truncated value\n */\nexport function truncate(value: string, n: number): string {\n let i = n\n if (value.length > i) {\n while (value[i] !== \" \" && --i > 0) { /* keep eating */ }\n return `${value.substring(0, i)}...`\n }\n return value\n}\n\n/**\n * Round a number for display with repository facts\n *\n * This is a reverse-engineered version of GitHub's weird rounding algorithm\n * for stars, forks and all other numbers. While all numbers below `1,000` are\n * returned as-is, bigger numbers are converted to fixed numbers:\n *\n * - `1,049` => `1k`\n * - `1,050` => `1.1k`\n * - `1,949` => `1.9k`\n * - `1,950` => `2k`\n *\n * @param value - Original value\n *\n * @returns Rounded value\n */\nexport function round(value: number): string {\n if (value > 999) {\n const digits = +((value - 950) % 1000 > 99)\n return `${((value + 0.000001) / 1000).toFixed(digits)}k`\n } else {\n return value.toString()\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n filter,\n fromEvent,\n map,\n shareReplay,\n startWith\n} from \"rxjs\"\n\nimport { getOptionalElement } from \"~/browser\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve location hash\n *\n * @returns Location hash\n */\nexport function getLocationHash(): string {\n return location.hash.substring(1)\n}\n\n/**\n * Set location hash\n *\n * Setting a new fragment identifier via `location.hash` will have no effect\n * if the value doesn't change. When a new fragment identifier is set, we want\n * the browser to target the respective element at all times, which is why we\n * use this dirty little trick.\n *\n * @param hash - Location hash\n */\nexport function setLocationHash(hash: string): void {\n const el = h(\"a\", { href: hash })\n el.addEventListener(\"click\", ev => ev.stopPropagation())\n el.click()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch location hash\n *\n * @returns Location hash observable\n */\nexport function watchLocationHash(): Observable {\n return fromEvent(window, \"hashchange\")\n .pipe(\n map(getLocationHash),\n startWith(getLocationHash()),\n filter(hash => hash.length > 0),\n shareReplay(1)\n )\n}\n\n/**\n * Watch location target\n *\n * @returns Location target observable\n */\nexport function watchLocationTarget(): Observable {\n return watchLocationHash()\n .pipe(\n map(id => getOptionalElement(`[id=\"${id}\"]`)!),\n filter(el => typeof el !== \"undefined\")\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n fromEvent,\n fromEventPattern,\n mapTo,\n merge,\n startWith,\n switchMap\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch media query\n *\n * Note that although `MediaQueryList.addListener` is deprecated we have to\n * use it, because it's the only way to ensure proper downward compatibility.\n *\n * @see https://bit.ly/3dUBH2m - GitHub issue\n *\n * @param query - Media query\n *\n * @returns Media observable\n */\nexport function watchMedia(query: string): Observable {\n const media = matchMedia(query)\n return fromEventPattern(next => (\n media.addListener(() => next(media.matches))\n ))\n .pipe(\n startWith(media.matches)\n )\n}\n\n/**\n * Watch print mode\n *\n * @returns Print observable\n */\nexport function watchPrint(): Observable {\n const media = matchMedia(\"print\")\n return merge(\n fromEvent(window, \"beforeprint\").pipe(mapTo(true)),\n fromEvent(window, \"afterprint\").pipe(mapTo(false))\n )\n .pipe(\n startWith(media.matches)\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Toggle an observable with a media observable\n *\n * @template T - Data type\n *\n * @param query$ - Media observable\n * @param factory - Observable factory\n *\n * @returns Toggled observable\n */\nexport function at(\n query$: Observable, factory: () => Observable\n): Observable {\n return query$\n .pipe(\n switchMap(active => active ? factory() : EMPTY)\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n catchError,\n filter,\n from,\n map,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch the given URL\n *\n * If the request fails (e.g. when dispatched from `file://` locations), the\n * observable will complete without emitting a value.\n *\n * @param url - Request URL\n * @param options - Options\n *\n * @returns Response observable\n */\nexport function request(\n url: URL | string, options: RequestInit = { credentials: \"same-origin\" }\n): Observable {\n return from(fetch(`${url}`, options))\n .pipe(\n filter(res => res.status === 200),\n catchError(() => EMPTY)\n )\n}\n\n/**\n * Fetch JSON from the given URL\n *\n * @template T - Data type\n *\n * @param url - Request URL\n * @param options - Options\n *\n * @returns Data observable\n */\nexport function requestJSON(\n url: URL | string, options?: RequestInit\n): Observable {\n return request(url, options)\n .pipe(\n switchMap(res => res.json()),\n shareReplay(1)\n )\n}\n\n/**\n * Fetch XML from the given URL\n *\n * @param url - Request URL\n * @param options - Options\n *\n * @returns Data observable\n */\nexport function requestXML(\n url: URL | string, options?: RequestInit\n): Observable {\n const dom = new DOMParser()\n return request(url, options)\n .pipe(\n switchMap(res => res.text()),\n map(res => dom.parseFromString(res, \"text/xml\")),\n shareReplay(1)\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n defer,\n finalize,\n fromEvent,\n mapTo,\n merge,\n switchMap,\n take,\n throwError\n} from \"rxjs\"\n\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create and load a `script` element\n *\n * This function returns an observable that will emit when the script was\n * successfully loaded, or throw an error if it didn't.\n *\n * @param src - Script URL\n *\n * @returns Script observable\n */\nexport function watchScript(src: string): Observable {\n const script = h(\"script\", { src })\n return defer(() => {\n document.head.appendChild(script)\n return merge(\n fromEvent(script, \"load\"),\n fromEvent(script, \"error\")\n .pipe(\n switchMap(() => (\n throwError(() => new ReferenceError(`Invalid script: ${src}`))\n ))\n )\n )\n .pipe(\n mapTo(undefined),\n finalize(() => document.head.removeChild(script)),\n take(1)\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n fromEvent,\n map,\n merge,\n startWith\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport offset\n */\nexport interface ViewportOffset {\n x: number /* Horizontal offset */\n y: number /* Vertical offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve viewport offset\n *\n * On iOS Safari, viewport offset can be negative due to overflow scrolling.\n * As this may induce strange behaviors downstream, we'll just limit it to 0.\n *\n * @returns Viewport offset\n */\nexport function getViewportOffset(): ViewportOffset {\n return {\n x: Math.max(0, scrollX),\n y: Math.max(0, scrollY)\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport offset\n *\n * @returns Viewport offset observable\n */\nexport function watchViewportOffset(): Observable {\n return merge(\n fromEvent(window, \"scroll\", { passive: true }),\n fromEvent(window, \"resize\", { passive: true })\n )\n .pipe(\n map(getViewportOffset),\n startWith(getViewportOffset())\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n fromEvent,\n map,\n startWith\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport size\n */\nexport interface ViewportSize {\n width: number /* Viewport width */\n height: number /* Viewport height */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve viewport size\n *\n * @returns Viewport size\n */\nexport function getViewportSize(): ViewportSize {\n return {\n width: innerWidth,\n height: innerHeight\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport size\n *\n * @returns Viewport size observable\n */\nexport function watchViewportSize(): Observable {\n return fromEvent(window, \"resize\", { passive: true })\n .pipe(\n map(getViewportSize),\n startWith(getViewportSize())\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n combineLatest,\n map,\n shareReplay\n} from \"rxjs\"\n\nimport {\n ViewportOffset,\n watchViewportOffset\n} from \"../offset\"\nimport {\n ViewportSize,\n watchViewportSize\n} from \"../size\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport\n */\nexport interface Viewport {\n offset: ViewportOffset /* Viewport offset */\n size: ViewportSize /* Viewport size */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport\n *\n * @returns Viewport observable\n */\nexport function watchViewport(): Observable {\n return combineLatest([\n watchViewportOffset(),\n watchViewportSize()\n ])\n .pipe(\n map(([offset, size]) => ({ offset, size })),\n shareReplay(1)\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n combineLatest,\n distinctUntilKeyChanged,\n map\n} from \"rxjs\"\n\nimport { Header } from \"~/components\"\n\nimport { getElementOffset } from \"../../element\"\nimport { Viewport } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
/* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport relative to element\n *\n * @param el - Element\n * @param options - Options\n *\n * @returns Viewport observable\n */\nexport function watchViewportAt(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable {\n const size$ = viewport$\n .pipe(\n distinctUntilKeyChanged(\"size\")\n )\n\n /* Compute element offset */\n const offset$ = combineLatest([size$, header$])\n .pipe(\n map(() => getElementOffset(el))\n )\n\n /* Compute relative viewport, return hot observable */\n return combineLatest([header$, viewport$, offset$])\n .pipe(\n map(([{ height }, { offset, size }, { x, y }]) => ({\n offset: {\n x: offset.x - x,\n y: offset.y - y + height\n },\n size\n }))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n fromEvent,\n map,\n share,\n switchMapTo,\n tap,\n throttle\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Worker message\n */\nexport interface WorkerMessage {\n type: unknown /* Message type */\n data?: unknown /* Message data */\n}\n\n/**\n * Worker handler\n *\n * @template T - Message type\n */\nexport interface WorkerHandler<\n T extends WorkerMessage\n> {\n tx$: Subject /* Message transmission subject */\n rx$: Observable /* Message receive observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n *\n * @template T - Worker message type\n */\ninterface WatchOptions {\n tx$: Observable /* Message transmission observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch a web worker\n *\n * This function returns an observable that sends all values emitted by the\n * message observable to the web worker. Web worker communication is expected\n * to be bidirectional (request-response) and synchronous. Messages that are\n * emitted during a pending request are throttled, the last one is emitted.\n *\n * @param worker - Web worker\n * @param options - Options\n *\n * @returns Worker message observable\n */\nexport function watchWorker(\n worker: Worker, { tx$ }: WatchOptions\n): Observable {\n\n /* Intercept messages from worker-like objects */\n const rx$ = fromEvent(worker, \"message\")\n .pipe(\n map(({ data }) => data as T)\n )\n\n /* Send and receive messages, return hot observable */\n return tx$\n .pipe(\n throttle(() => rx$, { leading: true, trailing: true }),\n tap(message => worker.postMessage(message)),\n switchMapTo(rx$),\n share()\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { getElement, getLocation } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Feature flag\n */\nexport type Flag =\n | \"content.code.annotate\" /* Code annotations */\n | \"header.autohide\" /* Hide header */\n | \"navigation.expand\" /* Automatic expansion */\n | \"navigation.indexes\" /* Section pages */\n | \"navigation.instant\" /* Instant loading */\n | \"navigation.sections\" /* Section navigation */\n | \"navigation.tabs\" /* Tabs navigation */\n | \"navigation.tabs.sticky\" /* Tabs navigation (sticky) */\n | \"navigation.top\" /* Back-to-top button */\n | \"navigation.tracking\" /* Anchor tracking */\n | \"search.highlight\" /* Search highlighting */\n | \"search.share\" /* Search sharing */\n | \"search.suggest\" /* Search suggestions */\n | \"toc.integrate\" /* Integrated table of contents */\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Translation\n */\nexport type Translation =\n | \"clipboard.copy\" /* Copy to clipboard */\n | \"clipboard.copied\" /* Copied to clipboard */\n | \"search.config.lang\" /* Search language */\n | \"search.config.pipeline\" /* Search pipeline */\n | \"search.config.separator\" /* Search separator */\n | \"search.placeholder\" /* Search */\n | \"search.result.placeholder\" /* Type to start searching */\n | \"search.result.none\" /* No matching documents */\n | \"search.result.one\" /* 1 matching document */\n | \"search.result.other\" /* # matching documents */\n | \"search.result.more.one\" /* 1 more on this page */\n | \"search.result.more.other\" /* # more on this page */\n | \"search.result.term.missing\" /* Missing */\n | \"select.version.title\" /* Version selector */\n\n/**\n * Translations\n */\nexport type Translations = Record\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Versioning\n */\nexport interface Versioning {\n provider: \"mike\" /* Version provider */\n default?: string /* Default version */\n}\n\n/**\n * Configuration\n */\nexport interface Config {\n base: string /* Base URL */\n features: Flag[] /* Feature flags */\n translations: Translations /* Translations */\n search: string /* Search worker URL */\n version?: Versioning /* Versioning */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve global configuration and make base URL absolute\n */\nconst script = getElement(\"#__config\")\nconst config: Config = JSON.parse(script.textContent!)\nconfig.base = `${new URL(config.base, getLocation())}`\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve global configuration\n *\n * @returns Global configuration\n */\nexport function configuration(): Config {\n return config\n}\n\n/**\n * Check whether a feature flag is enabled\n *\n * @param flag - Feature flag\n *\n * @returns Test result\n */\nexport function feature(flag: Flag): boolean {\n return config.features.includes(flag)\n}\n\n/**\n * Retrieve the translation for the given key\n *\n * @param key - Key to be translated\n * @param value - Positional value, if any\n *\n * @returns Translation\n */\nexport function translation(\n key: Translation, value?: string | number\n): string {\n return typeof value !== \"undefined\"\n ? config.translations[key].replace(\"#\", value.toString())\n : config.translations[key]\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { getElement, getElements } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Component type\n */\nexport type ComponentType =\n | \"announce\" /* Announcement bar */\n | \"container\" /* Container */\n | \"content\" /* Content */\n | \"dialog\" /* Dialog */\n | \"header\" /* Header */\n | \"header-title\" /* Header title */\n | \"header-topic\" /* Header topic */\n | \"main\" /* Main area */\n | \"outdated\" /* Version warning */\n | \"palette\" /* Color palette */\n | \"search\" /* Search */\n | \"search-query\" /* Search input */\n | \"search-result\" /* Search results */\n | \"search-share\" /* Search sharing */\n | \"search-suggest\" /* Search suggestions */\n | \"sidebar\" /* Sidebar */\n | \"skip\" /* Skip link */\n | \"source\" /* Repository information */\n | \"tabs\" /* Navigation tabs */\n | \"toc\" /* Table of contents */\n | \"top\" /* Back-to-top button */\n\n/**\n * Component\n *\n * @template T - Component type\n * @template U - Reference type\n */\nexport type Component<\n T extends {} = {},\n U extends HTMLElement = HTMLElement\n> =\n T & {\n ref: U /* Component reference */\n }\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Component type map\n */\ninterface ComponentTypeMap {\n \"announce\": HTMLElement /* Announcement bar */\n \"container\": HTMLElement /* Container */\n \"content\": HTMLElement /* Content */\n \"dialog\": HTMLElement /* Dialog */\n \"header\": HTMLElement /* Header */\n \"header-title\": HTMLElement /* Header title */\n \"header-topic\": HTMLElement /* Header topic */\n \"main\": HTMLElement /* Main area */\n \"outdated\": HTMLElement /* Version warning */\n \"palette\": HTMLElement /* Color palette */\n \"search\": HTMLElement /* Search */\n \"search-query\": HTMLInputElement /* Search input */\n \"search-result\": HTMLElement /* Search results */\n \"search-share\": HTMLAnchorElement /* Search sharing */\n \"search-suggest\": HTMLElement /* Search suggestions */\n \"sidebar\": HTMLElement /* Sidebar */\n \"skip\": HTMLAnchorElement /* Skip link */\n \"source\": HTMLAnchorElement /* Repository information */\n \"tabs\": HTMLElement /* Navigation tabs */\n \"toc\": HTMLElement /* Table of contents */\n \"top\": HTMLAnchorElement /* Back-to-top button */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve the element for a given component or throw a reference error\n *\n * @template T - Component type\n *\n * @param type - Component type\n * @param node - Node of reference\n *\n * @returns Element\n */\nexport function getComponentElement(\n type: T, node: ParentNode = document\n): ComponentTypeMap[T] {\n return getElement(`[data-md-component=${type}]`, node)\n}\n\n/**\n * Retrieve all elements for a given component\n *\n * @template T - Component type\n *\n * @param type - Component type\n * @param node - Node of reference\n *\n * @returns Elements\n */\nexport function getComponentElements(\n type: T, node: ParentNode = document\n): ComponentTypeMap[T][] {\n return getElements(`[data-md-component=${type}]`, node)\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ClipboardJS from \"clipboard\"\nimport {\n EMPTY,\n Observable,\n Subject,\n defer,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n finalize,\n map,\n mergeWith,\n switchMap,\n takeLast,\n takeUntil,\n tap\n} from \"rxjs\"\n\nimport { feature } from \"~/_\"\nimport {\n getElementContentSize,\n watchElementSize\n} from \"~/browser\"\nimport { renderClipboardButton } from \"~/templates\"\n\nimport { Component } from \"../../../_\"\nimport {\n Annotation,\n mountAnnotationList\n} from \"../../annotation\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Code block\n */\nexport interface CodeBlock {\n scrollable: boolean /* Code block overflows */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n print$: Observable /* Media print observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Global sequence number for Clipboard.js integration\n */\nlet sequence = 0\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Find candidate list element directly following a code block\n *\n * @param el - Code block element\n *\n * @returns List element or nothing\n */\nfunction findCandidateList(el: HTMLElement): HTMLElement | undefined {\n if (el.nextElementSibling) {\n const sibling = el.nextElementSibling as HTMLElement\n if (sibling.tagName === \"OL\")\n return sibling\n\n /* Skip empty paragraphs - see https://bit.ly/3r4ZJ2O */\n else if (sibling.tagName === \"P\" && !sibling.children.length)\n return findCandidateList(sibling)\n }\n\n /* Everything else */\n return undefined\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch code block\n *\n * This function monitors size changes of the viewport, as well as switches of\n * content tabs with embedded code blocks, as both may trigger overflow.\n *\n * @param el - Code block element\n *\n * @returns Code block observable\n */\nexport function watchCodeBlock(\n el: HTMLElement\n): Observable {\n return watchElementSize(el)\n .pipe(\n map(({ width }) => {\n const content = getElementContentSize(el)\n return {\n scrollable: content.width > width\n }\n }),\n distinctUntilKeyChanged(\"scrollable\")\n )\n}\n\n/**\n * Mount code block\n *\n * This function ensures that an overflowing code block is focusable through\n * keyboard, so it can be scrolled without a mouse to improve on accessibility.\n * Furthermore, if code annotations are enabled, they are mounted if and only\n * if the code block is currently visible, e.g., not in a hidden content tab.\n *\n * @param el - Code block element\n * @param options - Options\n *\n * @returns Code block and annotation component observable\n */\nexport function mountCodeBlock(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const { matches: hover } = matchMedia(\"(hover)\")\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe(({ scrollable }) => {\n if (scrollable && hover)\n el.setAttribute(\"tabindex\", \"0\")\n else\n el.removeAttribute(\"tabindex\")\n })\n\n /* Render button for Clipboard.js integration */\n if (ClipboardJS.isSupported()) {\n const parent = el.closest(\"pre\")!\n parent.id = `__code_${++sequence}`\n parent.insertBefore(\n renderClipboardButton(parent.id),\n el\n )\n }\n\n /* Handle code annotations */\n const container = el.closest([\n \":not(td):not(.code) > .highlight\",\n \".highlighttable\"\n ].join(\", \"))\n if (container instanceof HTMLElement) {\n const list = findCandidateList(container)\n\n /* Mount code annotations, if enabled */\n if (typeof list !== \"undefined\" && (\n container.classList.contains(\"annotate\") ||\n feature(\"content.code.annotate\")\n )) {\n const annotations$ = mountAnnotationList(list, el, options)\n\n /* Create and return component */\n return watchCodeBlock(el)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state })),\n mergeWith(watchElementSize(container)\n .pipe(\n takeUntil(push$.pipe(takeLast(1))),\n map(({ width, height }) => width && height),\n distinctUntilChanged(),\n switchMap(active => active ? annotations$ : EMPTY)\n )\n )\n )\n }\n }\n\n /* Create and return component */\n return watchCodeBlock(el)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render an empty annotation\n *\n * @param id - Annotation identifier\n *\n * @returns Element\n */\nexport function renderAnnotation(id: number): HTMLElement {\n return (\n \n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a 'copy-to-clipboard' button\n *\n * @param id - Unique identifier\n *\n * @returns Element\n */\nexport function renderClipboardButton(id: string): HTMLElement {\n return (\n code`}\n >\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ComponentChild } from \"preact\"\n\nimport { feature, translation } from \"~/_\"\nimport {\n SearchDocument,\n SearchMetadata,\n SearchResultItem\n} from \"~/integrations/search\"\nimport { h, truncate } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Render flag\n */\nconst enum Flag {\n TEASER = 1, /* Render teaser */\n PARENT = 2 /* Render as parent */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper function\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a search document\n *\n * @param document - Search document\n * @param flag - Render flags\n *\n * @returns Element\n */\nfunction renderSearchDocument(\n document: SearchDocument & SearchMetadata, flag: Flag\n): HTMLElement {\n const parent = flag & Flag.PARENT\n const teaser = flag & Flag.TEASER\n\n /* Render missing query terms */\n const missing = Object.keys(document.terms)\n .filter(key => !document.terms[key])\n .reduce((list, key) => [\n ...list, {key}, \" \"\n ], [])\n .slice(0, -1)\n\n /* Assemble query string for highlighting */\n const url = new URL(document.location)\n if (feature(\"search.highlight\"))\n url.searchParams.set(\"h\", Object.entries(document.terms)\n .filter(([, match]) => match)\n .reduce((highlight, [value]) => `${highlight} ${value}`.trim(), \"\")\n )\n\n /* Render article or section, depending on flags */\n return (\n \n \n {parent > 0 &&
}\n

{document.title}

\n {teaser > 0 && document.text.length > 0 &&\n

\n {truncate(document.text, 320)}\n

\n }\n {document.tags && document.tags.map(tag => (\n {tag}\n ))}\n {teaser > 0 && missing.length > 0 &&\n

\n {translation(\"search.result.term.missing\")}: {...missing}\n

\n }\n \n
\n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a search result\n *\n * @param result - Search result\n *\n * @returns Element\n */\nexport function renderSearchResultItem(\n result: SearchResultItem\n): HTMLElement {\n const threshold = result[0].score\n const docs = [...result]\n\n /* Find and extract parent article */\n const parent = docs.findIndex(doc => !doc.location.includes(\"#\"))\n const [article] = docs.splice(parent, 1)\n\n /* Determine last index above threshold */\n let index = docs.findIndex(doc => doc.score < threshold)\n if (index === -1)\n index = docs.length\n\n /* Partition sections */\n const best = docs.slice(0, index)\n const more = docs.slice(index)\n\n /* Render children */\n const children = [\n renderSearchDocument(article, Flag.PARENT | +(!parent && index === 0)),\n ...best.map(section => renderSearchDocument(section, Flag.TEASER)),\n ...more.length ? [\n
\n \n {more.length > 0 && more.length === 1\n ? translation(\"search.result.more.one\")\n : translation(\"search.result.more.other\", more.length)\n }\n \n {...more.map(section => renderSearchDocument(section, Flag.TEASER))}\n
\n ] : []\n ]\n\n /* Render search result */\n return (\n
  • \n {children}\n
  • \n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SourceFacts } from \"~/components\"\nimport { h, round } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render repository facts\n *\n * @param facts - Repository facts\n *\n * @returns Element\n */\nexport function renderSourceFacts(facts: SourceFacts): HTMLElement {\n return (\n
      \n {Object.entries(facts).map(([key, value]) => (\n
    • \n {typeof value === \"number\" ? round(value) : value}\n
    • \n ))}\n
    \n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a table inside a wrapper to improve scrolling on mobile\n *\n * @param table - Table element\n *\n * @returns Element\n */\nexport function renderTable(table: HTMLElement): HTMLElement {\n return (\n
    \n
    \n {table}\n
    \n
    \n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { configuration, translation } from \"~/_\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Version\n */\nexport interface Version {\n version: string /* Version identifier */\n title: string /* Version title */\n aliases: string[] /* Version aliases */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a version\n *\n * @param version - Version\n *\n * @returns Element\n */\nfunction renderVersion(version: Version): HTMLElement {\n const config = configuration()\n\n /* Ensure trailing slash, see https://bit.ly/3rL5u3f */\n const url = new URL(`../${version.version}/`, config.base)\n return (\n
  • \n \n {version.title}\n \n
  • \n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a version selector\n *\n * @param versions - Versions\n * @param active - Active version\n *\n * @returns Element\n */\nexport function renderVersionSelector(\n versions: Version[], active: Version\n): HTMLElement {\n return (\n
    \n \n {active.title}\n \n
      \n {versions.map(renderVersion)}\n
    \n
    \n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest,\n defer,\n finalize,\n fromEvent,\n map,\n switchMap,\n take,\n tap,\n throttleTime\n} from \"rxjs\"\n\nimport {\n ElementOffset,\n getElement,\n getElementSize,\n watchElementContentOffset,\n watchElementFocus,\n watchElementOffset\n} from \"~/browser\"\n\nimport { Component } from \"../../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Annotation\n */\nexport interface Annotation {\n active: boolean /* Annotation is active */\n offset: ElementOffset /* Annotation offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch annotation\n *\n * @param el - Annotation element\n * @param container - Containing element\n *\n * @returns Annotation observable\n */\nexport function watchAnnotation(\n el: HTMLElement, container: HTMLElement\n): Observable {\n const offset$ = defer(() => combineLatest([\n watchElementOffset(el),\n watchElementContentOffset(container)\n ]))\n .pipe(\n map(([{ x, y }, scroll]) => {\n const { width } = getElementSize(el)\n return ({\n x: x - scroll.x + width / 2,\n y: y - scroll.y\n })\n })\n )\n\n /* Actively watch annotation on focus */\n return watchElementFocus(el)\n .pipe(\n switchMap(active => offset$\n .pipe(\n map(offset => ({ active, offset })),\n take(+!active || Infinity)\n )\n )\n )\n}\n\n/**\n * Mount annotation\n *\n * @param el - Annotation element\n * @param container - Containing element\n *\n * @returns Annotation component observable\n */\nexport function mountAnnotation(\n el: HTMLElement, container: HTMLElement\n): Observable> {\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe({\n\n /* Handle emission */\n next({ offset }) {\n el.style.setProperty(\"--md-tooltip-x\", `${offset.x}px`)\n el.style.setProperty(\"--md-tooltip-y\", `${offset.y}px`)\n },\n\n /* Handle complete */\n complete() {\n el.style.removeProperty(\"--md-tooltip-x\")\n el.style.removeProperty(\"--md-tooltip-y\")\n }\n })\n\n /* Track relative origin of tooltip */\n push$\n .pipe(\n throttleTime(500, animationFrameScheduler),\n map(() => container.getBoundingClientRect()),\n map(({ x }) => x)\n )\n .subscribe({\n\n /* Handle emission */\n next(origin) {\n if (origin)\n el.style.setProperty(\"--md-tooltip-0\", `${-origin}px`)\n else\n el.style.removeProperty(\"--md-tooltip-0\")\n },\n\n /* Handle complete */\n complete() {\n el.style.removeProperty(\"--md-tooltip-0\")\n }\n })\n\n /* Close open annotation on click */\n const index = getElement(\":scope > :last-child\", el)\n const blur$ = fromEvent(index, \"mousedown\", { once: true })\n push$\n .pipe(\n switchMap(({ active }) => active ? blur$ : EMPTY),\n tap(ev => ev.preventDefault())\n )\n .subscribe(() => el.blur())\n\n /* Create and return component */\n return watchAnnotation(el, container)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n Subject,\n defer,\n finalize,\n merge,\n share,\n takeLast,\n takeUntil\n} from \"rxjs\"\n\nimport {\n getElement,\n getElements,\n getOptionalElement\n} from \"~/browser\"\nimport { renderAnnotation } from \"~/templates\"\n\nimport { Component } from \"../../../_\"\nimport {\n Annotation,\n mountAnnotation\n} from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n print$: Observable /* Media print observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Find all annotation markers in the given code block\n *\n * @param container - Containing element\n *\n * @returns Annotation markers\n */\nfunction findAnnotationMarkers(container: HTMLElement): Text[] {\n const markers: Text[] = []\n for (const comment of getElements(\".c, .c1, .cm\", container)) {\n let match: RegExpExecArray | null\n let text = comment.firstChild as Text\n\n /* Split text at marker and add to list */\n while ((match = /\\((\\d+)\\)/.exec(text.textContent!))) {\n const marker = text.splitText(match.index)\n text = marker.splitText(match[0].length)\n markers.push(marker)\n }\n }\n return markers\n}\n\n/**\n * Swap the child nodes of two elements\n *\n * @param source - Source element\n * @param target - Target element\n */\nfunction swap(source: HTMLElement, target: HTMLElement): void {\n target.append(...Array.from(source.childNodes))\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount annotation list\n *\n * This function analyzes the containing code block and checks for markers\n * referring to elements in the given annotation list. If no markers are found,\n * the list is left untouched. Otherwise, list elements are rendered as\n * annotations inside the code block.\n *\n * @param el - Annotation list element\n * @param container - Containing element\n * @param options - Options\n *\n * @returns Annotation component observable\n */\nexport function mountAnnotationList(\n el: HTMLElement, container: HTMLElement, { print$ }: MountOptions\n): Observable> {\n\n /* Find and replace all markers with empty annotations */\n const annotations = new Map()\n for (const marker of findAnnotationMarkers(container)) {\n const [, id] = marker.textContent!.match(/\\((\\d+)\\)/)!\n if (getOptionalElement(`li:nth-child(${id})`, el)) {\n annotations.set(+id, renderAnnotation(+id))\n marker.replaceWith(annotations.get(+id)!)\n }\n }\n\n /* Keep list if there are no annotations to render */\n if (annotations.size === 0)\n return EMPTY\n\n /* Create and return component */\n return defer(() => {\n const done$ = new Subject()\n\n /* Handle print mode - see https://bit.ly/3rgPdpt */\n print$\n .pipe(\n takeUntil(done$.pipe(takeLast(1)))\n )\n .subscribe(active => {\n el.hidden = !active\n\n /* Show annotations in code block or list (print) */\n for (const [id, annotation] of annotations) {\n const inner = getElement(\".md-typeset\", annotation)\n const child = getElement(`li:nth-child(${id})`, el)\n if (!active)\n swap(child, inner)\n else\n swap(inner, child)\n }\n })\n\n /* Create and return component */\n return merge(...[...annotations]\n .map(([, annotation]) => (\n mountAnnotation(annotation, container)\n ))\n )\n .pipe(\n finalize(() => done$.complete()),\n share()\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n mapTo,\n of,\n shareReplay,\n tap\n} from \"rxjs\"\n\nimport { watchScript } from \"~/browser\"\nimport { h } from \"~/utilities\"\n\nimport { Component } from \"../../../_\"\n\nimport themeCSS from \"./index.css\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mermaid diagram\n */\nexport interface Mermaid {}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Mermaid instance observable\n */\nlet mermaid$: Observable\n\n/**\n * Global index for Mermaid integration\n */\nlet index = 0\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch Mermaid script\n *\n * @returns Mermaid scripts observable\n */\nfunction fetchScripts(): Observable {\n return typeof mermaid === \"undefined\"\n ? watchScript(\"https://unpkg.com/mermaid@8.13.3/dist/mermaid.min.js\")\n : of(undefined)\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount Mermaid diagram\n *\n * @param el - Code block element\n *\n * @returns Mermaid diagram component observable\n */\nexport function mountMermaid(\n el: HTMLElement\n): Observable> {\n el.classList.remove(\"mermaid\") // Hack: mitigate https://bit.ly/3CiN6Du\n mermaid$ ||= fetchScripts()\n .pipe(\n tap(() => mermaid.initialize({\n startOnLoad: false,\n themeCSS\n })),\n mapTo(undefined),\n shareReplay(1)\n )\n\n /* Render diagram */\n mermaid$.subscribe(() => {\n el.classList.add(\"mermaid\") // Hack: mitigate https://bit.ly/3CiN6Du\n const id = `__mermaid_${index++}`\n const host = h(\"div\", { class: \"mermaid\" })\n mermaid.mermaidAPI.render(id, el.textContent, (svg: string) => {\n\n /* Create a shadow root and inject diagram */\n const shadow = host.attachShadow({ mode: \"closed\" })\n shadow.innerHTML = svg\n\n /* Replace code block with diagram */\n el.replaceWith(host)\n })\n })\n\n /* Create and return component */\n return mermaid$\n .pipe(\n mapTo({ ref: el })\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n defer,\n filter,\n finalize,\n map,\n mapTo,\n merge,\n tap\n} from \"rxjs\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Details\n */\nexport interface Details {\n action: \"open\" | \"close\" /* Details state */\n reveal?: boolean /* Details is revealed */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Media print observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Media print observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch details\n *\n * @param el - Details element\n * @param options - Options\n *\n * @returns Details observable\n */\nexport function watchDetails(\n el: HTMLDetailsElement, { target$, print$ }: WatchOptions\n): Observable
    {\n let open = true\n return merge(\n\n /* Open and focus details on location target */\n target$\n .pipe(\n map(target => target.closest(\"details:not([open])\")!),\n filter(details => el === details),\n mapTo
    ({ action: \"open\", reveal: true })\n ),\n\n /* Open details on print and close afterwards */\n print$\n .pipe(\n filter(active => active || !open),\n tap(() => open = el.open),\n map(active => ({\n action: active ? \"open\" : \"close\"\n }) as Details)\n )\n )\n}\n\n/**\n * Mount details\n *\n * This function ensures that `details` tags are opened on anchor jumps and\n * prior to printing, so the whole content of the page is visible.\n *\n * @param el - Details element\n * @param options - Options\n *\n * @returns Details component observable\n */\nexport function mountDetails(\n el: HTMLDetailsElement, options: MountOptions\n): Observable> {\n return defer(() => {\n const push$ = new Subject
    ()\n push$.subscribe(({ action, reveal }) => {\n if (action === \"open\")\n el.setAttribute(\"open\", \"\")\n else\n el.removeAttribute(\"open\")\n if (reveal)\n el.scrollIntoView()\n })\n\n /* Create and return component */\n return watchDetails(el, options)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, of } from \"rxjs\"\n\nimport { renderTable } from \"~/templates\"\nimport { h } from \"~/utilities\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Data table\n */\nexport interface DataTable {}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Sentinel for replacement\n */\nconst sentinel = h(\"table\")\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount data table\n *\n * This function wraps a data table in another scrollable container, so it can\n * be smoothly scrolled on smaller screen sizes and won't break the layout.\n *\n * @param el - Data table element\n *\n * @returns Data table component observable\n */\nexport function mountDataTable(\n el: HTMLElement\n): Observable> {\n el.replaceWith(sentinel)\n sentinel.replaceWith(renderTable(el))\n\n /* Create and return component */\n return of({ ref: el })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n auditTime,\n combineLatest,\n defer,\n finalize,\n fromEvent,\n map,\n mapTo,\n merge,\n startWith,\n takeLast,\n takeUntil,\n tap\n} from \"rxjs\"\n\nimport {\n getElement,\n getElementOffset,\n getElementSize,\n getElements,\n watchElementSize\n} from \"~/browser\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Content tabs\n */\nexport interface ContentTabs {\n active: HTMLLabelElement /* Active tab label */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch content tabs\n *\n * @param el - Content tabs element\n *\n * @returns Content tabs observable\n */\nexport function watchContentTabs(\n el: HTMLElement\n): Observable {\n const inputs = getElements(\":scope > input\", el)\n return merge(...inputs.map(input => fromEvent(input, \"change\")\n .pipe(\n mapTo({\n active: getElement(`label[for=${input.id}]`)\n })\n )\n ))\n .pipe(\n startWith({\n active: getElement(`label[for=${inputs[0].id}]`)\n } as ContentTabs)\n )\n}\n\n/**\n * Mount content tabs\n *\n * This function scrolls the active tab into view. While this functionality is\n * provided by browsers as part of `scrollInfoView`, browsers will always also\n * scroll the vertical axis, which we do not want. Thus, we decided to provide\n * this functionality ourselves.\n *\n * @param el - Content tabs element\n *\n * @returns Content tabs component observable\n */\nexport function mountContentTabs(\n el: HTMLElement\n): Observable> {\n const container = getElement(\".tabbed-labels\", el)\n return defer(() => {\n const push$ = new Subject()\n combineLatest([push$, watchElementSize(el)])\n .pipe(\n auditTime(1, animationFrameScheduler),\n takeUntil(push$.pipe(takeLast(1)))\n )\n .subscribe({\n\n /* Handle emission */\n next([{ active }]) {\n const offset = getElementOffset(active)\n const { width } = getElementSize(active)\n\n /* Set tab indicator offset and width */\n el.style.setProperty(\"--md-indicator-x\", `${offset.x}px`)\n el.style.setProperty(\"--md-indicator-width\", `${width}px`)\n\n /* Smoothly scroll container */\n container.scrollTo({\n behavior: \"smooth\",\n left: offset.x\n })\n },\n\n /* Handle complete */\n complete() {\n el.style.removeProperty(\"--md-indicator-x\")\n el.style.removeProperty(\"--md-indicator-width\")\n }\n })\n\n /* Create and return component */\n return watchContentTabs(el)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, merge } from \"rxjs\"\n\nimport { getElements } from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Annotation } from \"../annotation\"\nimport {\n CodeBlock,\n Mermaid,\n mountCodeBlock,\n mountMermaid\n} from \"../code\"\nimport {\n Details,\n mountDetails\n} from \"../details\"\nimport {\n DataTable,\n mountDataTable\n} from \"../table\"\nimport {\n ContentTabs,\n mountContentTabs\n} from \"../tabs\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Content\n */\nexport type Content =\n | Annotation\n | ContentTabs\n | CodeBlock\n | Mermaid\n | DataTable\n | Details\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Media print observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount content\n *\n * This function mounts all components that are found in the content of the\n * actual article, including code blocks, data tables and details.\n *\n * @param el - Content element\n * @param options - Options\n *\n * @returns Content component observable\n */\nexport function mountContent(\n el: HTMLElement, { target$, print$ }: MountOptions\n): Observable> {\n return merge(\n\n /* Code blocks */\n ...getElements(\"pre:not(.mermaid) > code\", el)\n .map(child => mountCodeBlock(child, { print$ })),\n\n /* Mermaid diagrams */\n ...getElements(\"pre.mermaid\", el)\n .map(child => mountMermaid(child)),\n\n /* Data tables */\n ...getElements(\"table:not([class])\", el)\n .map(child => mountDataTable(child)),\n\n /* Details */\n ...getElements(\"details\", el)\n .map(child => mountDetails(child, { target$, print$ })),\n\n /* Content tabs */\n ...getElements(\"[data-tabs]\", el)\n .map(child => mountContentTabs(child))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n defer,\n delay,\n finalize,\n map,\n merge,\n of,\n switchMap,\n tap\n} from \"rxjs\"\n\nimport { getElement } from \"~/browser\"\n\nimport { Component } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Dialog\n */\nexport interface Dialog {\n message: string /* Dialog message */\n active: boolean /* Dialog is active */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n alert$: Subject /* Alert subject */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n alert$: Subject /* Alert subject */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch dialog\n *\n * @param _el - Dialog element\n * @param options - Options\n *\n * @returns Dialog observable\n */\nexport function watchDialog(\n _el: HTMLElement, { alert$ }: WatchOptions\n): Observable {\n return alert$\n .pipe(\n switchMap(message => merge(\n of(true),\n of(false).pipe(delay(2000))\n )\n .pipe(\n map(active => ({ message, active }))\n )\n )\n )\n}\n\n/**\n * Mount dialog\n *\n * This function reveals the dialog in the right corner when a new alert is\n * emitted through the subject that is passed as part of the options.\n *\n * @param el - Dialog element\n * @param options - Options\n *\n * @returns Dialog component observable\n */\nexport function mountDialog(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const inner = getElement(\".md-typeset\", el)\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe(({ message, active }) => {\n inner.textContent = message\n if (active)\n el.setAttribute(\"data-md-state\", \"open\")\n else\n el.removeAttribute(\"data-md-state\")\n })\n\n /* Create and return component */\n return watchDialog(el, options)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n bufferCount,\n combineLatest,\n combineLatestWith,\n defer,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n filter,\n map,\n of,\n shareReplay,\n startWith,\n switchMap,\n takeLast,\n takeUntil\n} from \"rxjs\"\n\nimport { feature } from \"~/_\"\nimport {\n Viewport,\n watchElementSize,\n watchToggle\n} from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Main } from \"../../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Header\n */\nexport interface Header {\n height: number /* Header visible height */\n sticky: boolean /* Header stickyness */\n hidden: boolean /* Header is hidden */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Compute whether the header is hidden\n *\n * If the user scrolls past a certain threshold, the header can be hidden when\n * scrolling down, and shown when scrolling up.\n *\n * @param options - Options\n *\n * @returns Toggle observable\n */\nfunction isHidden({ viewport$ }: WatchOptions): Observable {\n if (!feature(\"header.autohide\"))\n return of(false)\n\n /* Compute direction and turning point */\n const direction$ = viewport$\n .pipe(\n map(({ offset: { y } }) => y),\n bufferCount(2, 1),\n map(([a, b]) => [a < b, b] as const),\n distinctUntilKeyChanged(0)\n )\n\n /* Compute whether header should be hidden */\n const hidden$ = combineLatest([viewport$, direction$])\n .pipe(\n filter(([{ offset }, [, y]]) => Math.abs(y - offset.y) > 100),\n map(([, [direction]]) => direction),\n distinctUntilChanged()\n )\n\n /* Compute threshold for hiding */\n const search$ = watchToggle(\"search\")\n return combineLatest([viewport$, search$])\n .pipe(\n map(([{ offset }, search]) => offset.y > 400 && !search),\n distinctUntilChanged(),\n switchMap(active => active ? hidden$ : of(false)),\n startWith(false)\n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch header\n *\n * @param el - Header element\n * @param options - Options\n *\n * @returns Header observable\n */\nexport function watchHeader(\n el: HTMLElement, options: WatchOptions\n): Observable
    {\n return defer(() => {\n const styles = getComputedStyle(el)\n return of(\n styles.position === \"sticky\" ||\n styles.position === \"-webkit-sticky\"\n )\n })\n .pipe(\n combineLatestWith(watchElementSize(el), isHidden(options)),\n map(([sticky, { height }, hidden]) => ({\n height: sticky ? height : 0,\n sticky,\n hidden\n })),\n distinctUntilChanged((a, b) => (\n a.sticky === b.sticky &&\n a.height === b.height &&\n a.hidden === b.hidden\n )),\n shareReplay(1)\n )\n}\n\n/**\n * Mount header\n *\n * This function manages the different states of the header, i.e. whether it's\n * hidden or rendered with a shadow. This depends heavily on the main area.\n *\n * @param el - Header element\n * @param options - Options\n *\n * @returns Header component observable\n */\nexport function mountHeader(\n el: HTMLElement, { header$, main$ }: MountOptions\n): Observable> {\n return defer(() => {\n const push$ = new Subject
    ()\n push$\n .pipe(\n distinctUntilKeyChanged(\"active\"),\n combineLatestWith(header$)\n )\n .subscribe(([{ active }, { hidden }]) => {\n if (active)\n el.setAttribute(\"data-md-state\", hidden ? \"hidden\" : \"shadow\")\n else\n el.removeAttribute(\"data-md-state\")\n })\n\n /* Link to main area */\n main$.subscribe(push$)\n\n /* Create and return component */\n return header$\n .pipe(\n takeUntil(push$.pipe(takeLast(1))),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n Subject,\n defer,\n distinctUntilKeyChanged,\n finalize,\n map,\n tap\n} from \"rxjs\"\n\nimport {\n Viewport,\n getElementSize,\n getOptionalElement,\n watchViewportAt\n} from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Header } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Header\n */\nexport interface HeaderTitle {\n active: boolean /* Header title is active */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch header title\n *\n * @param el - Heading element\n * @param options - Options\n *\n * @returns Header title observable\n */\nexport function watchHeaderTitle(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable {\n return watchViewportAt(el, { viewport$, header$ })\n .pipe(\n map(({ offset: { y } }) => {\n const { height } = getElementSize(el)\n return {\n active: y >= height\n }\n }),\n distinctUntilKeyChanged(\"active\")\n )\n}\n\n/**\n * Mount header title\n *\n * This function swaps the header title from the site title to the title of the\n * current page when the user scrolls past the first headline.\n *\n * @param el - Header title element\n * @param options - Options\n *\n * @returns Header title component observable\n */\nexport function mountHeaderTitle(\n el: HTMLElement, options: MountOptions\n): Observable> {\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe(({ active }) => {\n if (active)\n el.setAttribute(\"data-md-state\", \"active\")\n else\n el.removeAttribute(\"data-md-state\")\n })\n\n /* Obtain headline, if any */\n const heading = getOptionalElement(\"article h1\")\n if (typeof heading === \"undefined\")\n return EMPTY\n\n /* Create and return component */\n return watchHeaderTitle(heading, options)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n combineLatest,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n map,\n switchMap\n} from \"rxjs\"\n\nimport {\n Viewport,\n watchElementSize\n} from \"~/browser\"\n\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Main area\n */\nexport interface Main {\n offset: number /* Main area top offset */\n height: number /* Main area visible height */\n active: boolean /* Main area is active */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch main area\n *\n * This function returns an observable that computes the visual parameters of\n * the main area which depends on the viewport vertical offset and height, as\n * well as the height of the header element, if the header is fixed.\n *\n * @param el - Main area element\n * @param options - Options\n *\n * @returns Main area observable\n */\nexport function watchMain(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable
    {\n\n /* Compute necessary adjustment for header */\n const adjust$ = header$\n .pipe(\n map(({ height }) => height),\n distinctUntilChanged()\n )\n\n /* Compute the main area's top and bottom borders */\n const border$ = adjust$\n .pipe(\n switchMap(() => watchElementSize(el)\n .pipe(\n map(({ height }) => ({\n top: el.offsetTop,\n bottom: el.offsetTop + height\n })),\n distinctUntilKeyChanged(\"bottom\")\n )\n )\n )\n\n /* Compute the main area's offset, visible height and if we scrolled past */\n return combineLatest([adjust$, border$, viewport$])\n .pipe(\n map(([header, { top, bottom }, { offset: { y }, size: { height } }]) => {\n height = Math.max(0, height\n - Math.max(0, top - y, header)\n - Math.max(0, height + y - bottom)\n )\n return {\n offset: top - header,\n height,\n active: top - header <= y\n }\n }),\n distinctUntilChanged((a, b) => (\n a.offset === b.offset &&\n a.height === b.height &&\n a.active === b.active\n ))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n defer,\n finalize,\n fromEvent,\n map,\n mapTo,\n mergeMap,\n of,\n shareReplay,\n startWith,\n tap\n} from \"rxjs\"\n\nimport { getElements } from \"~/browser\"\n\nimport { Component } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Palette colors\n */\nexport interface PaletteColor {\n scheme?: string /* Color scheme */\n primary?: string /* Primary color */\n accent?: string /* Accent color */\n}\n\n/**\n * Palette\n */\nexport interface Palette {\n index: number /* Palette index */\n color: PaletteColor /* Palette colors */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch color palette\n *\n * @param inputs - Color palette element\n *\n * @returns Color palette observable\n */\nexport function watchPalette(\n inputs: HTMLInputElement[]\n): Observable {\n const current = __md_get(\"__palette\") || {\n index: inputs.findIndex(input => matchMedia(\n input.getAttribute(\"data-md-color-media\")!\n ).matches)\n }\n\n /* Emit changes in color palette */\n return of(...inputs)\n .pipe(\n mergeMap(input => fromEvent(input, \"change\")\n .pipe(\n mapTo(input)\n )\n ),\n startWith(inputs[Math.max(0, current.index)]),\n map(input => ({\n index: inputs.indexOf(input),\n color: {\n scheme: input.getAttribute(\"data-md-color-scheme\"),\n primary: input.getAttribute(\"data-md-color-primary\"),\n accent: input.getAttribute(\"data-md-color-accent\")\n }\n } as Palette)),\n shareReplay(1)\n )\n}\n\n/**\n * Mount color palette\n *\n * @param el - Color palette element\n *\n * @returns Color palette component observable\n */\nexport function mountPalette(\n el: HTMLElement\n): Observable> {\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe(palette => {\n\n /* Set color palette */\n for (const [key, value] of Object.entries(palette.color))\n document.body.setAttribute(`data-md-color-${key}`, value)\n\n /* Toggle visibility */\n for (let index = 0; index < inputs.length; index++) {\n const label = inputs[index].nextElementSibling\n if (label instanceof HTMLElement)\n label.hidden = palette.index !== index\n }\n\n /* Persist preference in local storage */\n __md_set(\"__palette\", palette)\n })\n\n /* Create and return component */\n const inputs = getElements(\"input\", el)\n return watchPalette(inputs)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ClipboardJS from \"clipboard\"\nimport {\n Observable,\n Subject,\n mapTo,\n tap\n} from \"rxjs\"\n\nimport { translation } from \"~/_\"\nimport { getElement } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Setup options\n */\ninterface SetupOptions {\n alert$: Subject /* Alert subject */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Extract text to copy\n *\n * @param el - HTML element\n *\n * @returns Extracted text\n */\nfunction extract(el: HTMLElement): string {\n el.setAttribute(\"data-md-copying\", \"\")\n const text = el.innerText\n el.removeAttribute(\"data-md-copying\")\n return text\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up Clipboard.js integration\n *\n * @param options - Options\n */\nexport function setupClipboardJS(\n { alert$ }: SetupOptions\n): void {\n if (ClipboardJS.isSupported()) {\n new Observable(subscriber => {\n new ClipboardJS(\"[data-clipboard-target], [data-clipboard-text]\", {\n text: el => (\n el.getAttribute(\"data-clipboard-text\")! ||\n extract(getElement(\n el.getAttribute(\"data-clipboard-target\")!\n ))\n )\n })\n .on(\"success\", ev => subscriber.next(ev))\n })\n .pipe(\n tap(ev => {\n const trigger = ev.trigger as HTMLElement\n trigger.focus()\n }),\n mapTo(translation(\"clipboard.copied\"))\n )\n .subscribe(alert$)\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n defaultIfEmpty,\n map,\n of,\n tap\n} from \"rxjs\"\n\nimport { configuration } from \"~/_\"\nimport { getElements, requestXML } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Sitemap, i.e. a list of URLs\n */\nexport type Sitemap = string[]\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Preprocess a list of URLs\n *\n * This function replaces the `site_url` in the sitemap with the actual base\n * URL, to allow instant loading to work in occasions like Netlify previews.\n *\n * @param urls - URLs\n *\n * @returns URL path parts\n */\nfunction preprocess(urls: Sitemap): Sitemap {\n if (urls.length < 2)\n return [\"\"]\n\n /* Take the first two URLs and remove everything after the last slash */\n const [root, next] = [...urls]\n .sort((a, b) => a.length - b.length)\n .map(url => url.replace(/[^/]+$/, \"\"))\n\n /* Compute common prefix */\n let index = 0\n if (root === next)\n index = root.length\n else\n while (root.charCodeAt(index) === next.charCodeAt(index))\n index++\n\n /* Remove common prefix and return in original order */\n return urls.map(url => url.replace(root.slice(0, index), \"\"))\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch the sitemap for the given base URL\n *\n * @param base - Base URL\n *\n * @returns Sitemap observable\n */\nexport function fetchSitemap(base?: URL): Observable {\n const cached = __md_get(\"__sitemap\", sessionStorage, base)\n if (cached) {\n return of(cached)\n } else {\n const config = configuration()\n return requestXML(new URL(\"sitemap.xml\", base || config.base))\n .pipe(\n map(sitemap => preprocess(getElements(\"loc\", sitemap)\n .map(node => node.textContent!)\n )),\n defaultIfEmpty([]),\n tap(sitemap => __md_set(\"__sitemap\", sitemap, sessionStorage, base))\n )\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n bufferCount,\n catchError,\n concatMap,\n debounceTime,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n filter,\n fromEvent,\n map,\n merge,\n of,\n sample,\n share,\n skip,\n skipUntil,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"~/_\"\nimport {\n Viewport,\n ViewportOffset,\n getElements,\n getOptionalElement,\n request,\n setLocation,\n setLocationHash\n} from \"~/browser\"\nimport { getComponentElement } from \"~/components\"\nimport { h } from \"~/utilities\"\n\nimport { fetchSitemap } from \"../sitemap\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * History state\n */\nexport interface HistoryState {\n url: URL /* State URL */\n offset?: ViewportOffset /* State viewport offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Setup options\n */\ninterface SetupOptions {\n document$: Subject /* Document subject */\n location$: Subject /* Location subject */\n viewport$: Observable /* Viewport observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up instant loading\n *\n * When fetching, theoretically, we could use `responseType: \"document\"`, but\n * since all MkDocs links are relative, we need to make sure that the current\n * location matches the document we just loaded. Otherwise any relative links\n * in the document could use the old location.\n *\n * This is the reason why we need to synchronize history events and the process\n * of fetching the document for navigation changes (except `popstate` events):\n *\n * 1. Fetch document via `XMLHTTPRequest`\n * 2. Set new location via `history.pushState`\n * 3. Parse and emit fetched document\n *\n * For `popstate` events, we must not use `history.pushState`, or the forward\n * history will be irreversibly overwritten. In case the request fails, the\n * location change is dispatched regularly.\n *\n * @param options - Options\n */\nexport function setupInstantLoading(\n { document$, location$, viewport$ }: SetupOptions\n): void {\n const config = configuration()\n if (location.protocol === \"file:\")\n return\n\n /* Disable automatic scroll restoration */\n if (\"scrollRestoration\" in history) {\n history.scrollRestoration = \"manual\"\n\n /* Hack: ensure that reloads restore viewport offset */\n fromEvent(window, \"beforeunload\")\n .subscribe(() => {\n history.scrollRestoration = \"auto\"\n })\n }\n\n /* Hack: ensure absolute favicon link to omit 404s when switching */\n const favicon = getOptionalElement(\"link[rel=icon]\")\n if (typeof favicon !== \"undefined\")\n favicon.href = favicon.href\n\n /* Intercept internal navigation */\n const push$ = fetchSitemap()\n .pipe(\n map(paths => paths.map(path => `${new URL(path, config.base)}`)),\n switchMap(urls => fromEvent(document.body, \"click\")\n .pipe(\n filter(ev => !ev.metaKey && !ev.ctrlKey),\n switchMap(ev => {\n if (ev.target instanceof Element) {\n const el = ev.target.closest(\"a\")\n if (el && !el.target) {\n const url = new URL(el.href)\n\n /* Canonicalize URL */\n url.search = \"\"\n url.hash = \"\"\n\n /* Check if URL should be intercepted */\n if (\n url.pathname !== location.pathname &&\n urls.includes(url.toString())\n ) {\n ev.preventDefault()\n return of({\n url: new URL(el.href)\n })\n }\n }\n }\n return NEVER\n })\n )\n ),\n share()\n )\n\n /* Intercept history back and forward */\n const pop$ = fromEvent(window, \"popstate\")\n .pipe(\n filter(ev => ev.state !== null),\n map(ev => ({\n url: new URL(location.href),\n offset: ev.state\n })),\n share()\n )\n\n /* Emit location change */\n merge(push$, pop$)\n .pipe(\n distinctUntilChanged((a, b) => a.url.href === b.url.href),\n map(({ url }) => url)\n )\n .subscribe(location$)\n\n /* Fetch document via `XMLHTTPRequest` */\n const response$ = location$\n .pipe(\n distinctUntilKeyChanged(\"pathname\"),\n switchMap(url => request(url.href)\n .pipe(\n catchError(() => {\n setLocation(url)\n return NEVER\n })\n )\n ),\n share()\n )\n\n /* Set new location via `history.pushState` */\n push$\n .pipe(\n sample(response$)\n )\n .subscribe(({ url }) => {\n history.pushState({}, \"\", `${url}`)\n })\n\n /* Parse and emit fetched document */\n const dom = new DOMParser()\n response$\n .pipe(\n switchMap(res => res.text()),\n map(res => dom.parseFromString(res, \"text/html\"))\n )\n .subscribe(document$)\n\n /* Replace meta tags and components */\n document$\n .pipe(\n skip(1)\n )\n .subscribe(replacement => {\n for (const selector of [\n\n /* Meta tags */\n \"title\",\n \"link[rel=canonical]\",\n \"meta[name=author]\",\n \"meta[name=description]\",\n\n /* Components */\n \"[data-md-component=announce]\",\n \"[data-md-component=container]\",\n \"[data-md-component=header-topic]\",\n \"[data-md-component=logo]\",\n \"[data-md-component=skip]\",\n ...feature(\"navigation.tabs.sticky\")\n ? [\"[data-md-component=tabs]\"]\n : []\n ]) {\n const source = getOptionalElement(selector)\n const target = getOptionalElement(selector, replacement)\n if (\n typeof source !== \"undefined\" &&\n typeof target !== \"undefined\"\n ) {\n source.replaceWith(target)\n }\n }\n })\n\n /* Re-evaluate scripts */\n document$\n .pipe(\n skip(1),\n map(() => getComponentElement(\"container\")),\n switchMap(el => of(...getElements(\"script\", el))),\n concatMap(el => {\n const script = h(\"script\")\n if (el.src) {\n for (const name of el.getAttributeNames())\n script.setAttribute(name, el.getAttribute(name)!)\n el.replaceWith(script)\n\n /* Complete when script is loaded */\n return new Observable(observer => {\n script.onload = () => observer.complete()\n })\n\n /* Complete immediately */\n } else {\n script.textContent = el.textContent\n el.replaceWith(script)\n return EMPTY\n }\n })\n )\n .subscribe()\n\n /* Emit history state change */\n merge(push$, pop$)\n .pipe(\n sample(document$)\n )\n .subscribe(({ url, offset }) => {\n if (url.hash && !offset) {\n setLocationHash(url.hash)\n } else {\n window.scrollTo(0, offset?.y || 0)\n }\n })\n\n /* Debounce update of viewport offset */\n viewport$\n .pipe(\n skipUntil(push$),\n debounceTime(250),\n distinctUntilKeyChanged(\"offset\")\n )\n .subscribe(({ offset }) => {\n history.replaceState(offset, \"\")\n })\n\n /* Set viewport offset from history */\n merge(push$, pop$)\n .pipe(\n bufferCount(2, 1),\n filter(([a, b]) => a.url.pathname === b.url.pathname),\n map(([, state]) => state)\n )\n .subscribe(({ offset }) => {\n window.scrollTo(0, offset?.y || 0)\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexDocument } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search document\n */\nexport interface SearchDocument extends SearchIndexDocument {\n parent?: SearchIndexDocument /* Parent article */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search document mapping\n */\nexport type SearchDocumentMap = Map\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search document mapping\n *\n * @param docs - Search index documents\n *\n * @returns Search document map\n */\nexport function setupSearchDocumentMap(\n docs: SearchIndexDocument[]\n): SearchDocumentMap {\n const documents = new Map()\n const parents = new Set()\n for (const doc of docs) {\n const [path, hash] = doc.location.split(\"#\")\n\n /* Extract location, title and tags */\n const location = doc.location\n const title = doc.title\n const tags = doc.tags\n\n /* Escape and cleanup text */\n const text = escapeHTML(doc.text)\n .replace(/\\s+(?=[,.:;!?])/g, \"\")\n .replace(/\\s+/g, \" \")\n\n /* Handle section */\n if (hash) {\n const parent = documents.get(path)!\n\n /* Ignore first section, override article */\n if (!parents.has(parent)) {\n parent.title = doc.title\n parent.text = text\n\n /* Remember that we processed the article */\n parents.add(parent)\n\n /* Add subsequent section */\n } else {\n documents.set(location, {\n location,\n title,\n text,\n parent\n })\n }\n\n /* Add article */\n } else {\n documents.set(location, {\n location,\n title,\n text,\n ...tags && { tags }\n })\n }\n }\n return documents\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexConfig } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search highlight function\n *\n * @param value - Value\n *\n * @returns Highlighted value\n */\nexport type SearchHighlightFn = (value: string) => string\n\n/**\n * Search highlight factory function\n *\n * @param query - Query value\n *\n * @returns Search highlight function\n */\nexport type SearchHighlightFactoryFn = (query: string) => SearchHighlightFn\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search highlighter\n *\n * @param config - Search index configuration\n * @param escape - Whether to escape HTML\n *\n * @returns Search highlight factory function\n */\nexport function setupSearchHighlighter(\n config: SearchIndexConfig, escape: boolean\n): SearchHighlightFactoryFn {\n const separator = new RegExp(config.separator, \"img\")\n const highlight = (_: unknown, data: string, term: string) => {\n return `${data}${term}`\n }\n\n /* Return factory function */\n return (query: string) => {\n query = query\n .replace(/[\\s*+\\-:~^]+/g, \" \")\n .trim()\n\n /* Create search term match expression */\n const match = new RegExp(`(^|${config.separator})(${\n query\n .replace(/[|\\\\{}()[\\]^$+*?.-]/g, \"\\\\$&\")\n .replace(separator, \"|\")\n })`, \"img\")\n\n /* Highlight string value */\n return value => (\n escape\n ? escapeHTML(value)\n : value\n )\n .replace(match, highlight)\n .replace(/<\\/mark>(\\s+)]*>/img, \"$1\")\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search transformation function\n *\n * @param value - Query value\n *\n * @returns Transformed query value\n */\nexport type SearchTransformFn = (value: string) => string\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Default transformation function\n *\n * 1. Search for terms in quotation marks and prepend a `+` modifier to denote\n * that the resulting document must contain all terms, converting the query\n * to an `AND` query (as opposed to the default `OR` behavior). While users\n * may expect terms enclosed in quotation marks to map to span queries, i.e.\n * for which order is important, Lunr.js doesn't support them, so the best\n * we can do is to convert the terms to an `AND` query.\n *\n * 2. Replace control characters which are not located at the beginning of the\n * query or preceded by white space, or are not followed by a non-whitespace\n * character or are at the end of the query string. Furthermore, filter\n * unmatched quotation marks.\n *\n * 3. Trim excess whitespace from left and right.\n *\n * @param query - Query value\n *\n * @returns Transformed query value\n */\nexport function defaultTransform(query: string): string {\n return query\n .split(/\"([^\"]+)\"/g) /* => 1 */\n .map((terms, index) => index & 1\n ? terms.replace(/^\\b|^(?![^\\x00-\\x7F]|$)|\\s+/g, \" +\")\n : terms\n )\n .join(\"\")\n .replace(/\"|(?:^|\\s+)[*+\\-:^~]+(?=\\s+|$)/g, \"\") /* => 2 */\n .trim() /* => 3 */\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SearchIndex, SearchResult } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search message type\n */\nexport const enum SearchMessageType {\n SETUP, /* Search index setup */\n READY, /* Search index ready */\n QUERY, /* Search query */\n RESULT /* Search results */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Message containing the data necessary to setup the search index\n */\nexport interface SearchSetupMessage {\n type: SearchMessageType.SETUP /* Message type */\n data: SearchIndex /* Message data */\n}\n\n/**\n * Message indicating the search index is ready\n */\nexport interface SearchReadyMessage {\n type: SearchMessageType.READY /* Message type */\n}\n\n/**\n * Message containing a search query\n */\nexport interface SearchQueryMessage {\n type: SearchMessageType.QUERY /* Message type */\n data: string /* Message data */\n}\n\n/**\n * Message containing results for a search query\n */\nexport interface SearchResultMessage {\n type: SearchMessageType.RESULT /* Message type */\n data: SearchResult /* Message data */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Message exchanged with the search worker\n */\nexport type SearchMessage =\n | SearchSetupMessage\n | SearchReadyMessage\n | SearchQueryMessage\n | SearchResultMessage\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Type guard for search setup messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchSetupMessage(\n message: SearchMessage\n): message is SearchSetupMessage {\n return message.type === SearchMessageType.SETUP\n}\n\n/**\n * Type guard for search ready messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchReadyMessage(\n message: SearchMessage\n): message is SearchReadyMessage {\n return message.type === SearchMessageType.READY\n}\n\n/**\n * Type guard for search query messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchQueryMessage(\n message: SearchMessage\n): message is SearchQueryMessage {\n return message.type === SearchMessageType.QUERY\n}\n\n/**\n * Type guard for search result messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchResultMessage(\n message: SearchMessage\n): message is SearchResultMessage {\n return message.type === SearchMessageType.RESULT\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n ObservableInput,\n Subject,\n from,\n map,\n share\n} from \"rxjs\"\n\nimport { configuration, feature, translation } from \"~/_\"\nimport { WorkerHandler, watchWorker } from \"~/browser\"\n\nimport { SearchIndex } from \"../../_\"\nimport {\n SearchOptions,\n SearchPipeline\n} from \"../../options\"\nimport {\n SearchMessage,\n SearchMessageType,\n SearchSetupMessage,\n isSearchResultMessage\n} from \"../message\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search worker\n */\nexport type SearchWorker = WorkerHandler\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up search index\n *\n * @param data - Search index\n *\n * @returns Search index\n */\nfunction setupSearchIndex({ config, docs }: SearchIndex): SearchIndex {\n\n /* Override default language with value from translation */\n if (config.lang.length === 1 && config.lang[0] === \"en\")\n config.lang = [\n translation(\"search.config.lang\")\n ]\n\n /* Override default separator with value from translation */\n if (config.separator === \"[\\\\s\\\\-]+\")\n config.separator = translation(\"search.config.separator\")\n\n /* Set pipeline from translation */\n const pipeline = translation(\"search.config.pipeline\")\n .split(/\\s*,\\s*/)\n .filter(Boolean) as SearchPipeline\n\n /* Determine search options */\n const options: SearchOptions = {\n pipeline,\n suggestions: feature(\"search.suggest\")\n }\n\n /* Return search index after defaulting */\n return { config, docs, options }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up search worker\n *\n * This function creates a web worker to set up and query the search index,\n * which is done using Lunr.js. The index must be passed as an observable to\n * enable hacks like _localsearch_ via search index embedding as JSON.\n *\n * @param url - Worker URL\n * @param index - Search index observable input\n *\n * @returns Search worker\n */\nexport function setupSearchWorker(\n url: string, index: ObservableInput\n): SearchWorker {\n const config = configuration()\n const worker = new Worker(url)\n\n /* Create communication channels and resolve relative links */\n const tx$ = new Subject()\n const rx$ = watchWorker(worker, { tx$ })\n .pipe(\n map(message => {\n if (isSearchResultMessage(message)) {\n for (const result of message.data.items)\n for (const document of result)\n document.location = `${new URL(document.location, config.base)}`\n }\n return message\n }),\n share()\n )\n\n /* Set up search index */\n from(index)\n .pipe(\n map(data => ({\n type: SearchMessageType.SETUP,\n data: setupSearchIndex(data)\n } as SearchSetupMessage))\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Return search worker */\n return { tx$, rx$ }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n combineLatest,\n filter,\n fromEvent,\n map,\n of,\n switchMap\n} from \"rxjs\"\n\nimport { configuration } from \"~/_\"\nimport {\n getElement,\n getLocation,\n requestJSON,\n setLocation\n} from \"~/browser\"\nimport { getComponentElements } from \"~/components\"\nimport {\n Version,\n renderVersionSelector\n} from \"~/templates\"\n\nimport { fetchSitemap } from \"../sitemap\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up version selector\n */\nexport function setupVersionSelector(): void {\n const config = configuration()\n const versions$ = requestJSON(\n new URL(\"../versions.json\", config.base)\n )\n\n /* Determine current version */\n const current$ = versions$\n .pipe(\n map(versions => {\n const [, current] = config.base.match(/([^/]+)\\/?$/)!\n return versions.find(({ version, aliases }) => (\n version === current || aliases.includes(current)\n )) || versions[0]\n })\n )\n\n /* Intercept inter-version navigation */\n combineLatest([versions$, current$])\n .pipe(\n map(([versions, current]) => new Map(versions\n .filter(version => version !== current)\n .map(version => [\n `${new URL(`../${version.version}/`, config.base)}`,\n version\n ])\n )),\n switchMap(urls => fromEvent(document.body, \"click\")\n .pipe(\n filter(ev => !ev.metaKey && !ev.ctrlKey),\n switchMap(ev => {\n if (ev.target instanceof Element) {\n const el = ev.target.closest(\"a\")\n if (el && !el.target && urls.has(el.href)) {\n ev.preventDefault()\n return of(el.href)\n }\n }\n return EMPTY\n }),\n switchMap(url => {\n const { version } = urls.get(url)!\n return fetchSitemap(new URL(url))\n .pipe(\n map(sitemap => {\n const location = getLocation()\n const path = location.href.replace(config.base, \"\")\n return sitemap.includes(path)\n ? new URL(`../${version}/${path}`, config.base)\n : new URL(url)\n })\n )\n })\n )\n )\n )\n .subscribe(url => setLocation(url))\n\n /* Render version selector and warning */\n combineLatest([versions$, current$])\n .subscribe(([versions, current]) => {\n const topic = getElement(\".md-header__topic\")\n topic.appendChild(renderVersionSelector(versions, current))\n\n /* Check if version state was already determined */\n if (__md_get(\"__outdated\", sessionStorage) === null) {\n const latest = config.version?.default || \"latest\"\n const outdated = !current.aliases.includes(latest)\n\n /* Persist version state in session storage */\n __md_set(\"__outdated\", outdated, sessionStorage)\n if (outdated)\n for (const warning of getComponentElements(\"outdated\"))\n warning.hidden = false\n }\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n combineLatest,\n delay,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n filter,\n finalize,\n fromEvent,\n map,\n merge,\n shareReplay,\n startWith,\n take,\n takeLast,\n takeUntil,\n tap\n} from \"rxjs\"\n\nimport { translation } from \"~/_\"\nimport {\n getLocation,\n setToggle,\n watchElementFocus\n} from \"~/browser\"\nimport {\n SearchMessageType,\n SearchQueryMessage,\n SearchWorker,\n defaultTransform,\n isSearchReadyMessage\n} from \"~/integrations\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search query\n */\nexport interface SearchQuery {\n value: string /* Query value */\n focus: boolean /* Query focus */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch search query\n *\n * Note that the focus event which triggers re-reading the current query value\n * is delayed by `1ms` so the input's empty state is allowed to propagate.\n *\n * @param el - Search query element\n * @param worker - Search worker\n *\n * @returns Search query observable\n */\nexport function watchSearchQuery(\n el: HTMLInputElement, { rx$ }: SearchWorker\n): Observable {\n const fn = __search?.transform || defaultTransform\n\n /* Immediately show search dialog */\n const { searchParams } = getLocation()\n if (searchParams.has(\"q\"))\n setToggle(\"search\", true)\n\n /* Intercept query parameter (deep link) */\n const param$ = rx$\n .pipe(\n filter(isSearchReadyMessage),\n take(1),\n map(() => searchParams.get(\"q\") || \"\")\n )\n\n /* Set query from parameter */\n param$.subscribe(value => { // TODO: not ideal - find a better way\n if (value)\n el.value = value\n })\n\n /* Intercept focus and input events */\n const focus$ = watchElementFocus(el)\n const value$ = merge(\n fromEvent(el, \"keyup\"),\n fromEvent(el, \"focus\").pipe(delay(1)),\n param$\n )\n .pipe(\n map(() => fn(el.value)),\n startWith(\"\"),\n distinctUntilChanged(),\n )\n\n /* Combine into single observable */\n return combineLatest([value$, focus$])\n .pipe(\n map(([value, focus]) => ({ value, focus })),\n shareReplay(1)\n )\n}\n\n/**\n * Mount search query\n *\n * @param el - Search query element\n * @param worker - Search worker\n *\n * @returns Search query component observable\n */\nexport function mountSearchQuery(\n el: HTMLInputElement, { tx$, rx$ }: SearchWorker\n): Observable> {\n const push$ = new Subject()\n\n /* Handle value changes */\n push$\n .pipe(\n distinctUntilKeyChanged(\"value\"),\n map(({ value }): SearchQueryMessage => ({\n type: SearchMessageType.QUERY,\n data: value\n }))\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Handle focus changes */\n push$\n .pipe(\n distinctUntilKeyChanged(\"focus\")\n )\n .subscribe(({ focus }) => {\n if (focus) {\n setToggle(\"search\", focus)\n el.placeholder = \"\"\n } else {\n el.placeholder = translation(\"search.placeholder\")\n }\n })\n\n /* Handle reset */\n fromEvent(el.form!, \"reset\")\n .pipe(\n takeUntil(push$.pipe(takeLast(1)))\n )\n .subscribe(() => el.focus())\n\n /* Create and return component */\n return watchSearchQuery(el, { tx$, rx$ })\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n bufferCount,\n filter,\n finalize,\n map,\n merge,\n of,\n skipUntil,\n switchMap,\n take,\n tap,\n withLatestFrom,\n zipWith\n} from \"rxjs\"\n\nimport { translation } from \"~/_\"\nimport {\n getElement,\n watchElementBoundary\n} from \"~/browser\"\nimport {\n SearchResult,\n SearchWorker,\n isSearchReadyMessage,\n isSearchResultMessage\n} from \"~/integrations\"\nimport { renderSearchResultItem } from \"~/templates\"\nimport { round } from \"~/utilities\"\n\nimport { Component } from \"../../_\"\nimport { SearchQuery } from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n query$: Observable /* Search query observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search result list\n *\n * This function performs a lazy rendering of the search results, depending on\n * the vertical offset of the search result container.\n *\n * @param el - Search result list element\n * @param worker - Search worker\n * @param options - Options\n *\n * @returns Search result list component observable\n */\nexport function mountSearchResult(\n el: HTMLElement, { rx$ }: SearchWorker, { query$ }: MountOptions\n): Observable> {\n const push$ = new Subject()\n const boundary$ = watchElementBoundary(el.parentElement!)\n .pipe(\n filter(Boolean)\n )\n\n /* Retrieve nested components */\n const meta = getElement(\":scope > :first-child\", el)\n const list = getElement(\":scope > :last-child\", el)\n\n /* Wait until search is ready */\n const ready$ = rx$\n .pipe(\n filter(isSearchReadyMessage),\n take(1)\n )\n\n /* Update search result metadata */\n push$\n .pipe(\n withLatestFrom(query$),\n skipUntil(ready$)\n )\n .subscribe(([{ items }, { value }]) => {\n if (value) {\n switch (items.length) {\n\n /* No results */\n case 0:\n meta.textContent = translation(\"search.result.none\")\n break\n\n /* One result */\n case 1:\n meta.textContent = translation(\"search.result.one\")\n break\n\n /* Multiple result */\n default:\n meta.textContent = translation(\n \"search.result.other\",\n round(items.length)\n )\n }\n } else {\n meta.textContent = translation(\"search.result.placeholder\")\n }\n })\n\n /* Update search result list */\n push$\n .pipe(\n tap(() => list.innerHTML = \"\"),\n switchMap(({ items }) => merge(\n of(...items.slice(0, 10)),\n of(...items.slice(10))\n .pipe(\n bufferCount(4),\n zipWith(boundary$),\n switchMap(([chunk]) => of(...chunk))\n )\n ))\n )\n .subscribe(result => list.appendChild(\n renderSearchResultItem(result)\n ))\n\n /* Filter search result message */\n const result$ = rx$\n .pipe(\n filter(isSearchResultMessage),\n map(({ data }) => data)\n )\n\n /* Create and return component */\n return result$\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n finalize,\n fromEvent,\n map,\n tap\n} from \"rxjs\"\n\nimport { getLocation } from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { SearchQuery } from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search sharing\n */\nexport interface SearchShare {\n url: URL /* Deep link for sharing */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n query$: Observable /* Search query observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n query$: Observable /* Search query observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search sharing\n *\n * @param _el - Search sharing element\n * @param options - Options\n *\n * @returns Search sharing observable\n */\nexport function watchSearchShare(\n _el: HTMLElement, { query$ }: WatchOptions\n): Observable {\n return query$\n .pipe(\n map(({ value }) => {\n const url = getLocation()\n url.hash = \"\"\n url.searchParams.delete(\"h\")\n url.searchParams.set(\"q\", value)\n return { url }\n })\n )\n}\n\n/**\n * Mount search sharing\n *\n * @param el - Search sharing element\n * @param options - Options\n *\n * @returns Search sharing component observable\n */\nexport function mountSearchShare(\n el: HTMLAnchorElement, options: MountOptions\n): Observable> {\n const push$ = new Subject()\n push$.subscribe(({ url }) => {\n el.setAttribute(\"data-clipboard-text\", el.href)\n el.href = `${url}`\n })\n\n /* Prevent following of link */\n fromEvent(el, \"click\")\n .subscribe(ev => ev.preventDefault())\n\n /* Create and return component */\n return watchSearchShare(el, options)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n asyncScheduler,\n combineLatestWith,\n distinctUntilChanged,\n filter,\n finalize,\n fromEvent,\n map,\n merge,\n observeOn,\n tap\n} from \"rxjs\"\n\nimport { Keyboard } from \"~/browser\"\nimport {\n SearchResult,\n SearchWorker,\n isSearchResultMessage\n} from \"~/integrations\"\n\nimport { Component, getComponentElement } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search suggestions\n */\nexport interface SearchSuggest {}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n keyboard$: Observable /* Keyboard observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search suggestions\n *\n * This function will perform a lazy rendering of the search results, depending\n * on the vertical offset of the search result container.\n *\n * @param el - Search result list element\n * @param worker - Search worker\n * @param options - Options\n *\n * @returns Search result list component observable\n */\nexport function mountSearchSuggest(\n el: HTMLElement, { rx$ }: SearchWorker, { keyboard$ }: MountOptions\n): Observable> {\n const push$ = new Subject()\n\n /* Retrieve query component and track all changes */\n const query = getComponentElement(\"search-query\")\n const query$ = merge(\n fromEvent(query, \"keydown\"),\n fromEvent(query, \"focus\")\n )\n .pipe(\n observeOn(asyncScheduler),\n map(() => query.value),\n distinctUntilChanged(),\n )\n\n /* Update search suggestions */\n push$\n .pipe(\n combineLatestWith(query$),\n map(([{ suggestions }, value]) => {\n const words = value.split(/([\\s-]+)/)\n if (suggestions?.length && words[words.length - 1]) {\n const last = suggestions[suggestions.length - 1]\n if (last.startsWith(words[words.length - 1]))\n words[words.length - 1] = last\n } else {\n words.length = 0\n }\n return words\n })\n )\n .subscribe(words => el.innerHTML = words\n .join(\"\")\n .replace(/\\s/g, \" \")\n )\n\n /* Set up search keyboard handlers */\n keyboard$\n .pipe(\n filter(({ mode }) => mode === \"search\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Right arrow: accept current suggestion */\n case \"ArrowRight\":\n if (\n el.innerText.length &&\n query.selectionStart === query.value.length\n )\n query.value = el.innerText\n break\n }\n })\n\n /* Filter search result message */\n const result$ = rx$\n .pipe(\n filter(isSearchResultMessage),\n map(({ data }) => data)\n )\n\n /* Create and return component */\n return result$\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(() => ({ ref: el }))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n NEVER,\n Observable,\n ObservableInput,\n filter,\n merge,\n mergeWith,\n sample,\n take\n} from \"rxjs\"\n\nimport { configuration } from \"~/_\"\nimport {\n Keyboard,\n getActiveElement,\n getElements,\n setToggle\n} from \"~/browser\"\nimport {\n SearchIndex,\n SearchResult,\n isSearchQueryMessage,\n isSearchReadyMessage,\n setupSearchWorker\n} from \"~/integrations\"\n\nimport {\n Component,\n getComponentElement,\n getComponentElements\n} from \"../../_\"\nimport {\n SearchQuery,\n mountSearchQuery\n} from \"../query\"\nimport { mountSearchResult } from \"../result\"\nimport {\n SearchShare,\n mountSearchShare\n} from \"../share\"\nimport {\n SearchSuggest,\n mountSearchSuggest\n} from \"../suggest\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search\n */\nexport type Search =\n | SearchQuery\n | SearchResult\n | SearchShare\n | SearchSuggest\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n index$: ObservableInput /* Search index observable */\n keyboard$: Observable /* Keyboard observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search\n *\n * This function sets up the search functionality, including the underlying\n * web worker and all keyboard bindings.\n *\n * @param el - Search element\n * @param options - Options\n *\n * @returns Search component observable\n */\nexport function mountSearch(\n el: HTMLElement, { index$, keyboard$ }: MountOptions\n): Observable> {\n const config = configuration()\n try {\n const url = __search?.worker || config.search\n const worker = setupSearchWorker(url, index$)\n\n /* Retrieve query and result components */\n const query = getComponentElement(\"search-query\", el)\n const result = getComponentElement(\"search-result\", el)\n\n /* Re-emit query when search is ready */\n const { tx$, rx$ } = worker\n tx$\n .pipe(\n filter(isSearchQueryMessage),\n sample(rx$.pipe(filter(isSearchReadyMessage))),\n take(1)\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Set up search keyboard handlers */\n keyboard$\n .pipe(\n filter(({ mode }) => mode === \"search\")\n )\n .subscribe(key => {\n const active = getActiveElement()\n switch (key.type) {\n\n /* Enter: go to first (best) result */\n case \"Enter\":\n if (active === query) {\n const anchors = new Map()\n for (const anchor of getElements(\n \":first-child [href]\", result\n )) {\n const article = anchor.firstElementChild!\n anchors.set(anchor, parseFloat(\n article.getAttribute(\"data-md-score\")!\n ))\n }\n\n /* Go to result with highest score, if any */\n if (anchors.size) {\n const [[best]] = [...anchors].sort(([, a], [, b]) => b - a)\n best.click()\n }\n\n /* Otherwise omit form submission */\n key.claim()\n }\n break\n\n /* Escape or Tab: close search */\n case \"Escape\":\n case \"Tab\":\n setToggle(\"search\", false)\n query.blur()\n break\n\n /* Vertical arrows: select previous or next search result */\n case \"ArrowUp\":\n case \"ArrowDown\":\n if (typeof active === \"undefined\") {\n query.focus()\n } else {\n const els = [query, ...getElements(\n \":not(details) > [href], summary, details[open] [href]\",\n result\n )]\n const i = Math.max(0, (\n Math.max(0, els.indexOf(active)) + els.length + (\n key.type === \"ArrowUp\" ? -1 : +1\n )\n ) % els.length)\n els[i].focus()\n }\n\n /* Prevent scrolling of page */\n key.claim()\n break\n\n /* All other keys: hand to search query */\n default:\n if (query !== getActiveElement())\n query.focus()\n }\n })\n\n /* Set up global keyboard handlers */\n keyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\"),\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Open search and select query */\n case \"f\":\n case \"s\":\n case \"/\":\n query.focus()\n query.select()\n\n /* Prevent scrolling of page */\n key.claim()\n break\n }\n })\n\n /* Create and return component */\n const query$ = mountSearchQuery(query, worker)\n const result$ = mountSearchResult(result, worker, { query$ })\n return merge(query$, result$)\n .pipe(\n mergeWith(\n\n /* Search sharing */\n ...getComponentElements(\"search-share\", el)\n .map(child => mountSearchShare(child, { query$ })),\n\n /* Search suggestions */\n ...getComponentElements(\"search-suggest\", el)\n .map(child => mountSearchSuggest(child, worker, { keyboard$ }))\n )\n )\n\n /* Gracefully handle broken search */\n } catch (err) {\n el.hidden = true\n return NEVER\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n ObservableInput,\n combineLatest,\n filter,\n map,\n startWith\n} from \"rxjs\"\n\nimport { getLocation } from \"~/browser\"\nimport {\n SearchIndex,\n setupSearchHighlighter\n} from \"~/integrations\"\nimport { h } from \"~/utilities\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search highlighting\n */\nexport interface SearchHighlight {\n nodes: Map /* Map of replacements */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n index$: ObservableInput /* Search index observable */\n location$: Observable /* Location observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search highlighting\n *\n * @param el - Content element\n * @param options - Options\n *\n * @returns Search highlighting component observable\n */\nexport function mountSearchHiglight(\n el: HTMLElement, { index$, location$ }: MountOptions\n): Observable> {\n return combineLatest([\n index$,\n location$\n .pipe(\n startWith(getLocation()),\n filter(url => !!url.searchParams.get(\"h\"))\n )\n ])\n .pipe(\n map(([index, url]) => setupSearchHighlighter(index.config, true)(\n url.searchParams.get(\"h\")!\n )),\n map(fn => {\n const nodes = new Map()\n\n /* Traverse text nodes and collect matches */\n const it = document.createNodeIterator(el, NodeFilter.SHOW_TEXT)\n for (let node = it.nextNode(); node; node = it.nextNode()) {\n if (node.parentElement?.offsetHeight) {\n const original = node.textContent!\n const replaced = fn(original)\n if (replaced.length > original.length)\n nodes.set(node as ChildNode, replaced)\n }\n }\n\n /* Replace original nodes with matches */\n for (const [node, text] of nodes) {\n const { childNodes } = h(\"span\", null, text)\n node.replaceWith(...Array.from(childNodes))\n }\n\n /* Return component */\n return { ref: el, nodes }\n })\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n auditTime,\n combineLatest,\n defer,\n distinctUntilChanged,\n finalize,\n map,\n tap,\n withLatestFrom\n} from \"rxjs\"\n\nimport {\n Viewport,\n getElement,\n getElementOffset\n} from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\nimport { Main } from \"../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Sidebar\n */\nexport interface Sidebar {\n height: number /* Sidebar height */\n locked: boolean /* Sidebar is locked */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n main$: Observable
    /* Main area observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch sidebar\n *\n * This function returns an observable that computes the visual parameters of\n * the sidebar which depends on the vertical viewport offset, as well as the\n * height of the main area. When the page is scrolled beyond the header, the\n * sidebar is locked and fills the remaining space.\n *\n * @param el - Sidebar element\n * @param options - Options\n *\n * @returns Sidebar observable\n */\nexport function watchSidebar(\n el: HTMLElement, { viewport$, main$ }: WatchOptions\n): Observable {\n const parent = el.parentElement!\n const adjust =\n parent.offsetTop -\n parent.parentElement!.offsetTop\n\n /* Compute the sidebar's available height and if it should be locked */\n return combineLatest([main$, viewport$])\n .pipe(\n map(([{ offset, height }, { offset: { y } }]) => {\n height = height\n + Math.min(adjust, Math.max(0, y - offset))\n - adjust\n return {\n height,\n locked: y >= offset + adjust\n }\n }),\n distinctUntilChanged((a, b) => (\n a.height === b.height &&\n a.locked === b.locked\n ))\n )\n}\n\n/**\n * Mount sidebar\n *\n * This function doesn't set the height of the actual sidebar, but of its first\n * child \u2013 the `.md-sidebar__scrollwrap` element in order to mitigiate jittery\n * sidebars when the footer is scrolled into view. At some point we switched\n * from `absolute` / `fixed` positioning to `sticky` positioning, significantly\n * reducing jitter in some browsers (respectively Firefox and Safari) when\n * scrolling from the top. However, top-aligned sticky positioning means that\n * the sidebar snaps to the bottom when the end of the container is reached.\n * This is what leads to the mentioned jitter, as the sidebar's height may be\n * updated too slowly.\n *\n * This behaviour can be mitigiated by setting the height of the sidebar to `0`\n * while preserving the padding, and the height on its first element.\n *\n * @param el - Sidebar element\n * @param options - Options\n *\n * @returns Sidebar component observable\n */\nexport function mountSidebar(\n el: HTMLElement, { header$, ...options }: MountOptions\n): Observable> {\n const inner = getElement(\".md-sidebar__scrollwrap\", el)\n const { y } = getElementOffset(inner)\n return defer(() => {\n const push$ = new Subject()\n push$\n .pipe(\n auditTime(0, animationFrameScheduler),\n withLatestFrom(header$)\n )\n .subscribe({\n\n /* Handle emission */\n next([{ height }, { height: offset }]) {\n inner.style.height = `${height - 2 * y}px`\n el.style.top = `${offset}px`\n },\n\n /* Handle complete */\n complete() {\n inner.style.height = \"\"\n el.style.top = \"\"\n }\n })\n\n /* Create and return component */\n return watchSidebar(el, options)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Repo, User } from \"github-types\"\nimport {\n Observable,\n defaultIfEmpty,\n map,\n zip\n} from \"rxjs\"\n\nimport { requestJSON } from \"~/browser\"\n\nimport { SourceFacts } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * GitHub release (partial)\n */\ninterface Release {\n tag_name: string /* Tag name */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch GitHub repository facts\n *\n * @param user - GitHub user or organization\n * @param repo - GitHub repository\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFactsFromGitHub(\n user: string, repo?: string\n): Observable {\n if (typeof repo !== \"undefined\") {\n const url = `https://api.github.com/repos/${user}/${repo}`\n return zip(\n\n /* Fetch version */\n requestJSON(`${url}/releases/latest`)\n .pipe(\n map(release => ({\n version: release.tag_name\n })),\n defaultIfEmpty({})\n ),\n\n /* Fetch stars and forks */\n requestJSON(url)\n .pipe(\n map(info => ({\n stars: info.stargazers_count,\n forks: info.forks_count\n })),\n defaultIfEmpty({})\n )\n )\n .pipe(\n map(([release, info]) => ({ ...release, ...info }))\n )\n\n /* User or organization */\n } else {\n const url = `https://api.github.com/users/${user}`\n return requestJSON(url)\n .pipe(\n map(info => ({\n repositories: info.public_repos\n })),\n defaultIfEmpty({})\n )\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ProjectSchema } from \"gitlab\"\nimport {\n Observable,\n defaultIfEmpty,\n map\n} from \"rxjs\"\n\nimport { requestJSON } from \"~/browser\"\n\nimport { SourceFacts } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch GitLab repository facts\n *\n * @param base - GitLab base\n * @param project - GitLab project\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFactsFromGitLab(\n base: string, project: string\n): Observable {\n const url = `https://${base}/api/v4/projects/${encodeURIComponent(project)}`\n return requestJSON(url)\n .pipe(\n map(({ star_count, forks_count }) => ({\n stars: star_count,\n forks: forks_count\n })),\n defaultIfEmpty({})\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { EMPTY, Observable } from \"rxjs\"\n\nimport { fetchSourceFactsFromGitHub } from \"../github\"\nimport { fetchSourceFactsFromGitLab } from \"../gitlab\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository facts for repositories\n */\nexport interface RepositoryFacts {\n stars?: number /* Number of stars */\n forks?: number /* Number of forks */\n version?: string /* Latest version */\n}\n\n/**\n * Repository facts for organizations\n */\nexport interface OrganizationFacts {\n repositories?: number /* Number of repositories */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Repository facts\n */\nexport type SourceFacts =\n | RepositoryFacts\n | OrganizationFacts\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch repository facts\n *\n * @param url - Repository URL\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFacts(\n url: string\n): Observable {\n const [type] = url.match(/(git(?:hub|lab))/i) || []\n switch (type.toLowerCase()) {\n\n /* GitHub repository */\n case \"github\":\n const [, user, repo] = url.match(/^.+github\\.com\\/([^/]+)\\/?([^/]+)?/i)!\n return fetchSourceFactsFromGitHub(user, repo)\n\n /* GitLab repository */\n case \"gitlab\":\n const [, base, slug] = url.match(/^.+?([^/]*gitlab[^/]+)\\/(.+?)\\/?$/i)!\n return fetchSourceFactsFromGitLab(base, slug)\n\n /* Everything else */\n default:\n return EMPTY\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n Subject,\n catchError,\n defer,\n filter,\n finalize,\n map,\n of,\n shareReplay,\n tap\n} from \"rxjs\"\n\nimport { getElement } from \"~/browser\"\nimport { renderSourceFacts } from \"~/templates\"\n\nimport { Component } from \"../../_\"\nimport {\n SourceFacts,\n fetchSourceFacts\n} from \"../facts\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository information\n */\nexport interface Source {\n facts: SourceFacts /* Repository facts */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository information observable\n */\nlet fetch$: Observable\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch repository information\n *\n * This function tries to read the repository facts from session storage, and\n * if unsuccessful, fetches them from the underlying provider.\n *\n * @param el - Repository information element\n *\n * @returns Repository information observable\n */\nexport function watchSource(\n el: HTMLAnchorElement\n): Observable {\n return fetch$ ||= defer(() => {\n const cached = __md_get(\"__source\", sessionStorage)\n if (cached)\n return of(cached)\n else\n return fetchSourceFacts(el.href)\n .pipe(\n tap(facts => __md_set(\"__source\", facts, sessionStorage))\n )\n })\n .pipe(\n catchError(() => EMPTY),\n filter(facts => Object.keys(facts).length > 0),\n map(facts => ({ facts })),\n shareReplay(1)\n )\n}\n\n/**\n * Mount repository information\n *\n * @param el - Repository information element\n *\n * @returns Repository information component observable\n */\nexport function mountSource(\n el: HTMLAnchorElement\n): Observable> {\n const inner = getElement(\":scope > :last-child\", el)\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe(({ facts }) => {\n inner.appendChild(renderSourceFacts(facts))\n inner.setAttribute(\"data-md-state\", \"done\")\n })\n\n /* Create and return component */\n return watchSource(el)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n defer,\n distinctUntilKeyChanged,\n finalize,\n map,\n of,\n switchMap,\n tap\n} from \"rxjs\"\n\nimport { feature } from \"~/_\"\nimport {\n Viewport,\n watchElementSize,\n watchViewportAt\n} from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Navigation tabs\n */\nexport interface Tabs {\n hidden: boolean /* Navigation tabs are hidden */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch navigation tabs\n *\n * @param el - Navigation tabs element\n * @param options - Options\n *\n * @returns Navigation tabs observable\n */\nexport function watchTabs(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable {\n return watchElementSize(document.body)\n .pipe(\n switchMap(() => watchViewportAt(el, { header$, viewport$ })),\n map(({ offset: { y } }) => {\n return {\n hidden: y >= 10\n }\n }),\n distinctUntilKeyChanged(\"hidden\")\n )\n}\n\n/**\n * Mount navigation tabs\n *\n * This function hides the navigation tabs when scrolling past the threshold\n * and makes them reappear in a nice CSS animation when scrolling back up.\n *\n * @param el - Navigation tabs element\n * @param options - Options\n *\n * @returns Navigation tabs component observable\n */\nexport function mountTabs(\n el: HTMLElement, options: MountOptions\n): Observable> {\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe({\n\n /* Handle emission */\n next({ hidden }) {\n if (hidden)\n el.setAttribute(\"data-md-state\", \"hidden\")\n else\n el.removeAttribute(\"data-md-state\")\n },\n\n /* Handle complete */\n complete() {\n el.removeAttribute(\"data-md-state\")\n }\n })\n\n /* Create and return component */\n return (\n feature(\"navigation.tabs.sticky\")\n ? of({ hidden: false })\n : watchTabs(el, options)\n )\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n bufferCount,\n combineLatest,\n debounceTime,\n defer,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n finalize,\n map,\n of,\n scan,\n startWith,\n switchMap,\n takeLast,\n takeUntil,\n tap,\n withLatestFrom\n} from \"rxjs\"\n\nimport { feature } from \"~/_\"\nimport {\n Viewport,\n getElements,\n getLocation,\n getOptionalElement,\n watchElementSize\n} from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Table of contents\n */\nexport interface TableOfContents {\n prev: HTMLAnchorElement[][] /* Anchors (previous) */\n next: HTMLAnchorElement[][] /* Anchors (next) */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch table of contents\n *\n * This is effectively a scroll spy implementation which will account for the\n * fixed header and automatically re-calculate anchor offsets when the viewport\n * is resized. The returned observable will only emit if the table of contents\n * needs to be repainted.\n *\n * This implementation tracks an anchor element's entire path starting from its\n * level up to the top-most anchor element, e.g. `[h3, h2, h1]`. Although the\n * Material theme currently doesn't make use of this information, it enables\n * the styling of the entire hierarchy through customization.\n *\n * Note that the current anchor is the last item of the `prev` anchor list.\n *\n * @param el - Table of contents element\n * @param options - Options\n *\n * @returns Table of contents observable\n */\nexport function watchTableOfContents(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable {\n const table = new Map()\n\n /* Compute anchor-to-target mapping */\n const anchors = getElements(\"[href^=\\\\#]\", el)\n for (const anchor of anchors) {\n const id = decodeURIComponent(anchor.hash.substring(1))\n const target = getOptionalElement(`[id=\"${id}\"]`)\n if (typeof target !== \"undefined\")\n table.set(anchor, target)\n }\n\n /* Compute necessary adjustment for header */\n const adjust$ = header$\n .pipe(\n map(header => 24 + header.height)\n )\n\n /* Compute partition of previous and next anchors */\n const partition$ = watchElementSize(document.body)\n .pipe(\n distinctUntilKeyChanged(\"height\"),\n\n /* Build index to map anchor paths to vertical offsets */\n switchMap(body => defer(() => {\n let path: HTMLAnchorElement[] = []\n return of([...table].reduce((index, [anchor, target]) => {\n while (path.length) {\n const last = table.get(path[path.length - 1])!\n if (last.tagName >= target.tagName) {\n path.pop()\n } else {\n break\n }\n }\n\n /* If the current anchor is hidden, continue with its parent */\n let offset = target.offsetTop\n while (!offset && target.parentElement) {\n target = target.parentElement\n offset = target.offsetTop\n }\n\n /* Map reversed anchor path to vertical offset */\n return index.set(\n [...path = [...path, anchor]].reverse(),\n offset\n )\n }, new Map()))\n })\n .pipe(\n\n /* Sort index by vertical offset (see https://bit.ly/30z6QSO) */\n map(index => new Map([...index].sort(([, a], [, b]) => a - b))),\n\n /* Re-compute partition when viewport offset changes */\n switchMap(index => combineLatest([viewport$, adjust$])\n .pipe(\n scan(([prev, next], [{ offset: { y }, size }, adjust]) => {\n const last = y + size.height >= Math.floor(body.height)\n\n /* Look forward */\n while (next.length) {\n const [, offset] = next[0]\n if (offset - adjust < y || last) {\n prev = [...prev, next.shift()!]\n } else {\n break\n }\n }\n\n /* Look backward */\n while (prev.length) {\n const [, offset] = prev[prev.length - 1]\n if (offset - adjust >= y && !last) {\n next = [prev.pop()!, ...next]\n } else {\n break\n }\n }\n\n /* Return partition */\n return [prev, next]\n }, [[], [...index]]),\n distinctUntilChanged((a, b) => (\n a[0] === b[0] &&\n a[1] === b[1]\n ))\n )\n )\n )\n )\n )\n\n /* Compute and return anchor list migrations */\n return partition$\n .pipe(\n map(([prev, next]) => ({\n prev: prev.map(([path]) => path),\n next: next.map(([path]) => path)\n })),\n\n /* Extract anchor list migrations */\n startWith({ prev: [], next: [] }),\n bufferCount(2, 1),\n map(([a, b]) => {\n\n /* Moving down */\n if (a.prev.length < b.prev.length) {\n return {\n prev: b.prev.slice(Math.max(0, a.prev.length - 1), b.prev.length),\n next: []\n }\n\n /* Moving up */\n } else {\n return {\n prev: b.prev.slice(-1),\n next: b.next.slice(0, b.next.length - a.next.length)\n }\n }\n })\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Mount table of contents\n *\n * @param el - Table of contents element\n * @param options - Options\n *\n * @returns Table of contents component observable\n */\nexport function mountTableOfContents(\n el: HTMLElement, { viewport$, header$ }: MountOptions\n): Observable> {\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe(({ prev, next }) => {\n\n /* Look forward */\n for (const [anchor] of next) {\n anchor.removeAttribute(\"data-md-state\")\n anchor.classList.remove(\n \"md-nav__link--active\"\n )\n }\n\n /* Look backward */\n for (const [index, [anchor]] of prev.entries()) {\n anchor.setAttribute(\"data-md-state\", \"blur\")\n anchor.classList.toggle(\n \"md-nav__link--active\",\n index === prev.length - 1\n )\n }\n })\n\n /* Set up anchor tracking, if enabled */\n if (feature(\"navigation.tracking\"))\n viewport$\n .pipe(\n takeUntil(push$.pipe(takeLast(1))),\n distinctUntilKeyChanged(\"offset\"),\n debounceTime(250),\n withLatestFrom(push$)\n )\n .subscribe(([, { prev }]) => {\n const url = getLocation()\n\n /* Set hash fragment to active anchor */\n const anchor = prev[prev.length - 1]\n if (anchor && anchor.length) {\n const [active] = anchor\n const { hash } = new URL(active.href)\n if (url.hash !== hash) {\n url.hash = hash\n history.replaceState({}, \"\", `${url}`)\n }\n\n /* Reset anchor when at the top */\n } else {\n url.hash = \"\"\n history.replaceState({}, \"\", `${url}`)\n }\n })\n\n /* Create and return component */\n return watchTableOfContents(el, { viewport$, header$ })\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n bufferCount,\n combineLatest,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n endWith,\n finalize,\n map,\n repeat,\n skip,\n takeLast,\n takeUntil,\n tap\n} from \"rxjs\"\n\nimport { Viewport } from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\nimport { Main } from \"../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Back-to-top button\n */\nexport interface BackToTop {\n hidden: boolean /* Back-to-top button is hidden */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n main$: Observable
    /* Main area observable */\n target$: Observable /* Location target observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n target$: Observable /* Location target observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch back-to-top\n *\n * @param _el - Back-to-top element\n * @param options - Options\n *\n * @returns Back-to-top observable\n */\nexport function watchBackToTop(\n _el: HTMLElement, { viewport$, main$, target$ }: WatchOptions\n): Observable {\n\n /* Compute direction */\n const direction$ = viewport$\n .pipe(\n map(({ offset: { y } }) => y),\n bufferCount(2, 1),\n map(([a, b]) => a > b && b > 0),\n distinctUntilChanged()\n )\n\n /* Compute whether main area is active */\n const active$ = main$\n .pipe(\n map(({ active }) => active)\n )\n\n /* Compute threshold for hiding */\n return combineLatest([active$, direction$])\n .pipe(\n map(([active, direction]) => !(active && direction)),\n distinctUntilChanged(),\n takeUntil(target$.pipe(skip(1))),\n endWith(true),\n repeat({ delay: 250 }),\n map(hidden => ({ hidden }))\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Mount back-to-top\n *\n * @param el - Back-to-top element\n * @param options - Options\n *\n * @returns Back-to-top component observable\n */\nexport function mountBackToTop(\n el: HTMLElement, { viewport$, header$, main$, target$ }: MountOptions\n): Observable> {\n const push$ = new Subject()\n push$.subscribe({\n\n /* Handle emission */\n next({ hidden }) {\n if (hidden) {\n el.setAttribute(\"data-md-state\", \"hidden\")\n el.setAttribute(\"tabindex\", \"-1\")\n el.blur()\n } else {\n el.removeAttribute(\"data-md-state\")\n el.removeAttribute(\"tabindex\")\n }\n },\n\n /* Handle complete */\n complete() {\n el.style.top = \"\"\n el.setAttribute(\"data-md-state\", \"hidden\")\n el.removeAttribute(\"tabindex\")\n }\n })\n\n /* Watch header height */\n header$\n .pipe(\n takeUntil(push$.pipe(endWith(0), takeLast(1))),\n distinctUntilKeyChanged(\"height\")\n )\n .subscribe(({ height }) => {\n el.style.top = `${height + 16}px`\n })\n\n /* Create and return component */\n return watchBackToTop(el, { viewport$, main$, target$ })\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n fromEvent,\n mapTo,\n mergeMap,\n of,\n switchMap,\n takeWhile,\n tap,\n withLatestFrom\n} from \"rxjs\"\n\nimport { getElements } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch options\n */\ninterface PatchOptions {\n document$: Observable /* Document observable */\n tablet$: Observable /* Media tablet observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch indeterminate checkboxes\n *\n * This function replaces the indeterminate \"pseudo state\" with the actual\n * indeterminate state, which is used to keep navigation always expanded.\n *\n * @param options - Options\n */\nexport function patchIndeterminate(\n { document$, tablet$ }: PatchOptions\n): void {\n document$\n .pipe(\n switchMap(() => of(...getElements(\n \"[data-md-state=indeterminate]\"\n ))),\n tap(el => {\n el.indeterminate = true\n el.checked = false\n }),\n mergeMap(el => fromEvent(el, \"change\")\n .pipe(\n takeWhile(() => el.hasAttribute(\"data-md-state\")),\n mapTo(el)\n )\n ),\n withLatestFrom(tablet$)\n )\n .subscribe(([el, tablet]) => {\n el.removeAttribute(\"data-md-state\")\n if (tablet)\n el.checked = false\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n filter,\n fromEvent,\n mapTo,\n mergeMap,\n of,\n switchMap,\n tap\n} from \"rxjs\"\n\nimport { getElements } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch options\n */\ninterface PatchOptions {\n document$: Observable /* Document observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Check whether the given device is an Apple device\n *\n * @returns Test result\n */\nfunction isAppleDevice(): boolean {\n return /(iPad|iPhone|iPod)/.test(navigator.userAgent)\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch all elements with `data-md-scrollfix` attributes\n *\n * This is a year-old patch which ensures that overflow scrolling works at the\n * top and bottom of containers on iOS by ensuring a `1px` scroll offset upon\n * the start of a touch event.\n *\n * @see https://bit.ly/2SCtAOO - Original source\n *\n * @param options - Options\n */\nexport function patchScrollfix(\n { document$ }: PatchOptions\n): void {\n document$\n .pipe(\n switchMap(() => of(...getElements(\"[data-md-scrollfix]\"))),\n tap(el => el.removeAttribute(\"data-md-scrollfix\")),\n filter(isAppleDevice),\n mergeMap(el => fromEvent(el, \"touchstart\")\n .pipe(\n mapTo(el)\n )\n )\n )\n .subscribe(el => {\n const top = el.scrollTop\n\n /* We're at the top of the container */\n if (top === 0) {\n el.scrollTop = 1\n\n /* We're at the bottom of the container */\n } else if (top + el.offsetHeight === el.scrollHeight) {\n el.scrollTop = top - 1\n }\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n combineLatest,\n delay,\n map,\n of,\n switchMap,\n withLatestFrom\n} from \"rxjs\"\n\nimport {\n Viewport,\n watchToggle\n} from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch options\n */\ninterface PatchOptions {\n viewport$: Observable /* Viewport observable */\n tablet$: Observable /* Media tablet observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch the document body to lock when search is open\n *\n * For mobile and tablet viewports, the search is rendered full screen, which\n * leads to scroll leaking when at the top or bottom of the search result. This\n * function locks the body when the search is in full screen mode, and restores\n * the scroll position when leaving.\n *\n * @param options - Options\n */\nexport function patchScrolllock(\n { viewport$, tablet$ }: PatchOptions\n): void {\n combineLatest([watchToggle(\"search\"), tablet$])\n .pipe(\n map(([active, tablet]) => active && !tablet),\n switchMap(active => of(active)\n .pipe(\n delay(active ? 400 : 100)\n )\n ),\n withLatestFrom(viewport$)\n )\n .subscribe(([active, { offset: { y }}]) => {\n if (active) {\n document.body.setAttribute(\"data-md-state\", \"lock\")\n document.body.style.top = `-${y}px`\n } else {\n const value = -1 * parseInt(document.body.style.top, 10)\n document.body.removeAttribute(\"data-md-state\")\n document.body.style.top = \"\"\n if (value)\n window.scrollTo(0, value)\n }\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Polyfills\n * ------------------------------------------------------------------------- */\n\n/* Polyfill `Object.entries` */\nif (!Object.entries)\n Object.entries = function (obj: object) {\n const data: [string, string][] = []\n for (const key of Object.keys(obj))\n // @ts-expect-error - ignore property access warning\n data.push([key, obj[key]])\n\n /* Return entries */\n return data\n }\n\n/* Polyfill `Object.values` */\nif (!Object.values)\n Object.values = function (obj: object) {\n const data: string[] = []\n for (const key of Object.keys(obj))\n // @ts-expect-error - ignore property access warning\n data.push(obj[key])\n\n /* Return values */\n return data\n }\n\n/* ------------------------------------------------------------------------- */\n\n/* Polyfills for `Element` */\nif (typeof Element !== \"undefined\") {\n\n /* Polyfill `Element.scrollTo` */\n if (!Element.prototype.scrollTo)\n Element.prototype.scrollTo = function (\n x?: ScrollToOptions | number, y?: number\n ): void {\n if (typeof x === \"object\") {\n this.scrollLeft = x.left!\n this.scrollTop = x.top!\n } else {\n this.scrollLeft = x!\n this.scrollTop = y!\n }\n }\n\n /* Polyfill `Element.replaceWith` */\n if (!Element.prototype.replaceWith)\n Element.prototype.replaceWith = function (\n ...nodes: Array\n ): void {\n const parent = this.parentNode\n if (parent) {\n if (nodes.length === 0)\n parent.removeChild(this)\n\n /* Replace children and create text nodes */\n for (let i = nodes.length - 1; i >= 0; i--) {\n let node = nodes[i]\n if (typeof node !== \"object\")\n node = document.createTextNode(node)\n else if (node.parentNode)\n node.parentNode.removeChild(node)\n\n /* Replace child or insert before previous sibling */\n if (!i)\n parent.replaceChild(node, this)\n else\n parent.insertBefore(this.previousSibling!, node)\n }\n }\n }\n}\n"], + "mappings": "4iCAAA,oBAAC,UAAU,EAAQ,EAAS,CAC1B,MAAO,KAAY,UAAY,MAAO,KAAW,YAAc,IAC/D,MAAO,SAAW,YAAc,OAAO,IAAM,OAAO,GACnD,MACD,GAAO,UAAY,CAAE,aASrB,WAAmC,EAAO,CACxC,GAAI,GAAmB,GACnB,EAA0B,GAC1B,EAAiC,KAEjC,EAAsB,CACxB,KAAM,GACN,OAAQ,GACR,IAAK,GACL,IAAK,GACL,MAAO,GACP,SAAU,GACV,OAAQ,GACR,KAAM,GACN,MAAO,GACP,KAAM,GACN,KAAM,GACN,SAAU,GACV,iBAAkB,IAQpB,WAA4B,EAAI,CAC9B,MACE,MACA,IAAO,UACP,EAAG,WAAa,QAChB,EAAG,WAAa,QAChB,aAAe,IACf,YAAc,GAAG,WAcrB,WAAuC,EAAI,CACzC,GAAI,IAAO,EAAG,KACV,GAAU,EAAG,QAUjB,MARI,QAAY,SAAW,EAAoB,KAAS,CAAC,EAAG,UAIxD,KAAY,YAAc,CAAC,EAAG,UAI9B,EAAG,mBAYT,WAA8B,EAAI,CAChC,AAAI,EAAG,UAAU,SAAS,kBAG1B,GAAG,UAAU,IAAI,iBACjB,EAAG,aAAa,2BAA4B,KAQ9C,WAAiC,EAAI,CACnC,AAAI,CAAC,EAAG,aAAa,6BAGrB,GAAG,UAAU,OAAO,iBACpB,EAAG,gBAAgB,6BAWrB,WAAmB,EAAG,CACpB,AAAI,EAAE,SAAW,EAAE,QAAU,EAAE,SAI3B,GAAmB,EAAM,gBAC3B,EAAqB,EAAM,eAG7B,EAAmB,IAWrB,WAAuB,EAAG,CACxB,EAAmB,GAUrB,WAAiB,EAAG,CAElB,AAAI,CAAC,EAAmB,EAAE,SAItB,IAAoB,EAA8B,EAAE,UACtD,EAAqB,EAAE,QAQ3B,WAAgB,EAAG,CACjB,AAAI,CAAC,EAAmB,EAAE,SAKxB,GAAE,OAAO,UAAU,SAAS,kBAC5B,EAAE,OAAO,aAAa,8BAMtB,GAA0B,GAC1B,OAAO,aAAa,GACpB,EAAiC,OAAO,WAAW,UAAW,CAC5D,EAA0B,IACzB,KACH,EAAwB,EAAE,SAS9B,WAA4B,EAAG,CAC7B,AAAI,SAAS,kBAAoB,UAK3B,IACF,GAAmB,IAErB,KAUJ,YAA0C,CACxC,SAAS,iBAAiB,YAAa,GACvC,SAAS,iBAAiB,YAAa,GACvC,SAAS,iBAAiB,UAAW,GACrC,SAAS,iBAAiB,cAAe,GACzC,SAAS,iBAAiB,cAAe,GACzC,SAAS,iBAAiB,YAAa,GACvC,SAAS,iBAAiB,YAAa,GACvC,SAAS,iBAAiB,aAAc,GACxC,SAAS,iBAAiB,WAAY,GAGxC,YAA6C,CAC3C,SAAS,oBAAoB,YAAa,GAC1C,SAAS,oBAAoB,YAAa,GAC1C,SAAS,oBAAoB,UAAW,GACxC,SAAS,oBAAoB,cAAe,GAC5C,SAAS,oBAAoB,cAAe,GAC5C,SAAS,oBAAoB,YAAa,GAC1C,SAAS,oBAAoB,YAAa,GAC1C,SAAS,oBAAoB,aAAc,GAC3C,SAAS,oBAAoB,WAAY,GAU3C,WAA8B,EAAG,CAG/B,AAAI,EAAE,OAAO,UAAY,EAAE,OAAO,SAAS,gBAAkB,QAI7D,GAAmB,GACnB,KAMF,SAAS,iBAAiB,UAAW,EAAW,IAChD,SAAS,iBAAiB,YAAa,EAAe,IACtD,SAAS,iBAAiB,cAAe,EAAe,IACxD,SAAS,iBAAiB,aAAc,EAAe,IACvD,SAAS,iBAAiB,mBAAoB,EAAoB,IAElE,IAMA,EAAM,iBAAiB,QAAS,EAAS,IACzC,EAAM,iBAAiB,OAAQ,EAAQ,IAOvC,AAAI,EAAM,WAAa,KAAK,wBAA0B,EAAM,KAI1D,EAAM,KAAK,aAAa,wBAAyB,IACxC,EAAM,WAAa,KAAK,eACjC,UAAS,gBAAgB,UAAU,IAAI,oBACvC,SAAS,gBAAgB,aAAa,wBAAyB,KAOnE,GAAI,MAAO,SAAW,aAAe,MAAO,WAAa,YAAa,CAIpE,OAAO,0BAA4B,EAInC,GAAI,GAEJ,GAAI,CACF,EAAQ,GAAI,aAAY,sCACjB,EAAP,CAEA,EAAQ,SAAS,YAAY,eAC7B,EAAM,gBAAgB,+BAAgC,GAAO,GAAO,IAGtE,OAAO,cAAc,GAGvB,AAAI,MAAO,WAAa,aAGtB,EAA0B,cCpT9B,eAAC,UAAS,EAAQ,CAOhB,GAAI,GAA6B,UAAW,CAC1C,GAAI,CACF,MAAO,CAAC,CAAC,OAAO,eACT,EAAP,CACA,MAAO,KAKP,EAAoB,IAEpB,EAAiB,SAAS,EAAO,CACnC,GAAI,GAAW,CACb,KAAM,UAAW,CACf,GAAI,GAAQ,EAAM,QAClB,MAAO,CAAE,KAAM,IAAU,OAAQ,MAAO,KAI5C,MAAI,IACF,GAAS,OAAO,UAAY,UAAW,CACrC,MAAO,KAIJ,GAOL,EAAiB,SAAS,EAAO,CACnC,MAAO,oBAAmB,GAAO,QAAQ,OAAQ,MAG/C,EAAmB,SAAS,EAAO,CACrC,MAAO,oBAAmB,OAAO,GAAO,QAAQ,MAAO,OAGrD,EAA0B,UAAW,CAEvC,GAAI,GAAkB,SAAS,EAAc,CAC3C,OAAO,eAAe,KAAM,WAAY,CAAE,SAAU,GAAM,MAAO,KACjE,GAAI,GAAqB,MAAO,GAEhC,GAAI,IAAuB,YAEpB,GAAI,IAAuB,SAChC,AAAI,IAAiB,IACnB,KAAK,YAAY,WAEV,YAAwB,GAAiB,CAClD,GAAI,GAAQ,KACZ,EAAa,QAAQ,SAAS,EAAO,EAAM,CACzC,EAAM,OAAO,EAAM,aAEX,IAAiB,MAAU,IAAuB,SAC5D,GAAI,OAAO,UAAU,SAAS,KAAK,KAAkB,iBACnD,OAAS,GAAI,EAAG,EAAI,EAAa,OAAQ,IAAK,CAC5C,GAAI,GAAQ,EAAa,GACzB,GAAK,OAAO,UAAU,SAAS,KAAK,KAAW,kBAAsB,EAAM,SAAW,EACpF,KAAK,OAAO,EAAM,GAAI,EAAM,QAE5B,MAAM,IAAI,WAAU,4CAA8C,EAAI,mCAI1E,QAAS,KAAO,GACd,AAAI,EAAa,eAAe,IAC9B,KAAK,OAAO,EAAK,EAAa,QAKpC,MAAM,IAAI,WAAU,iDAIpB,EAAQ,EAAgB,UAE5B,EAAM,OAAS,SAAS,EAAM,EAAO,CACnC,AAAI,IAAQ,MAAK,SACf,KAAK,SAAS,GAAM,KAAK,OAAO,IAEhC,KAAK,SAAS,GAAQ,CAAC,OAAO,KAIlC,EAAM,OAAS,SAAS,EAAM,CAC5B,MAAO,MAAK,SAAS,IAGvB,EAAM,IAAM,SAAS,EAAM,CACzB,MAAQ,KAAQ,MAAK,SAAY,KAAK,SAAS,GAAM,GAAK,MAG5D,EAAM,OAAS,SAAS,EAAM,CAC5B,MAAQ,KAAQ,MAAK,SAAY,KAAK,SAAS,GAAM,MAAM,GAAK,IAGlE,EAAM,IAAM,SAAS,EAAM,CACzB,MAAQ,KAAQ,MAAK,UAGvB,EAAM,IAAM,SAAS,EAAM,EAAO,CAChC,KAAK,SAAS,GAAQ,CAAC,OAAO,KAGhC,EAAM,QAAU,SAAS,EAAU,EAAS,CAC1C,GAAI,GACJ,OAAS,KAAQ,MAAK,SACpB,GAAI,KAAK,SAAS,eAAe,GAAO,CACtC,EAAU,KAAK,SAAS,GACxB,OAAS,GAAI,EAAG,EAAI,EAAQ,OAAQ,IAClC,EAAS,KAAK,EAAS,EAAQ,GAAI,EAAM,QAMjD,EAAM,KAAO,UAAW,CACtB,GAAI,GAAQ,GACZ,YAAK,QAAQ,SAAS,EAAO,EAAM,CACjC,EAAM,KAAK,KAEN,EAAe,IAGxB,EAAM,OAAS,UAAW,CACxB,GAAI,GAAQ,GACZ,YAAK,QAAQ,SAAS,EAAO,CAC3B,EAAM,KAAK,KAEN,EAAe,IAGxB,EAAM,QAAU,UAAW,CACzB,GAAI,GAAQ,GACZ,YAAK,QAAQ,SAAS,EAAO,EAAM,CACjC,EAAM,KAAK,CAAC,EAAM,MAEb,EAAe,IAGpB,GACF,GAAM,OAAO,UAAY,EAAM,SAGjC,EAAM,SAAW,UAAW,CAC1B,GAAI,GAAc,GAClB,YAAK,QAAQ,SAAS,EAAO,EAAM,CACjC,EAAY,KAAK,EAAe,GAAQ,IAAM,EAAe,MAExD,EAAY,KAAK,MAI1B,EAAO,gBAAkB,GAGvB,EAAkC,UAAW,CAC/C,GAAI,CACF,GAAI,GAAkB,EAAO,gBAE7B,MACG,IAAI,GAAgB,QAAQ,aAAe,OAC3C,MAAO,GAAgB,UAAU,KAAQ,YACzC,MAAO,GAAgB,UAAU,SAAY,iBAEzC,EAAP,CACA,MAAO,KAIX,AAAK,KACH,IAGF,GAAI,GAAQ,EAAO,gBAAgB,UAEnC,AAAI,MAAO,GAAM,MAAS,YACxB,GAAM,KAAO,UAAW,CACtB,GAAI,GAAQ,KACR,EAAQ,GACZ,KAAK,QAAQ,SAAS,EAAO,EAAM,CACjC,EAAM,KAAK,CAAC,EAAM,IACb,EAAM,UACT,EAAM,OAAO,KAGjB,EAAM,KAAK,SAAS,EAAG,EAAG,CACxB,MAAI,GAAE,GAAK,EAAE,GACJ,GACE,EAAE,GAAK,EAAE,GACX,EAEA,IAGP,EAAM,UACR,GAAM,SAAW,IAEnB,OAAS,GAAI,EAAG,EAAI,EAAM,OAAQ,IAChC,KAAK,OAAO,EAAM,GAAG,GAAI,EAAM,GAAG,MAKpC,MAAO,GAAM,aAAgB,YAC/B,OAAO,eAAe,EAAO,cAAe,CAC1C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,SAAS,EAAc,CAC5B,GAAI,KAAK,SACP,KAAK,SAAW,OACX,CACL,GAAI,GAAO,GACX,KAAK,QAAQ,SAAS,EAAO,EAAM,CACjC,EAAK,KAAK,KAEZ,OAAS,GAAI,EAAG,EAAI,EAAK,OAAQ,IAC/B,KAAK,OAAO,EAAK,IAIrB,EAAe,EAAa,QAAQ,MAAO,IAG3C,OAFI,GAAa,EAAa,MAAM,KAChC,EACK,EAAI,EAAG,EAAI,EAAW,OAAQ,IACrC,EAAY,EAAW,GAAG,MAAM,KAChC,KAAK,OACH,EAAiB,EAAU,IAC1B,EAAU,OAAS,EAAK,EAAiB,EAAU,IAAM,SAUnE,MAAO,SAAW,YAAe,OAC5B,MAAO,SAAW,YAAe,OACjC,MAAO,OAAS,YAAe,KAAO,IAG9C,AAAC,UAAS,EAAQ,CAOhB,GAAI,GAAwB,UAAW,CACrC,GAAI,CACF,GAAI,GAAI,GAAI,GAAO,IAAI,IAAK,YAC5B,SAAE,SAAW,MACL,EAAE,OAAS,kBAAqB,EAAE,mBACnC,EAAP,CACA,MAAO,KAKP,EAAc,UAAW,CAC3B,GAAI,GAAO,EAAO,IAEd,EAAM,SAAS,EAAK,EAAM,CAC5B,AAAI,MAAO,IAAQ,UAAU,GAAM,OAAO,IACtC,GAAQ,MAAO,IAAS,UAAU,GAAO,OAAO,IAGpD,GAAI,GAAM,SAAU,EACpB,GAAI,GAAS,GAAO,WAAa,QAAU,IAAS,EAAO,SAAS,MAAO,CACzE,EAAO,EAAK,cACZ,EAAM,SAAS,eAAe,mBAAmB,IACjD,EAAc,EAAI,cAAc,QAChC,EAAY,KAAO,EACnB,EAAI,KAAK,YAAY,GACrB,GAAI,CACF,GAAI,EAAY,KAAK,QAAQ,KAAU,EAAG,KAAM,IAAI,OAAM,EAAY,YAC/D,EAAP,CACA,KAAM,IAAI,OAAM,0BAA4B,EAAO,WAAa,IAIpE,GAAI,GAAgB,EAAI,cAAc,KACtC,EAAc,KAAO,EACjB,GACF,GAAI,KAAK,YAAY,GACrB,EAAc,KAAO,EAAc,MAGrC,GAAI,GAAe,EAAI,cAAc,SAIrC,GAHA,EAAa,KAAO,MACpB,EAAa,MAAQ,EAEjB,EAAc,WAAa,KAAO,CAAC,IAAI,KAAK,EAAc,OAAU,CAAC,EAAa,iBAAmB,CAAC,EACxG,KAAM,IAAI,WAAU,eAGtB,OAAO,eAAe,KAAM,iBAAkB,CAC5C,MAAO,IAKT,GAAI,GAAe,GAAI,GAAO,gBAAgB,KAAK,QAC/C,EAAqB,GACrB,EAA2B,GAC3B,EAAQ,KACZ,CAAC,SAAU,SAAU,OAAO,QAAQ,SAAS,EAAY,CACvD,GAAI,IAAS,EAAa,GAC1B,EAAa,GAAc,UAAW,CACpC,GAAO,MAAM,EAAc,WACvB,GACF,GAA2B,GAC3B,EAAM,OAAS,EAAa,WAC5B,EAA2B,OAKjC,OAAO,eAAe,KAAM,eAAgB,CAC1C,MAAO,EACP,WAAY,KAGd,GAAI,GAAS,OACb,OAAO,eAAe,KAAM,sBAAuB,CACjD,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,UAAW,CAChB,AAAI,KAAK,SAAW,GAClB,GAAS,KAAK,OACV,GACF,GAAqB,GACrB,KAAK,aAAa,YAAY,KAAK,QACnC,EAAqB,SAO3B,EAAQ,EAAI,UAEZ,EAA6B,SAAS,EAAe,CACvD,OAAO,eAAe,EAAO,EAAe,CAC1C,IAAK,UAAW,CACd,MAAO,MAAK,eAAe,IAE7B,IAAK,SAAS,EAAO,CACnB,KAAK,eAAe,GAAiB,GAEvC,WAAY,MAIhB,CAAC,OAAQ,OAAQ,WAAY,OAAQ,YAClC,QAAQ,SAAS,EAAe,CAC/B,EAA2B,KAG/B,OAAO,eAAe,EAAO,SAAU,CACrC,IAAK,UAAW,CACd,MAAO,MAAK,eAAe,QAE7B,IAAK,SAAS,EAAO,CACnB,KAAK,eAAe,OAAY,EAChC,KAAK,uBAEP,WAAY,KAGd,OAAO,iBAAiB,EAAO,CAE7B,SAAY,CACV,IAAK,UAAW,CACd,GAAI,GAAQ,KACZ,MAAO,WAAW,CAChB,MAAO,GAAM,QAKnB,KAAQ,CACN,IAAK,UAAW,CACd,MAAO,MAAK,eAAe,KAAK,QAAQ,MAAO,KAEjD,IAAK,SAAS,EAAO,CACnB,KAAK,eAAe,KAAO,EAC3B,KAAK,uBAEP,WAAY,IAGd,SAAY,CACV,IAAK,UAAW,CACd,MAAO,MAAK,eAAe,SAAS,QAAQ,SAAU,MAExD,IAAK,SAAS,EAAO,CACnB,KAAK,eAAe,SAAW,GAEjC,WAAY,IAGd,OAAU,CACR,IAAK,UAAW,CAEd,GAAI,GAAe,CAAE,QAAS,GAAI,SAAU,IAAK,OAAQ,IAAK,KAAK,eAAe,UAI9E,EAAkB,KAAK,eAAe,MAAQ,GAChD,KAAK,eAAe,OAAS,GAE/B,MAAO,MAAK,eAAe,SACzB,KACA,KAAK,eAAe,SACnB,GAAmB,IAAM,KAAK,eAAe,KAAQ,KAE1D,WAAY,IAGd,SAAY,CACV,IAAK,UAAW,CACd,MAAO,IAET,IAAK,SAAS,EAAO,GAErB,WAAY,IAGd,SAAY,CACV,IAAK,UAAW,CACd,MAAO,IAET,IAAK,SAAS,EAAO,GAErB,WAAY,MAIhB,EAAI,gBAAkB,SAAS,EAAM,CACnC,MAAO,GAAK,gBAAgB,MAAM,EAAM,YAG1C,EAAI,gBAAkB,SAAS,EAAK,CAClC,MAAO,GAAK,gBAAgB,MAAM,EAAM,YAG1C,EAAO,IAAM,GAQf,GAJK,KACH,IAGG,EAAO,WAAa,QAAW,CAAE,WAAY,GAAO,UAAW,CAClE,GAAI,GAAY,UAAW,CACzB,MAAO,GAAO,SAAS,SAAW,KAAO,EAAO,SAAS,SAAY,GAAO,SAAS,KAAQ,IAAM,EAAO,SAAS,KAAQ,KAG7H,GAAI,CACF,OAAO,eAAe,EAAO,SAAU,SAAU,CAC/C,IAAK,EACL,WAAY,WAEP,EAAP,CACA,YAAY,UAAW,CACrB,EAAO,SAAS,OAAS,KACxB,SAKN,MAAO,SAAW,YAAe,OAC5B,MAAO,SAAW,YAAe,OACjC,MAAO,OAAS,YAAe,KAAO,MC3e9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gFAeA,GAAI,IACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACJ,AAAC,UAAU,EAAS,CAChB,GAAI,GAAO,MAAO,SAAW,SAAW,OAAS,MAAO,OAAS,SAAW,KAAO,MAAO,OAAS,SAAW,KAAO,GACrH,AAAI,MAAO,SAAW,YAAc,OAAO,IACvC,OAAO,QAAS,CAAC,WAAY,SAAU,EAAS,CAAE,EAAQ,EAAe,EAAM,EAAe,OAE7F,AAAI,MAAO,KAAW,UAAY,MAAO,IAAO,SAAY,SAC7D,EAAQ,EAAe,EAAM,EAAe,GAAO,WAGnD,EAAQ,EAAe,IAE3B,WAAwB,EAAS,EAAU,CACvC,MAAI,KAAY,GACZ,CAAI,MAAO,QAAO,QAAW,WACzB,OAAO,eAAe,EAAS,aAAc,CAAE,MAAO,KAGtD,EAAQ,WAAa,IAGtB,SAAU,EAAI,EAAG,CAAE,MAAO,GAAQ,GAAM,EAAW,EAAS,EAAI,GAAK,MAGnF,SAAU,EAAU,CACjB,GAAI,GAAgB,OAAO,gBACtB,CAAE,UAAW,aAAgB,QAAS,SAAU,EAAG,EAAG,CAAE,EAAE,UAAY,IACvE,SAAU,EAAG,EAAG,CAAE,OAAS,KAAK,GAAG,AAAI,OAAO,UAAU,eAAe,KAAK,EAAG,IAAI,GAAE,GAAK,EAAE,KAEhG,GAAY,SAAU,EAAG,EAAG,CACxB,GAAI,MAAO,IAAM,YAAc,IAAM,KACjC,KAAM,IAAI,WAAU,uBAAyB,OAAO,GAAK,iCAC7D,EAAc,EAAG,GACjB,YAAc,CAAE,KAAK,YAAc,EACnC,EAAE,UAAY,IAAM,KAAO,OAAO,OAAO,GAAM,GAAG,UAAY,EAAE,UAAW,GAAI,KAGnF,GAAW,OAAO,QAAU,SAAU,EAAG,CACrC,OAAS,GAAG,EAAI,EAAG,EAAI,UAAU,OAAQ,EAAI,EAAG,IAAK,CACjD,EAAI,UAAU,GACd,OAAS,KAAK,GAAG,AAAI,OAAO,UAAU,eAAe,KAAK,EAAG,IAAI,GAAE,GAAK,EAAE,IAE9E,MAAO,IAGX,GAAS,SAAU,EAAG,EAAG,CACrB,GAAI,GAAI,GACR,OAAS,KAAK,GAAG,AAAI,OAAO,UAAU,eAAe,KAAK,EAAG,IAAM,EAAE,QAAQ,GAAK,GAC9E,GAAE,GAAK,EAAE,IACb,GAAI,GAAK,MAAQ,MAAO,QAAO,uBAA0B,WACrD,OAAS,GAAI,EAAG,EAAI,OAAO,sBAAsB,GAAI,EAAI,EAAE,OAAQ,IAC/D,AAAI,EAAE,QAAQ,EAAE,IAAM,GAAK,OAAO,UAAU,qBAAqB,KAAK,EAAG,EAAE,KACvE,GAAE,EAAE,IAAM,EAAE,EAAE,KAE1B,MAAO,IAGX,GAAa,SAAU,EAAY,EAAQ,EAAK,EAAM,CAClD,GAAI,GAAI,UAAU,OAAQ,EAAI,EAAI,EAAI,EAAS,IAAS,KAAO,EAAO,OAAO,yBAAyB,EAAQ,GAAO,EAAM,EAC3H,GAAI,MAAO,UAAY,UAAY,MAAO,SAAQ,UAAa,WAAY,EAAI,QAAQ,SAAS,EAAY,EAAQ,EAAK,OACpH,QAAS,GAAI,EAAW,OAAS,EAAG,GAAK,EAAG,IAAK,AAAI,GAAI,EAAW,KAAI,GAAK,GAAI,EAAI,EAAE,GAAK,EAAI,EAAI,EAAE,EAAQ,EAAK,GAAK,EAAE,EAAQ,KAAS,GAChJ,MAAO,GAAI,GAAK,GAAK,OAAO,eAAe,EAAQ,EAAK,GAAI,GAGhE,GAAU,SAAU,EAAY,EAAW,CACvC,MAAO,UAAU,EAAQ,EAAK,CAAE,EAAU,EAAQ,EAAK,KAG3D,GAAa,SAAU,EAAa,EAAe,CAC/C,GAAI,MAAO,UAAY,UAAY,MAAO,SAAQ,UAAa,WAAY,MAAO,SAAQ,SAAS,EAAa,IAGpH,GAAY,SAAU,EAAS,EAAY,EAAG,EAAW,CACrD,WAAe,EAAO,CAAE,MAAO,aAAiB,GAAI,EAAQ,GAAI,GAAE,SAAU,EAAS,CAAE,EAAQ,KAC/F,MAAO,IAAK,IAAM,GAAI,UAAU,SAAU,EAAS,EAAQ,CACvD,WAAmB,EAAO,CAAE,GAAI,CAAE,EAAK,EAAU,KAAK,UAAkB,EAAP,CAAY,EAAO,IACpF,WAAkB,EAAO,CAAE,GAAI,CAAE,EAAK,EAAU,MAAS,UAAkB,EAAP,CAAY,EAAO,IACvF,WAAc,EAAQ,CAAE,EAAO,KAAO,EAAQ,EAAO,OAAS,EAAM,EAAO,OAAO,KAAK,EAAW,GAClG,EAAM,GAAY,EAAU,MAAM,EAAS,GAAc,KAAK,WAItE,GAAc,SAAU,EAAS,EAAM,CACnC,GAAI,GAAI,CAAE,MAAO,EAAG,KAAM,UAAW,CAAE,GAAI,EAAE,GAAK,EAAG,KAAM,GAAE,GAAI,MAAO,GAAE,IAAO,KAAM,GAAI,IAAK,IAAM,EAAG,EAAG,EAAG,EAC/G,MAAO,GAAI,CAAE,KAAM,EAAK,GAAI,MAAS,EAAK,GAAI,OAAU,EAAK,IAAM,MAAO,SAAW,YAAe,GAAE,OAAO,UAAY,UAAW,CAAE,MAAO,QAAU,EACvJ,WAAc,EAAG,CAAE,MAAO,UAAU,EAAG,CAAE,MAAO,GAAK,CAAC,EAAG,KACzD,WAAc,EAAI,CACd,GAAI,EAAG,KAAM,IAAI,WAAU,mCAC3B,KAAO,GAAG,GAAI,CACV,GAAI,EAAI,EAAG,GAAM,GAAI,EAAG,GAAK,EAAI,EAAE,OAAY,EAAG,GAAK,EAAE,OAAc,IAAI,EAAE,SAAc,EAAE,KAAK,GAAI,GAAK,EAAE,OAAS,CAAE,GAAI,EAAE,KAAK,EAAG,EAAG,KAAK,KAAM,MAAO,GAE3J,OADI,EAAI,EAAG,GAAG,GAAK,CAAC,EAAG,GAAK,EAAG,EAAE,QACzB,EAAG,QACF,OAAQ,GAAG,EAAI,EAAI,UACnB,GAAG,SAAE,QAAgB,CAAE,MAAO,EAAG,GAAI,KAAM,QAC3C,GAAG,EAAE,QAAS,EAAI,EAAG,GAAI,EAAK,CAAC,GAAI,aACnC,GAAG,EAAK,EAAE,IAAI,MAAO,EAAE,KAAK,MAAO,iBAEpC,GAAM,EAAI,EAAE,KAAM,IAAI,EAAE,OAAS,GAAK,EAAE,EAAE,OAAS,KAAQ,GAAG,KAAO,GAAK,EAAG,KAAO,GAAI,CAAE,EAAI,EAAG,SACjG,GAAI,EAAG,KAAO,GAAM,EAAC,GAAM,EAAG,GAAK,EAAE,IAAM,EAAG,GAAK,EAAE,IAAM,CAAE,EAAE,MAAQ,EAAG,GAAI,MAC9E,GAAI,EAAG,KAAO,GAAK,EAAE,MAAQ,EAAE,GAAI,CAAE,EAAE,MAAQ,EAAE,GAAI,EAAI,EAAI,MAC7D,GAAI,GAAK,EAAE,MAAQ,EAAE,GAAI,CAAE,EAAE,MAAQ,EAAE,GAAI,EAAE,IAAI,KAAK,GAAK,MAC3D,AAAI,EAAE,IAAI,EAAE,IAAI,MAChB,EAAE,KAAK,MAAO,SAEtB,EAAK,EAAK,KAAK,EAAS,SACnB,EAAP,CAAY,EAAK,CAAC,EAAG,GAAI,EAAI,SAAK,CAAU,EAAI,EAAI,EACtD,GAAI,EAAG,GAAK,EAAG,KAAM,GAAG,GAAI,MAAO,CAAE,MAAO,EAAG,GAAK,EAAG,GAAK,OAAQ,KAAM,MAIlF,GAAe,SAAS,EAAG,EAAG,CAC1B,OAAS,KAAK,GAAG,AAAI,IAAM,WAAa,CAAC,OAAO,UAAU,eAAe,KAAK,EAAG,IAAI,GAAgB,EAAG,EAAG,IAG/G,GAAkB,OAAO,OAAU,SAAS,EAAG,EAAG,EAAG,EAAI,CACrD,AAAI,IAAO,QAAW,GAAK,GAC3B,OAAO,eAAe,EAAG,EAAI,CAAE,WAAY,GAAM,IAAK,UAAW,CAAE,MAAO,GAAE,OAC1E,SAAS,EAAG,EAAG,EAAG,EAAI,CACxB,AAAI,IAAO,QAAW,GAAK,GAC3B,EAAE,GAAM,EAAE,IAGd,GAAW,SAAU,EAAG,CACpB,GAAI,GAAI,MAAO,SAAW,YAAc,OAAO,SAAU,EAAI,GAAK,EAAE,GAAI,EAAI,EAC5E,GAAI,EAAG,MAAO,GAAE,KAAK,GACrB,GAAI,GAAK,MAAO,GAAE,QAAW,SAAU,MAAO,CAC1C,KAAM,UAAY,CACd,MAAI,IAAK,GAAK,EAAE,QAAQ,GAAI,QACrB,CAAE,MAAO,GAAK,EAAE,KAAM,KAAM,CAAC,KAG5C,KAAM,IAAI,WAAU,EAAI,0BAA4B,oCAGxD,GAAS,SAAU,EAAG,EAAG,CACrB,GAAI,GAAI,MAAO,SAAW,YAAc,EAAE,OAAO,UACjD,GAAI,CAAC,EAAG,MAAO,GACf,GAAI,GAAI,EAAE,KAAK,GAAI,EAAG,EAAK,GAAI,EAC/B,GAAI,CACA,KAAQ,KAAM,QAAU,KAAM,IAAM,CAAE,GAAI,EAAE,QAAQ,MAAM,EAAG,KAAK,EAAE,aAEjE,EAAP,CAAgB,EAAI,CAAE,MAAO,UAC7B,CACI,GAAI,CACA,AAAI,GAAK,CAAC,EAAE,MAAS,GAAI,EAAE,SAAY,EAAE,KAAK,UAElD,CAAU,GAAI,EAAG,KAAM,GAAE,OAE7B,MAAO,IAIX,GAAW,UAAY,CACnB,OAAS,GAAK,GAAI,EAAI,EAAG,EAAI,UAAU,OAAQ,IAC3C,EAAK,EAAG,OAAO,GAAO,UAAU,KACpC,MAAO,IAIX,GAAiB,UAAY,CACzB,OAAS,GAAI,EAAG,EAAI,EAAG,EAAK,UAAU,OAAQ,EAAI,EAAI,IAAK,GAAK,UAAU,GAAG,OAC7E,OAAS,GAAI,MAAM,GAAI,EAAI,EAAG,EAAI,EAAG,EAAI,EAAI,IACzC,OAAS,GAAI,UAAU,GAAI,EAAI,EAAG,EAAK,EAAE,OAAQ,EAAI,EAAI,IAAK,IAC1D,EAAE,GAAK,EAAE,GACjB,MAAO,IAGX,GAAgB,SAAU,EAAI,EAAM,EAAM,CACtC,GAAI,GAAQ,UAAU,SAAW,EAAG,OAAS,GAAI,EAAG,EAAI,EAAK,OAAQ,EAAI,EAAI,EAAG,IAC5E,AAAI,IAAM,CAAE,KAAK,MACR,IAAI,GAAK,MAAM,UAAU,MAAM,KAAK,EAAM,EAAG,IAClD,EAAG,GAAK,EAAK,IAGrB,MAAO,GAAG,OAAO,GAAM,MAAM,UAAU,MAAM,KAAK,KAGtD,GAAU,SAAU,EAAG,CACnB,MAAO,gBAAgB,IAAW,MAAK,EAAI,EAAG,MAAQ,GAAI,IAAQ,IAGtE,GAAmB,SAAU,EAAS,EAAY,EAAW,CACzD,GAAI,CAAC,OAAO,cAAe,KAAM,IAAI,WAAU,wCAC/C,GAAI,GAAI,EAAU,MAAM,EAAS,GAAc,IAAK,EAAG,EAAI,GAC3D,MAAO,GAAI,GAAI,EAAK,QAAS,EAAK,SAAU,EAAK,UAAW,EAAE,OAAO,eAAiB,UAAY,CAAE,MAAO,OAAS,EACpH,WAAc,EAAG,CAAE,AAAI,EAAE,IAAI,GAAE,GAAK,SAAU,EAAG,CAAE,MAAO,IAAI,SAAQ,SAAU,EAAG,EAAG,CAAE,EAAE,KAAK,CAAC,EAAG,EAAG,EAAG,IAAM,GAAK,EAAO,EAAG,OAC9H,WAAgB,EAAG,EAAG,CAAE,GAAI,CAAE,EAAK,EAAE,GAAG,UAAc,EAAP,CAAY,EAAO,EAAE,GAAG,GAAI,IAC3E,WAAc,EAAG,CAAE,EAAE,gBAAiB,IAAU,QAAQ,QAAQ,EAAE,MAAM,GAAG,KAAK,EAAS,GAAU,EAAO,EAAE,GAAG,GAAI,GACnH,WAAiB,EAAO,CAAE,EAAO,OAAQ,GACzC,WAAgB,EAAO,CAAE,EAAO,QAAS,GACzC,WAAgB,EAAG,EAAG,CAAE,AAAI,EAAE,GAAI,EAAE,QAAS,EAAE,QAAQ,EAAO,EAAE,GAAG,GAAI,EAAE,GAAG,MAGhF,GAAmB,SAAU,EAAG,CAC5B,GAAI,GAAG,EACP,MAAO,GAAI,GAAI,EAAK,QAAS,EAAK,QAAS,SAAU,EAAG,CAAE,KAAM,KAAO,EAAK,UAAW,EAAE,OAAO,UAAY,UAAY,CAAE,MAAO,OAAS,EAC1I,WAAc,EAAG,EAAG,CAAE,EAAE,GAAK,EAAE,GAAK,SAAU,EAAG,CAAE,MAAQ,GAAI,CAAC,GAAK,CAAE,MAAO,GAAQ,EAAE,GAAG,IAAK,KAAM,IAAM,UAAa,EAAI,EAAE,GAAK,GAAO,IAG/I,GAAgB,SAAU,EAAG,CACzB,GAAI,CAAC,OAAO,cAAe,KAAM,IAAI,WAAU,wCAC/C,GAAI,GAAI,EAAE,OAAO,eAAgB,EACjC,MAAO,GAAI,EAAE,KAAK,GAAM,GAAI,MAAO,KAAa,WAAa,GAAS,GAAK,EAAE,OAAO,YAAa,EAAI,GAAI,EAAK,QAAS,EAAK,SAAU,EAAK,UAAW,EAAE,OAAO,eAAiB,UAAY,CAAE,MAAO,OAAS,GAC9M,WAAc,EAAG,CAAE,EAAE,GAAK,EAAE,IAAM,SAAU,EAAG,CAAE,MAAO,IAAI,SAAQ,SAAU,EAAS,EAAQ,CAAE,EAAI,EAAE,GAAG,GAAI,EAAO,EAAS,EAAQ,EAAE,KAAM,EAAE,UAChJ,WAAgB,EAAS,EAAQ,EAAG,EAAG,CAAE,QAAQ,QAAQ,GAAG,KAAK,SAAS,EAAG,CAAE,EAAQ,CAAE,MAAO,EAAG,KAAM,KAAS,KAGtH,GAAuB,SAAU,EAAQ,EAAK,CAC1C,MAAI,QAAO,eAAkB,OAAO,eAAe,EAAQ,MAAO,CAAE,MAAO,IAAiB,EAAO,IAAM,EAClG,GAGX,GAAI,GAAqB,OAAO,OAAU,SAAS,EAAG,EAAG,CACrD,OAAO,eAAe,EAAG,UAAW,CAAE,WAAY,GAAM,MAAO,KAC9D,SAAS,EAAG,EAAG,CAChB,EAAE,QAAa,GAGnB,GAAe,SAAU,EAAK,CAC1B,GAAI,GAAO,EAAI,WAAY,MAAO,GAClC,GAAI,GAAS,GACb,GAAI,GAAO,KAAM,OAAS,KAAK,GAAK,AAAI,IAAM,WAAa,OAAO,UAAU,eAAe,KAAK,EAAK,IAAI,GAAgB,EAAQ,EAAK,GACtI,SAAmB,EAAQ,GACpB,GAGX,GAAkB,SAAU,EAAK,CAC7B,MAAQ,IAAO,EAAI,WAAc,EAAM,CAAE,QAAW,IAGxD,GAAyB,SAAU,EAAU,EAAO,EAAM,EAAG,CACzD,GAAI,IAAS,KAAO,CAAC,EAAG,KAAM,IAAI,WAAU,iDAC5C,GAAI,MAAO,IAAU,WAAa,IAAa,GAAS,CAAC,EAAI,CAAC,EAAM,IAAI,GAAW,KAAM,IAAI,WAAU,4EACvG,MAAO,KAAS,IAAM,EAAI,IAAS,IAAM,EAAE,KAAK,GAAY,EAAI,EAAE,MAAQ,EAAM,IAAI,IAGxF,GAAyB,SAAU,EAAU,EAAO,EAAO,EAAM,EAAG,CAChE,GAAI,IAAS,IAAK,KAAM,IAAI,WAAU,kCACtC,GAAI,IAAS,KAAO,CAAC,EAAG,KAAM,IAAI,WAAU,iDAC5C,GAAI,MAAO,IAAU,WAAa,IAAa,GAAS,CAAC,EAAI,CAAC,EAAM,IAAI,GAAW,KAAM,IAAI,WAAU,2EACvG,MAAQ,KAAS,IAAM,EAAE,KAAK,EAAU,GAAS,EAAI,EAAE,MAAQ,EAAQ,EAAM,IAAI,EAAU,GAAS,GAGxG,EAAS,YAAa,IACtB,EAAS,WAAY,IACrB,EAAS,SAAU,IACnB,EAAS,aAAc,IACvB,EAAS,UAAW,IACpB,EAAS,aAAc,IACvB,EAAS,YAAa,IACtB,EAAS,cAAe,IACxB,EAAS,eAAgB,IACzB,EAAS,kBAAmB,IAC5B,EAAS,WAAY,IACrB,EAAS,SAAU,IACnB,EAAS,WAAY,IACrB,EAAS,iBAAkB,IAC3B,EAAS,gBAAiB,IAC1B,EAAS,UAAW,IACpB,EAAS,mBAAoB,IAC7B,EAAS,mBAAoB,IAC7B,EAAS,gBAAiB,IAC1B,EAAS,uBAAwB,IACjC,EAAS,eAAgB,IACzB,EAAS,kBAAmB,IAC5B,EAAS,yBAA0B,IACnC,EAAS,yBAA0B,QChTvC;AAAA;AAAA;AAAA;AAAA;AAAA,GAMA,AAAC,UAA0C,EAAM,EAAS,CACzD,AAAG,MAAO,KAAY,UAAY,MAAO,KAAW,SACnD,GAAO,QAAU,IACb,AAAG,MAAO,SAAW,YAAc,OAAO,IAC9C,OAAO,GAAI,GACP,AAAG,MAAO,KAAY,SAC1B,GAAQ,YAAiB,IAEzB,EAAK,YAAiB,MACrB,GAAM,UAAW,CACpB,MAAiB,WAAW,CAClB,GAAI,GAAuB,CAE/B,IACC,SAAS,EAAyB,EAAqB,EAAqB,CAEnF,aAGA,EAAoB,EAAE,EAAqB,CACzC,QAAW,UAAW,CAAE,MAAqB,OAI/C,GAAI,GAAe,EAAoB,KACnC,EAAoC,EAAoB,EAAE,GAE1D,EAAS,EAAoB,KAC7B,EAA8B,EAAoB,EAAE,GAEpD,EAAa,EAAoB,KACjC,EAA8B,EAAoB,EAAE,GAOxD,WAAiB,EAAM,CACrB,GAAI,CACF,MAAO,UAAS,YAAY,SACrB,EAAP,CACA,MAAO,IAYX,GAAI,GAAqB,SAA4B,EAAQ,CAC3D,GAAI,GAAe,IAAiB,GACpC,SAAQ,OACD,GAGwB,EAAe,EAOhD,WAA2B,EAAO,CAChC,GAAI,GAAQ,SAAS,gBAAgB,aAAa,SAAW,MACzD,EAAc,SAAS,cAAc,YAEzC,EAAY,MAAM,SAAW,OAE7B,EAAY,MAAM,OAAS,IAC3B,EAAY,MAAM,QAAU,IAC5B,EAAY,MAAM,OAAS,IAE3B,EAAY,MAAM,SAAW,WAC7B,EAAY,MAAM,EAAQ,QAAU,QAAU,UAE9C,GAAI,GAAY,OAAO,aAAe,SAAS,gBAAgB,UAC/D,SAAY,MAAM,IAAM,GAAG,OAAO,EAAW,MAC7C,EAAY,aAAa,WAAY,IACrC,EAAY,MAAQ,EACb,EAaT,GAAI,GAAsB,SAA6B,EAAQ,CAC7D,GAAI,GAAU,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,CAChF,UAAW,SAAS,MAElB,EAAe,GAEnB,GAAI,MAAO,IAAW,SAAU,CAC9B,GAAI,GAAc,EAAkB,GACpC,EAAQ,UAAU,YAAY,GAC9B,EAAe,IAAiB,GAChC,EAAQ,QACR,EAAY,aAEZ,GAAe,IAAiB,GAChC,EAAQ,QAGV,MAAO,IAGwB,EAAgB,EAEjD,WAAiB,EAAK,CAA6B,MAAI,OAAO,SAAW,YAAc,MAAO,QAAO,UAAa,SAAY,EAAU,SAAiB,EAAK,CAAE,MAAO,OAAO,IAAiB,EAAU,SAAiB,EAAK,CAAE,MAAO,IAAO,MAAO,SAAW,YAAc,EAAI,cAAgB,QAAU,IAAQ,OAAO,UAAY,SAAW,MAAO,IAAiB,EAAQ,GAUnX,GAAI,GAAyB,UAAkC,CAC7D,GAAI,GAAU,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,GAE9E,EAAkB,EAAQ,OAC1B,EAAS,IAAoB,OAAS,OAAS,EAC/C,EAAY,EAAQ,UACpB,EAAS,EAAQ,OACjB,GAAO,EAAQ,KAEnB,GAAI,IAAW,QAAU,IAAW,MAClC,KAAM,IAAI,OAAM,sDAIlB,GAAI,IAAW,OACb,GAAI,GAAU,EAAQ,KAAY,UAAY,EAAO,WAAa,EAAG,CACnE,GAAI,IAAW,QAAU,EAAO,aAAa,YAC3C,KAAM,IAAI,OAAM,qFAGlB,GAAI,IAAW,OAAU,GAAO,aAAa,aAAe,EAAO,aAAa,aAC9E,KAAM,IAAI,OAAM,6GAGlB,MAAM,IAAI,OAAM,+CAKpB,GAAI,GACF,MAAO,GAAa,GAAM,CACxB,UAAW,IAKf,GAAI,EACF,MAAO,KAAW,MAAQ,EAAY,GAAU,EAAa,EAAQ,CACnE,UAAW,KAKgB,GAAmB,EAEpD,YAA0B,EAAK,CAA6B,MAAI,OAAO,SAAW,YAAc,MAAO,QAAO,UAAa,SAAY,GAAmB,SAAiB,EAAK,CAAE,MAAO,OAAO,IAAiB,GAAmB,SAAiB,EAAK,CAAE,MAAO,IAAO,MAAO,SAAW,YAAc,EAAI,cAAgB,QAAU,IAAQ,OAAO,UAAY,SAAW,MAAO,IAAiB,GAAiB,GAEvZ,YAAyB,EAAU,EAAa,CAAE,GAAI,CAAE,aAAoB,IAAgB,KAAM,IAAI,WAAU,qCAEhH,YAA2B,EAAQ,EAAO,CAAE,OAAS,GAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CAAE,GAAI,GAAa,EAAM,GAAI,EAAW,WAAa,EAAW,YAAc,GAAO,EAAW,aAAe,GAAU,SAAW,IAAY,GAAW,SAAW,IAAM,OAAO,eAAe,EAAQ,EAAW,IAAK,IAE7S,YAAsB,EAAa,EAAY,EAAa,CAAE,MAAI,IAAY,GAAkB,EAAY,UAAW,GAAiB,GAAa,GAAkB,EAAa,GAAqB,EAEzM,YAAmB,EAAU,EAAY,CAAE,GAAI,MAAO,IAAe,YAAc,IAAe,KAAQ,KAAM,IAAI,WAAU,sDAAyD,EAAS,UAAY,OAAO,OAAO,GAAc,EAAW,UAAW,CAAE,YAAa,CAAE,MAAO,EAAU,SAAU,GAAM,aAAc,MAAe,GAAY,GAAgB,EAAU,GAEnX,YAAyB,EAAG,EAAG,CAAE,UAAkB,OAAO,gBAAkB,SAAyB,EAAG,EAAG,CAAE,SAAE,UAAY,EAAU,GAAa,GAAgB,EAAG,GAErK,YAAsB,EAAS,CAAE,GAAI,GAA4B,KAA6B,MAAO,WAAgC,CAAE,GAAI,GAAQ,GAAgB,GAAU,EAAQ,GAAI,EAA2B,CAAE,GAAI,GAAY,GAAgB,MAAM,YAAa,EAAS,QAAQ,UAAU,EAAO,UAAW,OAAqB,GAAS,EAAM,MAAM,KAAM,WAAc,MAAO,IAA2B,KAAM,IAE5Z,YAAoC,EAAM,EAAM,CAAE,MAAI,IAAS,IAAiB,KAAU,UAAY,MAAO,IAAS,YAAsB,EAAe,GAAuB,GAElL,YAAgC,EAAM,CAAE,GAAI,IAAS,OAAU,KAAM,IAAI,gBAAe,6DAAgE,MAAO,GAE/J,aAAqC,CAA0E,GAApE,MAAO,UAAY,aAAe,CAAC,QAAQ,WAA6B,QAAQ,UAAU,KAAM,MAAO,GAAO,GAAI,MAAO,QAAU,WAAY,MAAO,GAAM,GAAI,CAAE,YAAK,UAAU,SAAS,KAAK,QAAQ,UAAU,KAAM,GAAI,UAAY,KAAa,SAAe,EAAP,CAAY,MAAO,IAE1T,YAAyB,EAAG,CAAE,UAAkB,OAAO,eAAiB,OAAO,eAAiB,SAAyB,EAAG,CAAE,MAAO,GAAE,WAAa,OAAO,eAAe,IAAc,GAAgB,GAaxM,YAA2B,EAAQ,EAAS,CAC1C,GAAI,GAAY,kBAAkB,OAAO,GAEzC,GAAI,EAAC,EAAQ,aAAa,GAI1B,MAAO,GAAQ,aAAa,GAQ9B,GAAI,IAAyB,SAAU,EAAU,CAC/C,GAAU,EAAW,GAErB,GAAI,GAAS,GAAa,GAM1B,WAAmB,EAAS,EAAS,CACnC,GAAI,GAEJ,UAAgB,KAAM,GAEtB,EAAQ,EAAO,KAAK,MAEpB,EAAM,eAAe,GAErB,EAAM,YAAY,GAEX,EAST,UAAa,EAAW,CAAC,CACvB,IAAK,iBACL,MAAO,UAA0B,CAC/B,GAAI,GAAU,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,GAClF,KAAK,OAAS,MAAO,GAAQ,QAAW,WAAa,EAAQ,OAAS,KAAK,cAC3E,KAAK,OAAS,MAAO,GAAQ,QAAW,WAAa,EAAQ,OAAS,KAAK,cAC3E,KAAK,KAAO,MAAO,GAAQ,MAAS,WAAa,EAAQ,KAAO,KAAK,YACrE,KAAK,UAAY,GAAiB,EAAQ,aAAe,SAAW,EAAQ,UAAY,SAAS,OAOlG,CACD,IAAK,cACL,MAAO,SAAqB,EAAS,CACnC,GAAI,GAAS,KAEb,KAAK,SAAW,IAAiB,EAAS,QAAS,SAAU,GAAG,CAC9D,MAAO,GAAO,QAAQ,QAQzB,CACD,IAAK,UACL,MAAO,SAAiB,EAAG,CACzB,GAAI,GAAU,EAAE,gBAAkB,EAAE,cAChC,GAAS,KAAK,OAAO,IAAY,OACjC,GAAO,GAAgB,CACzB,OAAQ,GACR,UAAW,KAAK,UAChB,OAAQ,KAAK,OAAO,GACpB,KAAM,KAAK,KAAK,KAGlB,KAAK,KAAK,GAAO,UAAY,QAAS,CACpC,OAAQ,GACR,KAAM,GACN,QAAS,EACT,eAAgB,UAA0B,CACxC,AAAI,GACF,EAAQ,QAGV,SAAS,cAAc,OACvB,OAAO,eAAe,uBAS3B,CACD,IAAK,gBACL,MAAO,SAAuB,EAAS,CACrC,MAAO,IAAkB,SAAU,KAOpC,CACD,IAAK,gBACL,MAAO,SAAuB,EAAS,CACrC,GAAI,GAAW,GAAkB,SAAU,GAE3C,GAAI,EACF,MAAO,UAAS,cAAc,KAUjC,CACD,IAAK,cAML,MAAO,SAAqB,EAAS,CACnC,MAAO,IAAkB,OAAQ,KAMlC,CACD,IAAK,UACL,MAAO,UAAmB,CACxB,KAAK,SAAS,aAEd,CAAC,CACH,IAAK,OACL,MAAO,SAAc,EAAQ,CAC3B,GAAI,GAAU,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,CAChF,UAAW,SAAS,MAEtB,MAAO,GAAa,EAAQ,KAQ7B,CACD,IAAK,MACL,MAAO,SAAa,EAAQ,CAC1B,MAAO,GAAY,KAQpB,CACD,IAAK,cACL,MAAO,UAAuB,CAC5B,GAAI,GAAS,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,CAAC,OAAQ,OACtF,EAAU,MAAO,IAAW,SAAW,CAAC,GAAU,EAClD,GAAU,CAAC,CAAC,SAAS,sBACzB,SAAQ,QAAQ,SAAU,GAAQ,CAChC,GAAU,IAAW,CAAC,CAAC,SAAS,sBAAsB,MAEjD,OAIJ,GACN,KAE8B,GAAa,IAIxC,IACC,SAAS,EAAQ,CAExB,GAAI,GAAqB,EAKzB,GAAI,MAAO,UAAY,aAAe,CAAC,QAAQ,UAAU,QAAS,CAC9D,GAAI,GAAQ,QAAQ,UAEpB,EAAM,QAAU,EAAM,iBACN,EAAM,oBACN,EAAM,mBACN,EAAM,kBACN,EAAM,sBAU1B,WAAkB,EAAS,EAAU,CACjC,KAAO,GAAW,EAAQ,WAAa,GAAoB,CACvD,GAAI,MAAO,GAAQ,SAAY,YAC3B,EAAQ,QAAQ,GAClB,MAAO,GAET,EAAU,EAAQ,YAI1B,EAAO,QAAU,GAKX,IACC,SAAS,EAAQ,EAA0B,EAAqB,CAEvE,GAAI,GAAU,EAAoB,KAYlC,WAAmB,EAAS,EAAU,EAAM,EAAU,EAAY,CAC9D,GAAI,GAAa,EAAS,MAAM,KAAM,WAEtC,SAAQ,iBAAiB,EAAM,EAAY,GAEpC,CACH,QAAS,UAAW,CAChB,EAAQ,oBAAoB,EAAM,EAAY,KAe1D,WAAkB,EAAU,EAAU,EAAM,EAAU,EAAY,CAE9D,MAAI,OAAO,GAAS,kBAAqB,WAC9B,EAAU,MAAM,KAAM,WAI7B,MAAO,IAAS,WAGT,EAAU,KAAK,KAAM,UAAU,MAAM,KAAM,WAIlD,OAAO,IAAa,UACpB,GAAW,SAAS,iBAAiB,IAIlC,MAAM,UAAU,IAAI,KAAK,EAAU,SAAU,EAAS,CACzD,MAAO,GAAU,EAAS,EAAU,EAAM,EAAU,MAa5D,WAAkB,EAAS,EAAU,EAAM,EAAU,CACjD,MAAO,UAAS,EAAG,CACf,EAAE,eAAiB,EAAQ,EAAE,OAAQ,GAEjC,EAAE,gBACF,EAAS,KAAK,EAAS,IAKnC,EAAO,QAAU,GAKX,IACC,SAAS,EAAyB,EAAS,CAQlD,EAAQ,KAAO,SAAS,EAAO,CAC3B,MAAO,KAAU,QACV,YAAiB,cACjB,EAAM,WAAa,GAS9B,EAAQ,SAAW,SAAS,EAAO,CAC/B,GAAI,GAAO,OAAO,UAAU,SAAS,KAAK,GAE1C,MAAO,KAAU,QACT,KAAS,qBAAuB,IAAS,4BACzC,UAAY,IACZ,GAAM,SAAW,GAAK,EAAQ,KAAK,EAAM,MASrD,EAAQ,OAAS,SAAS,EAAO,CAC7B,MAAO,OAAO,IAAU,UACjB,YAAiB,SAS5B,EAAQ,GAAK,SAAS,EAAO,CACzB,GAAI,GAAO,OAAO,UAAU,SAAS,KAAK,GAE1C,MAAO,KAAS,sBAMd,IACC,SAAS,EAAQ,EAA0B,EAAqB,CAEvE,GAAI,GAAK,EAAoB,KACzB,EAAW,EAAoB,KAWnC,WAAgB,EAAQ,EAAM,EAAU,CACpC,GAAI,CAAC,GAAU,CAAC,GAAQ,CAAC,EACrB,KAAM,IAAI,OAAM,8BAGpB,GAAI,CAAC,EAAG,OAAO,GACX,KAAM,IAAI,WAAU,oCAGxB,GAAI,CAAC,EAAG,GAAG,GACP,KAAM,IAAI,WAAU,qCAGxB,GAAI,EAAG,KAAK,GACR,MAAO,GAAW,EAAQ,EAAM,GAE/B,GAAI,EAAG,SAAS,GACjB,MAAO,GAAe,EAAQ,EAAM,GAEnC,GAAI,EAAG,OAAO,GACf,MAAO,GAAe,EAAQ,EAAM,GAGpC,KAAM,IAAI,WAAU,6EAa5B,WAAoB,EAAM,EAAM,EAAU,CACtC,SAAK,iBAAiB,EAAM,GAErB,CACH,QAAS,UAAW,CAChB,EAAK,oBAAoB,EAAM,KAc3C,WAAwB,EAAU,EAAM,EAAU,CAC9C,aAAM,UAAU,QAAQ,KAAK,EAAU,SAAS,EAAM,CAClD,EAAK,iBAAiB,EAAM,KAGzB,CACH,QAAS,UAAW,CAChB,MAAM,UAAU,QAAQ,KAAK,EAAU,SAAS,EAAM,CAClD,EAAK,oBAAoB,EAAM,OAe/C,WAAwB,EAAU,EAAM,EAAU,CAC9C,MAAO,GAAS,SAAS,KAAM,EAAU,EAAM,GAGnD,EAAO,QAAU,GAKX,IACC,SAAS,EAAQ,CAExB,WAAgB,EAAS,CACrB,GAAI,GAEJ,GAAI,EAAQ,WAAa,SACrB,EAAQ,QAER,EAAe,EAAQ,cAElB,EAAQ,WAAa,SAAW,EAAQ,WAAa,WAAY,CACtE,GAAI,GAAa,EAAQ,aAAa,YAEtC,AAAK,GACD,EAAQ,aAAa,WAAY,IAGrC,EAAQ,SACR,EAAQ,kBAAkB,EAAG,EAAQ,MAAM,QAEtC,GACD,EAAQ,gBAAgB,YAG5B,EAAe,EAAQ,UAEtB,CACD,AAAI,EAAQ,aAAa,oBACrB,EAAQ,QAGZ,GAAI,GAAY,OAAO,eACnB,EAAQ,SAAS,cAErB,EAAM,mBAAmB,GACzB,EAAU,kBACV,EAAU,SAAS,GAEnB,EAAe,EAAU,WAG7B,MAAO,GAGX,EAAO,QAAU,GAKX,IACC,SAAS,EAAQ,CAExB,YAAc,EAKd,EAAE,UAAY,CACZ,GAAI,SAAU,EAAM,EAAU,EAAK,CACjC,GAAI,GAAI,KAAK,GAAM,MAAK,EAAI,IAE5B,MAAC,GAAE,IAAU,GAAE,GAAQ,KAAK,KAAK,CAC/B,GAAI,EACJ,IAAK,IAGA,MAGT,KAAM,SAAU,EAAM,EAAU,EAAK,CACnC,GAAI,GAAO,KACX,YAAqB,CACnB,EAAK,IAAI,EAAM,GACf,EAAS,MAAM,EAAK,WAGtB,SAAS,EAAI,EACN,KAAK,GAAG,EAAM,EAAU,IAGjC,KAAM,SAAU,EAAM,CACpB,GAAI,GAAO,GAAG,MAAM,KAAK,UAAW,GAChC,EAAW,OAAK,GAAM,MAAK,EAAI,KAAK,IAAS,IAAI,QACjD,EAAI,EACJ,EAAM,EAAO,OAEjB,IAAK,EAAG,EAAI,EAAK,IACf,EAAO,GAAG,GAAG,MAAM,EAAO,GAAG,IAAK,GAGpC,MAAO,OAGT,IAAK,SAAU,EAAM,EAAU,CAC7B,GAAI,GAAI,KAAK,GAAM,MAAK,EAAI,IACxB,EAAO,EAAE,GACT,EAAa,GAEjB,GAAI,GAAQ,EACV,OAAS,GAAI,EAAG,EAAM,EAAK,OAAQ,EAAI,EAAK,IAC1C,AAAI,EAAK,GAAG,KAAO,GAAY,EAAK,GAAG,GAAG,IAAM,GAC9C,EAAW,KAAK,EAAK,IAQ3B,MAAC,GAAW,OACR,EAAE,GAAQ,EACV,MAAO,GAAE,GAEN,OAIX,EAAO,QAAU,EACjB,EAAO,QAAQ,YAAc,IAQf,EAA2B,GAG/B,WAA6B,EAAU,CAEtC,GAAG,EAAyB,GAC3B,MAAO,GAAyB,GAAU,QAG3C,GAAI,GAAS,EAAyB,GAAY,CAGjD,QAAS,IAIV,SAAoB,GAAU,EAAQ,EAAO,QAAS,GAG/C,EAAO,QAKf,MAAC,WAAW,CAEX,EAAoB,EAAI,SAAS,EAAQ,CACxC,GAAI,GAAS,GAAU,EAAO,WAC7B,UAAW,CAAE,MAAO,GAAO,SAC3B,UAAW,CAAE,MAAO,IACrB,SAAoB,EAAE,EAAQ,CAAE,EAAG,IAC5B,MAKR,UAAW,CAEX,EAAoB,EAAI,SAAS,EAAS,EAAY,CACrD,OAAQ,KAAO,GACd,AAAG,EAAoB,EAAE,EAAY,IAAQ,CAAC,EAAoB,EAAE,EAAS,IAC5E,OAAO,eAAe,EAAS,EAAK,CAAE,WAAY,GAAM,IAAK,EAAW,SAO3E,UAAW,CACX,EAAoB,EAAI,SAAS,EAAK,EAAM,CAAE,MAAO,QAAO,UAAU,eAAe,KAAK,EAAK,OAOzF,EAAoB,QAEpC,YC12BD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAeA,GAAI,IAAkB,UAOtB,GAAO,QAAU,GAUjB,YAAoB,EAAQ,CAC1B,GAAI,GAAM,GAAK,EACX,EAAQ,GAAgB,KAAK,GAEjC,GAAI,CAAC,EACH,MAAO,GAGT,GAAI,GACA,EAAO,GACP,EAAQ,EACR,EAAY,EAEhB,IAAK,EAAQ,EAAM,MAAO,EAAQ,EAAI,OAAQ,IAAS,CACrD,OAAQ,EAAI,WAAW,QAChB,IACH,EAAS,SACT,UACG,IACH,EAAS,QACT,UACG,IACH,EAAS,QACT,UACG,IACH,EAAS,OACT,UACG,IACH,EAAS,OACT,cAEA,SAGJ,AAAI,IAAc,GAChB,IAAQ,EAAI,UAAU,EAAW,IAGnC,EAAY,EAAQ,EACpB,GAAQ,EAGV,MAAO,KAAc,EACjB,EAAO,EAAI,UAAU,EAAW,GAChC,KC5EN,MAAM,UAAU,MAAM,OAAO,eAAe,MAAM,UAAU,OAAO,CAAC,aAAa,GAAG,MAAM,YAAY,CAAC,GAAI,GAAE,MAAM,UAAU,IAAI,EAAE,OAAO,UAAU,IAAI,MAAO,GAAE,MAAM,UAAU,OAAO,KAAK,KAAK,SAAS,EAAE,EAAE,CAAC,MAAO,OAAM,QAAQ,GAAG,EAAE,KAAK,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,GAAG,GAAG,IAAI,MAAM,UAAU,MAAM,KAAK,OAAO,SAAS,KAAK,MAAM,UAAU,SAAS,OAAO,eAAe,MAAM,UAAU,UAAU,CAAC,aAAa,GAAG,MAAM,SAAS,EAAE,CAAC,MAAO,OAAM,UAAU,IAAI,MAAM,KAAK,WAAW,QAAQ,SAAS,KCuBrf,OAAO,SCvBP,KAAK,OAAQ,MAAK,MAAM,SAAS,EAAE,EAAE,CAAC,MAAO,GAAE,GAAG,GAAG,GAAI,SAAQ,SAAS,EAAE,EAAE,CAAC,GAAI,GAAE,GAAI,gBAAe,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,GAAG,AAAI,GAAE,OAAO,IAAI,IAAjB,EAAoB,WAAW,EAAE,WAAW,OAAO,EAAE,OAAO,IAAI,EAAE,YAAY,KAAK,UAAU,CAAC,MAAO,SAAQ,QAAQ,EAAE,eAAe,KAAK,UAAU,CAAC,MAAO,SAAQ,QAAQ,EAAE,cAAc,KAAK,KAAK,QAAQ,KAAK,UAAU,CAAC,MAAO,SAAQ,QAAQ,GAAI,MAAK,CAAC,EAAE,aAAa,MAAM,EAAE,QAAQ,CAAC,KAAK,UAAU,CAAC,MAAO,IAAG,QAAQ,UAAU,CAAC,MAAO,IAAG,IAAI,SAAS,EAAE,CAAC,MAAO,GAAE,EAAE,gBAAgB,IAAI,SAAS,EAAE,CAAC,MAAO,GAAE,eAAgB,OAAM,OAAQ,KAAK,GAAE,KAAK,EAAE,QAAQ,MAAM,EAAE,IAAI,EAAE,OAAO,UAAU,CAAC,EAAE,wBAAwB,QAAQ,+BAA+B,SAAS,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,eAAe,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,gBAAgB,AAAW,EAAE,aAAb,UAAyB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,EAAE,QAAQ,IAAI,EAAE,KAAK,EAAE,MAAM,UDyB14B,OAAO,SEzBP,OAAkB,WACZ,CACF,aACA,YACA,UACA,cACA,WACA,cACA,aACA,eACA,gBACA,mBACA,YACA,SACA,YACA,kBACA,gBACA,WACA,oBACA,oBACA,iBACA,wBACA,gBACA,mBACA,0BACA,2BACA,WCtBE,WAAqB,EAAU,CACnC,MAAO,OAAO,IAAU,WCIpB,YAA8B,EAAgC,CAClE,GAAM,GAAS,SAAC,EAAa,CAC3B,MAAM,KAAK,GACX,EAAS,MAAQ,GAAI,SAAQ,OAGzB,EAAW,EAAW,GAC5B,SAAS,UAAY,OAAO,OAAO,MAAM,WACzC,EAAS,UAAU,YAAc,EAC1B,ECAF,GAAM,IAA+C,GAC1D,SAAC,EAAM,CACL,MAAA,UAA4C,EAA0B,CACpE,EAAO,MACP,KAAK,QAAU,EACR,EAAO,OAAM;EACxB,EAAO,IAAI,SAAC,EAAK,EAAC,CAAK,MAAG,GAAI,EAAC,KAAK,EAAI,aAAc,KAAK;KACnD,GACJ,KAAK,KAAO,sBACZ,KAAK,OAAS,KCtBd,YAAuB,EAA6B,EAAO,CAC/D,GAAI,EAAK,CACP,GAAM,GAAQ,EAAI,QAAQ,GAC1B,GAAK,GAAS,EAAI,OAAO,EAAO,ICSpC,GAAA,IAAA,UAAA,CAyBE,WAAoB,EAA4B,CAA5B,KAAA,gBAAA,EAdb,KAAA,OAAS,GAER,KAAA,WAAmD,KAMnD,KAAA,WAAoD,KAc5D,SAAA,UAAA,YAAA,UAAA,aACM,EAEJ,GAAI,CAAC,KAAK,OAAQ,CAChB,KAAK,OAAS,GAGN,GAAA,GAAe,KAAI,WAC3B,GAAI,EAEF,GADA,KAAK,WAAa,KACd,MAAM,QAAQ,OAChB,OAAqB,GAAA,GAAA,GAAU,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAA5B,GAAM,GAAM,EAAA,MACf,EAAO,OAAO,4GAGhB,GAAW,OAAO,MAId,GAAA,GAAoB,KAAI,gBAChC,GAAI,EAAW,GACb,GAAI,CACF,UACO,EAAP,CACA,EAAS,YAAa,IAAsB,EAAE,OAAS,CAAC,GAIpD,GAAA,GAAe,KAAI,WAC3B,GAAI,EAAY,CACd,KAAK,WAAa,SAClB,OAAuB,GAAA,GAAA,GAAU,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAA9B,GAAM,GAAQ,EAAA,MACjB,GAAI,CACF,GAAa,SACN,EAAP,CACA,EAAS,GAAM,KAAN,EAAU,GACnB,AAAI,YAAe,IACjB,EAAM,EAAA,EAAA,GAAA,EAAO,IAAM,EAAK,EAAI,SAE5B,EAAO,KAAK,uGAMpB,GAAI,EACF,KAAM,IAAI,IAAoB,KAuBpC,EAAA,UAAA,IAAA,SAAI,EAAuB,OAGzB,GAAI,GAAY,IAAa,KAC3B,GAAI,KAAK,OAGP,GAAa,OACR,CACL,GAAI,YAAoB,GAAc,CAGpC,GAAI,EAAS,QAAU,EAAS,WAAW,MACzC,OAEF,EAAS,WAAW,MAEtB,AAAC,MAAK,WAAa,GAAA,KAAK,cAAU,MAAA,IAAA,OAAA,EAAI,IAAI,KAAK,KAU7C,EAAA,UAAA,WAAR,SAAmB,EAAoB,CAC7B,GAAA,GAAe,KAAI,WAC3B,MAAO,KAAe,GAAW,MAAM,QAAQ,IAAe,EAAW,SAAS,IAU5E,EAAA,UAAA,WAAR,SAAmB,EAAoB,CAC7B,GAAA,GAAe,KAAI,WAC3B,KAAK,WAAa,MAAM,QAAQ,GAAe,GAAW,KAAK,GAAS,GAAc,EAAa,CAAC,EAAY,GAAU,GAOpH,EAAA,UAAA,cAAR,SAAsB,EAAoB,CAChC,GAAA,GAAe,KAAI,WAC3B,AAAI,IAAe,EACjB,KAAK,WAAa,KACT,MAAM,QAAQ,IACvB,GAAU,EAAY,IAkB1B,EAAA,UAAA,OAAA,SAAO,EAAsC,CACnC,GAAA,GAAe,KAAI,WAC3B,GAAc,GAAU,EAAY,GAEhC,YAAoB,IACtB,EAAS,cAAc,OAhLb,EAAA,MAAS,UAAA,CACrB,GAAM,GAAQ,GAAI,GAClB,SAAM,OAAS,GACR,KAgLX,KAEO,GAAM,IAAqB,GAAa,MAEzC,YAAyB,EAAU,CACvC,MACE,aAAiB,KAChB,GAAS,UAAY,IAAS,EAAW,EAAM,SAAW,EAAW,EAAM,MAAQ,EAAW,EAAM,aAIzG,YAAsB,EAAuC,CAC3D,AAAI,EAAW,GACb,IAEA,EAAS,cC9MN,GAAM,IAAuB,CAClC,iBAAkB,KAClB,sBAAuB,KACvB,QAAS,OACT,sCAAuC,GACvC,yBAA0B,ICErB,GAAM,IAAmC,CAG9C,WAAU,UAAA,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACD,GAAA,GAAa,GAAe,SACpC,MAAQ,KAAQ,KAAA,OAAR,EAAU,aAAc,YAAW,MAAA,OAAA,EAAA,GAAA,EAAI,MAEjD,aAAY,SAAC,EAAM,CACT,GAAA,GAAa,GAAe,SACpC,MAAQ,KAAQ,KAAA,OAAR,EAAU,eAAgB,cAAc,IAElD,SAAU,QCbN,YAA+B,EAAQ,CAC3C,GAAgB,WAAW,UAAA,CACjB,GAAA,GAAqB,GAAM,iBACnC,GAAI,EAEF,EAAiB,OAGjB,MAAM,KCnBN,aAAc,ECMb,GAAM,IAAyB,UAAA,CAAM,MAAA,IAAmB,IAAK,OAAW,WAOzE,YAA4B,EAAU,CAC1C,MAAO,IAAmB,IAAK,OAAW,GAQtC,YAA8B,EAAQ,CAC1C,MAAO,IAAmB,IAAK,EAAO,QASlC,YAA6B,EAAuB,EAAY,EAAU,CAC9E,MAAO,CACL,KAAI,EACJ,MAAK,EACL,MAAK,GCnCT,GAAI,IAAuD,KASrD,YAAuB,EAAc,CACzC,GAAI,GAAO,sCAAuC,CAChD,GAAM,GAAS,CAAC,GAKhB,GAJI,GACF,IAAU,CAAE,YAAa,GAAO,MAAO,OAEzC,IACI,EAAQ,CACJ,GAAA,GAAyB,GAAvB,EAAW,EAAA,YAAE,EAAK,EAAA,MAE1B,GADA,GAAU,KACN,EACF,KAAM,QAMV,KAQE,YAAuB,EAAQ,CACnC,AAAI,GAAO,uCAAyC,IAClD,IAAQ,YAAc,GACtB,GAAQ,MAAQ,GCnBpB,GAAA,IAAA,SAAA,EAAA,CAAmC,GAAA,EAAA,GA6BjC,WAAY,EAA6C,CAAzD,GAAA,GACE,EAAA,KAAA,OAAO,KATC,SAAA,UAAqB,GAU7B,AAAI,EACF,GAAK,YAAc,EAGf,GAAe,IACjB,EAAY,IAAI,IAGlB,EAAK,YAAc,KAvBhB,SAAA,OAAP,SAAiB,EAAwB,EAA2B,EAAqB,CACvF,MAAO,IAAI,IAAe,EAAM,EAAO,IAiCzC,EAAA,UAAA,KAAA,SAAK,EAAS,CACZ,AAAI,KAAK,UACP,GAA0B,GAAiB,GAAQ,MAEnD,KAAK,MAAM,IAWf,EAAA,UAAA,MAAA,SAAM,EAAS,CACb,AAAI,KAAK,UACP,GAA0B,GAAkB,GAAM,MAElD,MAAK,UAAY,GACjB,KAAK,OAAO,KAUhB,EAAA,UAAA,SAAA,UAAA,CACE,AAAI,KAAK,UACP,GAA0B,GAAuB,MAEjD,MAAK,UAAY,GACjB,KAAK,cAIT,EAAA,UAAA,YAAA,UAAA,CACE,AAAK,KAAK,QACR,MAAK,UAAY,GACjB,EAAA,UAAM,YAAW,KAAA,MACjB,KAAK,YAAc,OAIb,EAAA,UAAA,MAAV,SAAgB,EAAQ,CACtB,KAAK,YAAY,KAAK,IAGd,EAAA,UAAA,OAAV,SAAiB,EAAQ,CACvB,GAAI,CACF,KAAK,YAAY,MAAM,WAEvB,KAAK,gBAIC,EAAA,UAAA,UAAV,UAAA,CACE,GAAI,CACF,KAAK,YAAY,mBAEjB,KAAK,gBAGX,GApHmC,IA2HnC,GAAM,IAAQ,SAAS,UAAU,KAEjC,YAAkD,EAAQ,EAAY,CACpE,MAAO,IAAM,KAAK,EAAI,GAOxB,GAAA,IAAA,UAAA,CACE,WAAoB,EAAqC,CAArC,KAAA,gBAAA,EAEpB,SAAA,UAAA,KAAA,SAAK,EAAQ,CACH,GAAA,GAAoB,KAAI,gBAChC,GAAI,EAAgB,KAClB,GAAI,CACF,EAAgB,KAAK,SACd,EAAP,CACA,GAAqB,KAK3B,EAAA,UAAA,MAAA,SAAM,EAAQ,CACJ,GAAA,GAAoB,KAAI,gBAChC,GAAI,EAAgB,MAClB,GAAI,CACF,EAAgB,MAAM,SACf,EAAP,CACA,GAAqB,OAGvB,IAAqB,IAIzB,EAAA,UAAA,SAAA,UAAA,CACU,GAAA,GAAoB,KAAI,gBAChC,GAAI,EAAgB,SAClB,GAAI,CACF,EAAgB,iBACT,EAAP,CACA,GAAqB,KAI7B,KAEA,GAAA,SAAA,EAAA,CAAuC,GAAA,EAAA,GACrC,WACE,EACA,EACA,EAA8B,CAHhC,GAAA,GAKE,EAAA,KAAA,OAAO,KAEH,EACJ,GAAI,EAAW,IAAmB,CAAC,EAGjC,EAAkB,CAChB,KAAM,GAAc,KAAd,EAAkB,OACxB,MAAO,GAAK,KAAL,EAAS,OAChB,SAAU,GAAQ,KAAR,EAAY,YAEnB,CAEL,GAAI,GACJ,AAAI,GAAQ,GAAO,yBAIjB,GAAU,OAAO,OAAO,GACxB,EAAQ,YAAc,UAAA,CAAM,MAAA,GAAK,eACjC,EAAkB,CAChB,KAAM,EAAe,MAAQ,GAAK,EAAe,KAAM,GACvD,MAAO,EAAe,OAAS,GAAK,EAAe,MAAO,GAC1D,SAAU,EAAe,UAAY,GAAK,EAAe,SAAU,KAIrE,EAAkB,EAMtB,SAAK,YAAc,GAAI,IAAiB,KAE5C,MAAA,IAzCuC,IA2CvC,YAA8B,EAAU,CACtC,AAAI,GAAO,sCACT,GAAa,GAIb,GAAqB,GAUzB,YAA6B,EAAQ,CACnC,KAAM,GAQR,YAAmC,EAA2C,EAA2B,CAC/F,GAAA,GAA0B,GAAM,sBACxC,GAAyB,GAAgB,WAAW,UAAA,CAAM,MAAA,GAAsB,EAAc,KAQzF,GAAM,IAA6D,CACxE,OAAQ,GACR,KAAM,GACN,MAAO,GACP,SAAU,ICjRL,GAAM,IAA+B,UAAA,CAAM,MAAC,OAAO,SAAW,YAAc,OAAO,YAAe,kBCyCnG,YAAsB,EAAI,CAC9B,MAAO,GCkCH,aAAc,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACnB,MAAO,IAAc,GAIjB,YAA8B,EAA+B,CACjE,MAAI,GAAI,SAAW,EACV,GAGL,EAAI,SAAW,EACV,EAAI,GAGN,SAAe,EAAQ,CAC5B,MAAO,GAAI,OAAO,SAAC,EAAW,EAAuB,CAAK,MAAA,GAAG,IAAO,IC5ExE,GAAA,GAAA,UAAA,CAkBE,WAAY,EAA6E,CACvF,AAAI,GACF,MAAK,WAAa,GA8BtB,SAAA,UAAA,KAAA,SAAQ,EAAyB,CAC/B,GAAM,GAAa,GAAI,GACvB,SAAW,OAAS,KACpB,EAAW,SAAW,EACf,GA+IT,EAAA,UAAA,UAAA,SACE,EACA,EACA,EAA8B,CAHhC,GAAA,GAAA,KAKQ,EAAa,GAAa,GAAkB,EAAiB,GAAI,IAAe,EAAgB,EAAO,GAE7G,UAAa,UAAA,CACL,GAAA,GAAuB,EAArB,EAAQ,EAAA,SAAE,EAAM,EAAA,OACxB,EAAW,IACT,EAGI,EAAS,KAAK,EAAY,GAC1B,EAIA,EAAK,WAAW,GAGhB,EAAK,cAAc,MAIpB,GAIC,EAAA,UAAA,cAAV,SAAwB,EAAmB,CACzC,GAAI,CACF,MAAO,MAAK,WAAW,SAChB,EAAP,CAIA,EAAK,MAAM,KA+Df,EAAA,UAAA,QAAA,SAAQ,EAA0B,EAAoC,CAAtE,GAAA,GAAA,KACE,SAAc,GAAe,GAEtB,GAAI,GAAkB,SAAC,EAAS,EAAM,CAC3C,GAAM,GAAa,GAAI,IAAkB,CACvC,KAAM,SAAC,EAAK,CACV,GAAI,CACF,EAAK,SACE,EAAP,CACA,EAAO,GACP,EAAW,gBAGf,MAAO,EACP,SAAU,IAEZ,EAAK,UAAU,MAKT,EAAA,UAAA,WAAV,SAAqB,EAA2B,OAC9C,MAAO,GAAA,KAAK,UAAM,MAAA,IAAA,OAAA,OAAA,EAAE,UAAU,IAQhC,EAAA,UAAC,IAAD,UAAA,CACE,MAAO,OA6FT,EAAA,UAAA,KAAA,UAAA,QAAK,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACH,MAAO,IAAc,GAAY,OA8BnC,EAAA,UAAA,UAAA,SAAU,EAAoC,CAA9C,GAAA,GAAA,KACE,SAAc,GAAe,GAEtB,GAAI,GAAY,SAAC,EAAS,EAAM,CACrC,GAAI,GACJ,EAAK,UACH,SAAC,EAAI,CAAK,MAAC,GAAQ,GACnB,SAAC,EAAQ,CAAK,MAAA,GAAO,IACrB,UAAA,CAAM,MAAA,GAAQ,QAxab,EAAA,OAAkC,SAAI,EAAwD,CACnG,MAAO,IAAI,GAAc,IA2a7B,KASA,YAAwB,EAA+C,OACrE,MAAO,GAAA,GAAW,KAAX,EAAe,GAAO,WAAO,MAAA,IAAA,OAAA,EAAI,QAG1C,YAAuB,EAAU,CAC/B,MAAO,IAAS,EAAW,EAAM,OAAS,EAAW,EAAM,QAAU,EAAW,EAAM,UAGxF,YAAyB,EAAU,CACjC,MAAQ,IAAS,YAAiB,KAAgB,GAAW,IAAU,GAAe,GCzelF,YAAkB,EAAW,CACjC,MAAO,GAAW,GAAM,KAAA,OAAN,EAAQ,MAOtB,WACJ,EAAqF,CAErF,MAAO,UAAC,EAAqB,CAC3B,GAAI,GAAQ,GACV,MAAO,GAAO,KAAK,SAA+B,EAA2B,CAC3E,GAAI,CACF,MAAO,GAAK,EAAc,YACnB,EAAP,CACA,KAAK,MAAM,MAIjB,KAAM,IAAI,WAAU,2CCflB,WACJ,EACA,EACA,EACA,EACA,EAAuB,CAEvB,MAAO,IAAI,IAAmB,EAAa,EAAQ,EAAY,EAAS,GAO1E,GAAA,IAAA,SAAA,EAAA,CAA2C,GAAA,EAAA,GAiBzC,WACE,EACA,EACA,EACA,EACQ,EACA,EAAiC,CAN3C,GAAA,GAoBE,EAAA,KAAA,KAAM,IAAY,KAfV,SAAA,WAAA,EACA,EAAA,kBAAA,EAeR,EAAK,MAAQ,EACT,SAAuC,EAAQ,CAC7C,GAAI,CACF,EAAO,SACA,EAAP,CACA,EAAY,MAAM,KAGtB,EAAA,UAAM,MACV,EAAK,OAAS,EACV,SAAuC,EAAQ,CAC7C,GAAI,CACF,EAAQ,SACD,EAAP,CAEA,EAAY,MAAM,WAGlB,KAAK,gBAGT,EAAA,UAAM,OACV,EAAK,UAAY,EACb,UAAA,CACE,GAAI,CACF,UACO,EAAP,CAEA,EAAY,MAAM,WAGlB,KAAK,gBAGT,EAAA,UAAM,YAGZ,SAAA,UAAA,YAAA,UAAA,OACE,GAAI,CAAC,KAAK,mBAAqB,KAAK,oBAAqB,CAC/C,GAAA,GAAW,KAAI,OACvB,EAAA,UAAM,YAAW,KAAA,MAEjB,CAAC,GAAU,IAAA,KAAK,cAAU,MAAA,IAAA,QAAA,EAAA,KAAf,SAGjB,GAnF2C,ICdpC,GAAM,IAAiD,CAG5D,SAAA,SAAS,EAAQ,CACf,GAAI,GAAU,sBACV,EAAkD,qBAC9C,EAAa,GAAsB,SAC3C,AAAI,GACF,GAAU,EAAS,sBACnB,EAAS,EAAS,sBAEpB,GAAM,GAAS,EAAQ,SAAC,EAAS,CAI/B,EAAS,OACT,EAAS,KAEX,MAAO,IAAI,IAAa,UAAA,CAAM,MAAA,IAAM,KAAA,OAAN,EAAS,MAEzC,sBAAqB,UAAA,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACZ,GAAA,GAAa,GAAsB,SAC3C,MAAQ,KAAQ,KAAA,OAAR,EAAU,wBAAyB,uBAAsB,MAAA,OAAA,EAAA,GAAA,EAAI,MAEvE,qBAAoB,UAAA,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACX,GAAA,GAAa,GAAsB,SAC3C,MAAQ,KAAQ,KAAA,OAAR,EAAU,uBAAwB,sBAAqB,MAAA,OAAA,EAAA,GAAA,EAAI,MAErE,SAAU,QCrBL,GAAM,IAAuD,GAClE,SAAC,EAAM,CACL,MAAA,WAAoC,CAClC,EAAO,MACP,KAAK,KAAO,0BACZ,KAAK,QAAU,yBCVrB,GAAA,GAAA,SAAA,EAAA,CAAgC,GAAA,EAAA,GAqB9B,YAAA,CAAA,GAAA,GAEE,EAAA,KAAA,OAAO,KAtBT,SAAA,OAAS,GAET,EAAA,UAA2B,GAE3B,EAAA,UAAY,GAEZ,EAAA,SAAW,GAEX,EAAA,YAAmB,OAkBnB,SAAA,UAAA,KAAA,SAAQ,EAAwB,CAC9B,GAAM,GAAU,GAAI,IAAiB,KAAM,MAC3C,SAAQ,SAAW,EACZ,GAIC,EAAA,UAAA,eAAV,UAAA,CACE,GAAI,KAAK,OACP,KAAM,IAAI,KAId,EAAA,UAAA,KAAA,SAAK,EAAQ,CAAb,GAAA,GAAA,KACE,GAAa,UAAA,SAEX,GADA,EAAK,iBACD,CAAC,EAAK,UAAW,CACnB,GAAM,GAAO,EAAK,UAAU,YAC5B,OAAuB,GAAA,GAAA,GAAI,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAAxB,GAAM,GAAQ,EAAA,MACjB,EAAS,KAAK,0GAMtB,EAAA,UAAA,MAAA,SAAM,EAAQ,CAAd,GAAA,GAAA,KACE,GAAa,UAAA,CAEX,GADA,EAAK,iBACD,CAAC,EAAK,UAAW,CACnB,EAAK,SAAW,EAAK,UAAY,GACjC,EAAK,YAAc,EAEnB,OADQ,GAAc,EAAI,UACnB,EAAU,QACf,EAAU,QAAS,MAAM,OAMjC,EAAA,UAAA,SAAA,UAAA,CAAA,GAAA,GAAA,KACE,GAAa,UAAA,CAEX,GADA,EAAK,iBACD,CAAC,EAAK,UAAW,CACnB,EAAK,UAAY,GAEjB,OADQ,GAAc,EAAI,UACnB,EAAU,QACf,EAAU,QAAS,eAM3B,EAAA,UAAA,YAAA,UAAA,CACE,KAAK,UAAY,KAAK,OAAS,GAC/B,KAAK,UAAY,MAGnB,OAAA,eAAI,EAAA,UAAA,WAAQ,KAAZ,UAAA,OACE,MAAO,IAAA,KAAK,aAAS,MAAA,IAAA,OAAA,OAAA,EAAE,QAAS,mCAIxB,EAAA,UAAA,cAAV,SAAwB,EAAyB,CAC/C,YAAK,iBACE,EAAA,UAAM,cAAa,KAAA,KAAC,IAInB,EAAA,UAAA,WAAV,SAAqB,EAAyB,CAC5C,YAAK,iBACL,KAAK,wBAAwB,GACtB,KAAK,gBAAgB,IAIpB,EAAA,UAAA,gBAAV,SAA0B,EAA2B,CAC7C,GAAA,GAAqC,KAAnC,EAAQ,EAAA,SAAE,EAAS,EAAA,UAAE,EAAS,EAAA,UACtC,MAAO,IAAY,EACf,GACC,GAAU,KAAK,GAAa,GAAI,IAAa,UAAA,CAAM,MAAA,IAAU,EAAW,OAIrE,EAAA,UAAA,wBAAV,SAAkC,EAA2B,CACrD,GAAA,GAAuC,KAArC,EAAQ,EAAA,SAAE,EAAW,EAAA,YAAE,EAAS,EAAA,UACxC,AAAI,EACF,EAAW,MAAM,GACR,GACT,EAAW,YAUf,EAAA,UAAA,aAAA,UAAA,CACE,GAAM,GAAkB,GAAI,GAC5B,SAAW,OAAS,KACb,GA/GF,EAAA,OAAkC,SAAI,EAA0B,EAAqB,CAC1F,MAAO,IAAI,IAAoB,EAAa,IAgHhD,GAlIgC,GAuIhC,GAAA,IAAA,SAAA,EAAA,CAAyC,GAAA,EAAA,GACvC,WAES,EACP,EAAsB,CAHxB,GAAA,GAKE,EAAA,KAAA,OAAO,KAHA,SAAA,YAAA,EAIP,EAAK,OAAS,IAGhB,SAAA,UAAA,KAAA,SAAK,EAAQ,SACX,AAAA,GAAA,GAAA,KAAK,eAAW,MAAA,IAAA,OAAA,OAAA,EAAE,QAAI,MAAA,IAAA,QAAA,EAAA,KAAA,EAAG,IAG3B,EAAA,UAAA,MAAA,SAAM,EAAQ,SACZ,AAAA,GAAA,GAAA,KAAK,eAAW,MAAA,IAAA,OAAA,OAAA,EAAE,SAAK,MAAA,IAAA,QAAA,EAAA,KAAA,EAAG,IAG5B,EAAA,UAAA,SAAA,UAAA,SACE,AAAA,GAAA,GAAA,KAAK,eAAW,MAAA,IAAA,OAAA,OAAA,EAAE,YAAQ,MAAA,IAAA,QAAA,EAAA,KAAA,IAIlB,EAAA,UAAA,WAAV,SAAqB,EAAyB,SAC5C,MAAO,GAAA,GAAA,KAAK,UAAM,MAAA,IAAA,OAAA,OAAA,EAAE,UAAU,MAAW,MAAA,IAAA,OAAA,EAAI,IAEjD,GA1ByC,GCjJlC,GAAM,IAA+C,CAC1D,IAAG,UAAA,CAGD,MAAQ,IAAsB,UAAY,MAAM,OAElD,SAAU,QCwBZ,GAAA,IAAA,SAAA,EAAA,CAAsC,GAAA,EAAA,GAUpC,WACU,EACA,EACA,EAA6D,CAF7D,AAAA,IAAA,QAAA,GAAA,KACA,IAAA,QAAA,GAAA,KACA,IAAA,QAAA,GAAA,IAHV,GAAA,GAKE,EAAA,KAAA,OAAO,KAJC,SAAA,YAAA,EACA,EAAA,YAAA,EACA,EAAA,mBAAA,EAZF,EAAA,QAA0B,GAC1B,EAAA,oBAAsB,GAc5B,EAAK,oBAAsB,IAAgB,IAC3C,EAAK,YAAc,KAAK,IAAI,EAAG,GAC/B,EAAK,YAAc,KAAK,IAAI,EAAG,KAGjC,SAAA,UAAA,KAAA,SAAK,EAAQ,CACL,GAAA,GAA+E,KAA7E,EAAS,EAAA,UAAE,EAAO,EAAA,QAAE,EAAmB,EAAA,oBAAE,EAAkB,EAAA,mBAAE,EAAW,EAAA,YAChF,AAAK,GACH,GAAQ,KAAK,GACb,CAAC,GAAuB,EAAQ,KAAK,EAAmB,MAAQ,IAElE,KAAK,cACL,EAAA,UAAM,KAAI,KAAA,KAAC,IAIH,EAAA,UAAA,WAAV,SAAqB,EAAyB,CAC5C,KAAK,iBACL,KAAK,cAQL,OANM,GAAe,KAAK,gBAAgB,GAEpC,EAAmC,KAAjC,EAAmB,EAAA,oBAAE,EAAO,EAAA,QAG9B,EAAO,EAAQ,QACZ,EAAI,EAAG,EAAI,EAAK,QAAU,CAAC,EAAW,OAAQ,GAAK,EAAsB,EAAI,EACpF,EAAW,KAAK,EAAK,IAGvB,YAAK,wBAAwB,GAEtB,GAGD,EAAA,UAAA,YAAR,UAAA,CACQ,GAAA,GAAoE,KAAlE,EAAW,EAAA,YAAE,EAAkB,EAAA,mBAAE,EAAO,EAAA,QAAE,EAAmB,EAAA,oBAK/D,EAAsB,GAAsB,EAAI,GAAK,EAK3D,GAJA,EAAc,KAAY,EAAqB,EAAQ,QAAU,EAAQ,OAAO,EAAG,EAAQ,OAAS,GAIhG,CAAC,EAAqB,CAKxB,OAJM,GAAM,EAAmB,MAC3B,EAAO,EAGF,EAAI,EAAG,EAAI,EAAQ,QAAW,EAAQ,IAAiB,EAAK,GAAK,EACxE,EAAO,EAET,GAAQ,EAAQ,OAAO,EAAG,EAAO,KAGvC,GAzEsC,GClBtC,GAAA,IAAA,SAAA,EAAA,CAA+B,GAAA,EAAA,GAC7B,WAAY,EAAsB,EAAmD,OACnF,GAAA,KAAA,OAAO,KAYF,SAAA,UAAA,SAAP,SAAgB,EAAW,EAAiB,CAAjB,MAAA,KAAA,QAAA,GAAA,GAClB,MAEX,GAjB+B,ICJxB,GAAM,IAAqC,CAGhD,YAAW,UAAA,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACF,GAAA,GAAa,GAAgB,SACrC,MAAQ,KAAQ,KAAA,OAAR,EAAU,cAAe,aAAY,MAAA,OAAA,EAAA,GAAA,EAAI,MAEnD,cAAa,SAAC,EAAM,CACV,GAAA,GAAa,GAAgB,SACrC,MAAQ,KAAQ,KAAA,OAAR,EAAU,gBAAiB,eAAe,IAEpD,SAAU,QClBZ,GAAA,IAAA,SAAA,EAAA,CAAoC,GAAA,EAAA,GAOlC,WAAsB,EAAqC,EAAmD,CAA9G,GAAA,GACE,EAAA,KAAA,KAAM,EAAW,IAAK,KADF,SAAA,UAAA,EAAqC,EAAA,KAAA,EAFjD,EAAA,QAAmB,KAMtB,SAAA,UAAA,SAAP,SAAgB,EAAW,EAAiB,CAC1C,GADyB,IAAA,QAAA,GAAA,GACrB,KAAK,OACP,MAAO,MAIT,KAAK,MAAQ,EAEb,GAAM,GAAK,KAAK,GACV,EAAY,KAAK,UAuBvB,MAAI,IAAM,MACR,MAAK,GAAK,KAAK,eAAe,EAAW,EAAI,IAK/C,KAAK,QAAU,GAEf,KAAK,MAAQ,EAEb,KAAK,GAAK,KAAK,IAAM,KAAK,eAAe,EAAW,KAAK,GAAI,GAEtD,MAGC,EAAA,UAAA,eAAV,SAAyB,EAA2B,EAAW,EAAiB,CAAjB,MAAA,KAAA,QAAA,GAAA,GACtD,GAAiB,YAAY,EAAU,MAAM,KAAK,EAAW,MAAO,IAGnE,EAAA,UAAA,eAAV,SAAyB,EAA4B,EAAS,EAAwB,CAEpF,GAF4D,IAAA,QAAA,GAAA,GAExD,GAAS,MAAQ,KAAK,QAAU,GAAS,KAAK,UAAY,GAC5D,MAAO,GAIT,GAAiB,cAAc,IAQ1B,EAAA,UAAA,QAAP,SAAe,EAAU,EAAa,CACpC,GAAI,KAAK,OACP,MAAO,IAAI,OAAM,gCAGnB,KAAK,QAAU,GACf,GAAM,GAAQ,KAAK,SAAS,EAAO,GACnC,GAAI,EACF,MAAO,GACF,AAAI,KAAK,UAAY,IAAS,KAAK,IAAM,MAc9C,MAAK,GAAK,KAAK,eAAe,KAAK,UAAW,KAAK,GAAI,QAIjD,EAAA,UAAA,SAAV,SAAmB,EAAU,EAAc,CACzC,GAAI,GAAmB,GACnB,EACJ,GAAI,CACF,KAAK,KAAK,SACH,EAAP,CACA,EAAU,GAIV,EAAa,GAAQ,GAAI,OAAM,sCAEjC,GAAI,EACF,YAAK,cACE,GAIX,EAAA,UAAA,YAAA,UAAA,CACE,GAAI,CAAC,KAAK,OAAQ,CACV,GAAA,GAAoB,KAAlB,EAAE,EAAA,GAAE,EAAS,EAAA,UACb,EAAY,EAAS,QAE7B,KAAK,KAAO,KAAK,MAAQ,KAAK,UAAY,KAC1C,KAAK,QAAU,GAEf,GAAU,EAAS,MACf,GAAM,MACR,MAAK,GAAK,KAAK,eAAe,EAAW,EAAI,OAG/C,KAAK,MAAQ,KACb,EAAA,UAAM,YAAW,KAAA,QAGvB,GA3IoC,ICiBpC,GAAA,IAAA,UAAA,CAGE,WAAoB,EAAoC,EAAiC,CAAjC,AAAA,IAAA,QAAA,GAAoB,EAAU,KAAlE,KAAA,oBAAA,EAClB,KAAK,IAAM,EA8BN,SAAA,UAAA,SAAP,SAAmB,EAAqD,EAAmB,EAAS,CAA5B,MAAA,KAAA,QAAA,GAAA,GAC/D,GAAI,MAAK,oBAAuB,KAAM,GAAM,SAAS,EAAO,IAlCvD,EAAA,IAAoB,GAAsB,IAoC1D,KCzDA,GAAA,IAAA,SAAA,EAAA,CAAoC,GAAA,EAAA,GAkBlC,WAAY,EAAgC,EAAiC,CAAjC,AAAA,IAAA,QAAA,GAAoB,GAAU,KAA1E,GAAA,GACE,EAAA,KAAA,KAAM,EAAiB,IAAI,KAlBtB,SAAA,QAAmC,GAOnC,EAAA,QAAmB,GAQnB,EAAA,WAAkB,SAMlB,SAAA,UAAA,MAAP,SAAa,EAAwB,CAC3B,GAAA,GAAY,KAAI,QAExB,GAAI,KAAK,QAAS,CAChB,EAAQ,KAAK,GACb,OAGF,GAAI,GACJ,KAAK,QAAU,GAEf,EACE,IAAK,EAAQ,EAAO,QAAQ,EAAO,MAAO,EAAO,OAC/C,YAEM,EAAS,EAAQ,SAI3B,GAFA,KAAK,QAAU,GAEX,EAAO,CACT,KAAQ,EAAS,EAAQ,SACvB,EAAO,cAET,KAAM,KAGZ,GAhDoC,IC8C7B,GAAM,IAAiB,GAAI,IAAe,IAKpC,GAAQ,GClDrB,GAAA,IAAA,SAAA,EAAA,CAA6C,GAAA,EAAA,GAC3C,WAAsB,EAA8C,EAAmD,CAAvH,GAAA,GACE,EAAA,KAAA,KAAM,EAAW,IAAK,KADF,SAAA,UAAA,EAA8C,EAAA,KAAA,IAI1D,SAAA,UAAA,eAAV,SAAyB,EAAoC,EAAU,EAAiB,CAEtF,MAFqE,KAAA,QAAA,GAAA,GAEjE,IAAU,MAAQ,EAAQ,EACrB,EAAA,UAAM,eAAc,KAAA,KAAC,EAAW,EAAI,GAG7C,GAAU,QAAQ,KAAK,MAIhB,EAAU,YAAe,GAAU,WAAa,GAAuB,sBAAsB,UAAA,CAAM,MAAA,GAAU,MAAM,aAElH,EAAA,UAAA,eAAV,SAAyB,EAAoC,EAAU,EAAiB,CAItF,GAJqE,IAAA,QAAA,GAAA,GAIhE,GAAS,MAAQ,EAAQ,GAAO,GAAS,MAAQ,KAAK,MAAQ,EACjE,MAAO,GAAA,UAAM,eAAc,KAAA,KAAC,EAAW,EAAI,GAK7C,AAAK,EAAU,QAAQ,KAAK,SAAC,EAAM,CAAK,MAAA,GAAO,KAAO,KACpD,IAAuB,qBAAqB,GAC5C,EAAU,WAAa,SAK7B,GAlC6C,ICF7C,GAAA,IAAA,SAAA,EAAA,CAA6C,GAAA,EAAA,GAA7C,YAAA,gDACS,SAAA,UAAA,MAAP,SAAa,EAAyB,CACpC,KAAK,QAAU,GAUf,GAAM,GAAU,KAAK,WACrB,KAAK,WAAa,OAEV,GAAA,GAAY,KAAI,QACpB,EACJ,EAAS,GAAU,EAAQ,QAE3B,EACE,IAAK,EAAQ,EAAO,QAAQ,EAAO,MAAO,EAAO,OAC/C,YAEM,GAAS,EAAQ,KAAO,EAAO,KAAO,GAAW,EAAQ,SAInE,GAFA,KAAK,QAAU,GAEX,EAAO,CACT,KAAQ,GAAS,EAAQ,KAAO,EAAO,KAAO,GAAW,EAAQ,SAC/D,EAAO,cAET,KAAM,KAGZ,GAlC6C,ICgCtC,GAAM,IAA0B,GAAI,IAAwB,IC8B5D,GAAM,GAAQ,GAAI,GAAkB,SAAC,EAAU,CAAK,MAAA,GAAW,aC9DhE,YAAsB,EAAU,CACpC,MAAO,IAAS,EAAW,EAAM,UCAnC,YAAiB,EAAQ,CACvB,MAAO,GAAI,EAAI,OAAS,GAGpB,YAA4B,EAAW,CAC3C,MAAO,GAAW,GAAK,IAAS,EAAK,MAAQ,OAGzC,YAAuB,EAAW,CACtC,MAAO,IAAY,GAAK,IAAS,EAAK,MAAQ,OAG1C,YAAoB,EAAa,EAAoB,CACzD,MAAO,OAAO,IAAK,IAAU,SAAW,EAAK,MAAS,ECjBjD,GAAM,IAAe,SAAI,EAAM,CAAwB,MAAA,IAAK,MAAO,GAAE,QAAW,UAAY,MAAO,IAAM,YCM1G,YAAoB,EAAU,CAClC,MAAO,GAAW,GAAK,KAAA,OAAL,EAAO,MCFrB,YAA8B,EAAU,CAC5C,MAAO,GAAW,EAAM,KCJpB,YAA6B,EAAQ,CACzC,MAAO,QAAO,eAAiB,EAAW,GAAG,KAAA,OAAH,EAAM,OAAO,gBCCnD,YAA2C,EAAU,CAEzD,MAAO,IAAI,WACT,gBACE,KAAU,MAAQ,MAAO,IAAU,SAAW,oBAAsB,IAAI,EAAK,KAAG,4HCRhF,aAA2B,CAC/B,MAAI,OAAO,SAAW,YAAc,CAAC,OAAO,SACnC,aAGF,OAAO,SAGT,GAAM,IAAW,KCJlB,YAAqB,EAAU,CACnC,MAAO,GAAW,GAAK,KAAA,OAAL,EAAQ,KCFtB,YAAuD,EAAqC,mGAC1F,EAAS,EAAe,qEAGF,MAAA,CAAA,EAAA,GAAM,EAAO,sBAA/B,GAAkB,EAAA,OAAhB,EAAK,EAAA,MAAE,EAAI,EAAA,KACf,iBAAA,CAAA,EAAA,UACF,MAAA,CAAA,EAAA,EAAA,2BAEI,WAAN,MAAA,CAAA,EAAA,EAAA,eAAA,SAAA,wCAGF,SAAO,yCAIL,YAAkC,EAAQ,CAG9C,MAAO,GAAW,GAAG,KAAA,OAAH,EAAK,WCPnB,WAAuB,EAAyB,CACpD,GAAI,YAAiB,GACnB,MAAO,GAET,GAAI,GAAS,KAAM,CACjB,GAAI,GAAoB,GACtB,MAAO,IAAsB,GAE/B,GAAI,GAAY,GACd,MAAO,IAAc,GAEvB,GAAI,GAAU,GACZ,MAAO,IAAY,GAErB,GAAI,GAAgB,GAClB,MAAO,IAAkB,GAE3B,GAAI,GAAW,GACb,MAAO,IAAa,GAEtB,GAAI,GAAqB,GACvB,MAAO,IAAuB,GAIlC,KAAM,IAAiC,GAOnC,YAAmC,EAAQ,CAC/C,MAAO,IAAI,GAAW,SAAC,EAAyB,CAC9C,GAAM,GAAM,EAAI,MAChB,GAAI,EAAW,EAAI,WACjB,MAAO,GAAI,UAAU,GAGvB,KAAM,IAAI,WAAU,oEAWlB,YAA2B,EAAmB,CAClD,MAAO,IAAI,GAAW,SAAC,EAAyB,CAU9C,OAAS,GAAI,EAAG,EAAI,EAAM,QAAU,CAAC,EAAW,OAAQ,IACtD,EAAW,KAAK,EAAM,IAExB,EAAW,aAIT,YAAyB,EAAuB,CACpD,MAAO,IAAI,GAAW,SAAC,EAAyB,CAC9C,EACG,KACC,SAAC,EAAK,CACJ,AAAK,EAAW,QACd,GAAW,KAAK,GAChB,EAAW,aAGf,SAAC,EAAQ,CAAK,MAAA,GAAW,MAAM,KAEhC,KAAK,KAAM,MAIZ,YAA0B,EAAqB,CACnD,MAAO,IAAI,GAAW,SAAC,EAAyB,aAC9C,OAAoB,GAAA,GAAA,GAAQ,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAAzB,GAAM,GAAK,EAAA,MAEd,GADA,EAAW,KAAK,GACZ,EAAW,OACb,yGAGJ,EAAW,aAIT,YAA+B,EAA+B,CAClE,MAAO,IAAI,GAAW,SAAC,EAAyB,CAC9C,GAAQ,EAAe,GAAY,MAAM,SAAC,EAAG,CAAK,MAAA,GAAW,MAAM,OAIjE,YAAoC,EAAqC,CAC7E,MAAO,IAAkB,GAAmC,IAG9D,YAA0B,EAAiC,EAAyB,uIACxD,EAAA,GAAA,iFAIxB,GAJe,EAAK,EAAA,MACpB,EAAW,KAAK,GAGZ,EAAW,OACb,MAAA,CAAA,8RAGJ,SAAW,oBC/GP,YACJ,EACA,EACA,EACA,EACA,EAAc,CADd,AAAA,IAAA,QAAA,GAAA,GACA,IAAA,QAAA,GAAA,IAEA,GAAM,GAAuB,EAAU,SAAS,UAAA,CAC9C,IACA,AAAI,EACF,EAAmB,IAAI,KAAK,SAAS,KAAM,IAE3C,KAAK,eAEN,GAIH,GAFA,EAAmB,IAAI,GAEnB,CAAC,EAKH,MAAO,GCiBL,YAAuB,EAA0B,EAAS,CAAT,MAAA,KAAA,QAAA,GAAA,GAC9C,EAAQ,SAAC,EAAQ,EAAU,CAChC,EAAO,UACL,EACE,EACA,SAAC,EAAK,CAAK,MAAA,IAAgB,EAAY,EAAW,UAAA,CAAM,MAAA,GAAW,KAAK,IAAQ,IAChF,UAAA,CAAM,MAAA,IAAgB,EAAY,EAAW,UAAA,CAAM,MAAA,GAAW,YAAY,IAC1E,SAAC,EAAG,CAAK,MAAA,IAAgB,EAAY,EAAW,UAAA,CAAM,MAAA,GAAW,MAAM,IAAM,QCH/E,YAAyB,EAA0B,EAAiB,CAAjB,MAAA,KAAA,QAAA,GAAA,GAChD,EAAQ,SAAC,EAAQ,EAAU,CAChC,EAAW,IAAI,EAAU,SAAS,UAAA,CAAM,MAAA,GAAO,UAAU,IAAa,MC3DpE,YAAgC,EAA6B,EAAwB,CACzF,MAAO,GAAU,GAAO,KAAK,GAAY,GAAY,GAAU,ICD3D,YAA6B,EAAuB,EAAwB,CAChF,MAAO,GAAU,GAAO,KAAK,GAAY,GAAY,GAAU,ICH3D,YAA2B,EAAqB,EAAwB,CAC5E,MAAO,IAAI,GAAc,SAAC,EAAU,CAElC,GAAI,GAAI,EAER,MAAO,GAAU,SAAS,UAAA,CACxB,AAAI,IAAM,EAAM,OAGd,EAAW,WAIX,GAAW,KAAK,EAAM,MAIjB,EAAW,QACd,KAAK,gBCVT,YAA8B,EAAoB,EAAwB,CAC9E,MAAO,IAAI,GAAc,SAAC,EAAU,CAClC,GAAI,GAKJ,UAAgB,EAAY,EAAW,UAAA,CAErC,EAAY,EAAc,MAE1B,GACE,EACA,EACA,UAAA,OACM,EACA,EACJ,GAAI,CAEF,AAAC,EAAkB,EAAS,OAAzB,EAAK,EAAA,MAAE,EAAI,EAAA,WACP,EAAP,CAEA,EAAW,MAAM,GACjB,OAGF,AAAI,EAKF,EAAW,WAGX,EAAW,KAAK,IAGpB,EACA,MAQG,UAAA,CAAM,MAAA,GAAW,GAAQ,KAAA,OAAR,EAAU,SAAW,EAAS,YCrDpD,YAAmC,EAAyB,EAAwB,CACxF,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,2BAElB,MAAO,IAAI,GAAc,SAAC,EAAU,CAClC,GAAgB,EAAY,EAAW,UAAA,CACrC,GAAM,GAAW,EAAM,OAAO,iBAC9B,GACE,EACA,EACA,UAAA,CACE,EAAS,OAAO,KAAK,SAAC,EAAM,CAC1B,AAAI,EAAO,KAGT,EAAW,WAEX,EAAW,KAAK,EAAO,UAI7B,EACA,QCrBF,YAAwC,EAA8B,EAAwB,CAClG,MAAO,IAAsB,GAAmC,GAAQ,GCqBpE,YAAuB,EAA2B,EAAwB,CAC9E,GAAI,GAAS,KAAM,CACjB,GAAI,GAAoB,GACtB,MAAO,IAAmB,EAAO,GAEnC,GAAI,GAAY,GACd,MAAO,IAAc,EAAO,GAE9B,GAAI,GAAU,GACZ,MAAO,IAAgB,EAAO,GAEhC,GAAI,GAAgB,GAClB,MAAO,IAAsB,EAAO,GAEtC,GAAI,GAAW,GACb,MAAO,IAAiB,EAAO,GAEjC,GAAI,GAAqB,GACvB,MAAO,IAA2B,EAAO,GAG7C,KAAM,IAAiC,GCqDnC,YAAkB,EAA2B,EAAyB,CAC1E,MAAO,GAAY,GAAU,EAAO,GAAa,EAAU,GCvBvD,YAAY,QAAI,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACpB,GAAM,GAAY,GAAa,GAC/B,MAAO,IAAK,EAAa,GCuCrB,YAAqB,EAA0B,EAAyB,CAC5E,GAAM,GAAe,EAAW,GAAuB,EAAsB,UAAA,CAAM,MAAA,IAC7E,EAAO,SAAC,EAA6B,CAAK,MAAA,GAAW,MAAM,MACjE,MAAO,IAAI,GAAW,EAAY,SAAC,EAAU,CAAK,MAAA,GAAU,SAAS,EAAa,EAAG,IAAc,GCpH/F,YAAsB,EAAU,CACpC,MAAO,aAAiB,OAAQ,CAAC,MAAM,GCuCnC,WAAoB,EAAyC,EAAa,CAC9E,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAEhC,GAAI,GAAQ,EAGZ,EAAO,UACL,EAAyB,EAAY,SAAC,EAAQ,CAG5C,EAAW,KAAK,EAAQ,KAAK,EAAS,EAAO,WCtD7C,GAAA,IAAY,MAAK,QAEzB,YAA2B,EAA6B,EAAW,CAC/D,MAAO,IAAQ,GAAQ,EAAE,MAAA,OAAA,EAAA,GAAA,EAAI,KAAQ,EAAG,GAOtC,YAAiC,EAA2B,CAC9D,MAAO,GAAI,SAAA,EAAI,CAAI,MAAA,IAAY,EAAI,KCd/B,GAAA,IAAY,MAAK,QACjB,GAA0D,OAAM,eAArC,GAA+B,OAAM,UAAlB,GAAY,OAAM,KAQlE,YAA+D,EAAuB,CAC1F,GAAI,EAAK,SAAW,EAAG,CACrB,GAAM,GAAQ,EAAK,GACnB,GAAI,GAAQ,GACV,MAAO,CAAE,KAAM,EAAO,KAAM,MAE9B,GAAI,GAAO,GAAQ,CACjB,GAAM,GAAO,GAAQ,GACrB,MAAO,CACL,KAAM,EAAK,IAAI,SAAC,EAAG,CAAK,MAAA,GAAM,KAC9B,KAAI,IAKV,MAAO,CAAE,KAAM,EAAa,KAAM,MAGpC,YAAgB,EAAQ,CACtB,MAAO,IAAO,MAAO,IAAQ,UAAY,GAAe,KAAS,GC5B7D,YAAuB,EAAgB,EAAa,CACxD,MAAO,GAAK,OAAO,SAAC,EAAQ,EAAK,EAAC,CAAK,MAAE,GAAO,GAAO,EAAO,GAAK,GAAS,ICuMxE,YAAuB,QAAoC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAC/D,GAAM,GAAY,GAAa,GACzB,EAAiB,GAAkB,GAEnC,EAA8B,GAAqB,GAA3C,EAAW,EAAA,KAAE,EAAI,EAAA,KAE/B,GAAI,EAAY,SAAW,EAIzB,MAAO,IAAK,GAAI,GAGlB,GAAM,GAAS,GAAI,GACjB,GACE,EACA,EACA,EAEI,SAAC,EAAM,CAAK,MAAA,IAAa,EAAM,IAE/B,KAIR,MAAO,GAAkB,EAAO,KAAK,GAAiB,IAAqC,EAGvF,YACJ,EACA,EACA,EAAiD,CAAjD,MAAA,KAAA,QAAA,GAAA,IAEO,SAAC,EAA2B,CAGjC,GACE,EACA,UAAA,CAaE,OAZQ,GAAW,EAAW,OAExB,EAAS,GAAI,OAAM,GAGrB,EAAS,EAIT,EAAuB,aAGlB,EAAC,CACR,GACE,EACA,UAAA,CACE,GAAM,GAAS,GAAK,EAAY,GAAI,GAChC,EAAgB,GACpB,EAAO,UACL,EACE,EACA,SAAC,EAAK,CAEJ,EAAO,GAAK,EACP,GAEH,GAAgB,GAChB,KAEG,GAGH,EAAW,KAAK,EAAe,EAAO,WAG1C,UAAA,CACE,AAAK,EAAE,GAGL,EAAW,eAMrB,IAjCK,EAAI,EAAG,EAAI,EAAQ,MAAnB,IAqCX,IASN,YAAuB,EAAsC,EAAqB,EAA0B,CAC1G,AAAI,EACF,GAAgB,EAAc,EAAW,GAEzC,ICzRE,YACJ,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EAA+B,CAG/B,GAAM,GAAc,GAEhB,EAAS,EAET,EAAQ,EAER,EAAa,GAKX,EAAgB,UAAA,CAIpB,AAAI,GAAc,CAAC,EAAO,QAAU,CAAC,GACnC,EAAW,YAKT,EAAY,SAAC,EAAQ,CAAK,MAAC,GAAS,EAAa,EAAW,GAAS,EAAO,KAAK,IAEjF,EAAa,SAAC,EAAQ,CAI1B,GAAU,EAAW,KAAK,GAI1B,IAKA,GAAI,GAAgB,GAGpB,EAAU,EAAQ,EAAO,MAAU,UACjC,EACE,EACA,SAAC,EAAU,CAGT,GAAY,MAAZ,EAAe,GAEf,AAAI,EAGF,EAAU,GAGV,EAAW,KAAK,IAGpB,UAAA,CAGE,EAAgB,IAGlB,OACA,UAAA,CAIE,GAAI,EAKF,GAAI,CAIF,IAKA,qBACE,GAAM,GAAgB,EAAO,QAI7B,AAAI,EACF,GAAgB,EAAY,EAAmB,UAAA,CAAM,MAAA,GAAW,KAEhE,EAAW,IARR,EAAO,QAAU,EAAS,OAYjC,UACO,EAAP,CACA,EAAW,MAAM,QAS7B,SAAO,UACL,EAAyB,EAAY,EAAW,UAAA,CAE9C,EAAa,GACb,OAMG,UAAA,CACL,GAAkB,MAAlB,KChEE,YACJ,EACA,EACA,EAA6B,CAE7B,MAFA,KAAA,QAAA,GAAA,KAEI,EAAW,GAEN,GAAS,SAAC,EAAG,EAAC,CAAK,MAAA,GAAI,SAAC,EAAQ,EAAU,CAAK,MAAA,GAAe,EAAG,EAAG,EAAG,KAAK,EAAU,EAAQ,EAAG,MAAM,GACrG,OAAO,IAAmB,UACnC,GAAa,GAGR,EAAQ,SAAC,EAAQ,EAAU,CAAK,MAAA,IAAe,EAAQ,EAAY,EAAS,MC/B/E,YAAmD,EAA6B,CAA7B,MAAA,KAAA,QAAA,GAAA,KAChD,GAAS,GAAU,GCLtB,aAAmB,CACvB,MAAO,IAAS,GCoDZ,aAAgB,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACrB,MAAO,MAAY,GAAK,EAAM,GAAa,KC7DvC,WAAgD,EAA0B,CAC9E,MAAO,IAAI,GAA+B,SAAC,EAAU,CACnD,EAAU,KAAqB,UAAU,KC9C7C,GAAM,IAA0B,CAAC,cAAe,kBAC1C,GAAqB,CAAC,mBAAoB,uBAC1C,GAAgB,CAAC,KAAM,OA8NvB,WACJ,EACA,EACA,EACA,EAAsC,CAMtC,GAJI,EAAW,IACb,GAAiB,EACjB,EAAU,QAER,EACF,MAAO,GAAa,EAAQ,EAAW,GAAiC,KAAK,GAAiB,IAU1F,GAAA,GAAA,EAEJ,GAAc,GACV,GAAmB,IAAI,SAAC,EAAU,CAAK,MAAA,UAAC,EAAY,CAAK,MAAA,GAAO,GAAY,EAAW,EAAS,MAElG,GAAwB,GACtB,GAAwB,IAAI,GAAwB,EAAQ,IAC5D,GAA0B,GAC1B,GAAc,IAAI,GAAwB,EAAQ,IAClD,GAAE,GATD,EAAG,EAAA,GAAE,EAAM,EAAA,GAgBlB,GAAI,CAAC,GACC,GAAY,GACd,MAAO,IAAS,SAAC,EAAc,CAAK,MAAA,GAAU,EAAW,EAAW,KAClE,EAAU,IAOhB,GAAI,CAAC,EACH,KAAM,IAAI,WAAU,wBAGtB,MAAO,IAAI,GAAc,SAAC,EAAU,CAIlC,GAAM,GAAU,UAAA,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAAmB,MAAA,GAAW,KAAK,EAAI,EAAK,OAAS,EAAO,EAAK,KAElF,SAAI,GAEG,UAAA,CAAM,MAAA,GAAQ,MAWzB,YAAiC,EAAa,EAAiB,CAC7D,MAAO,UAAC,EAAkB,CAAK,MAAA,UAAC,EAAY,CAAK,MAAA,GAAO,GAAY,EAAW,KAQjF,YAAiC,EAAW,CAC1C,MAAO,GAAW,EAAO,cAAgB,EAAW,EAAO,gBAQ7D,YAAmC,EAAW,CAC5C,MAAO,GAAW,EAAO,KAAO,EAAW,EAAO,KAQpD,YAAuB,EAAW,CAChC,MAAO,GAAW,EAAO,mBAAqB,EAAW,EAAO,qBC9L5D,YACJ,EACA,EACA,EAAsC,CAEtC,MAAI,GACK,GAAoB,EAAY,GAAe,KAAK,GAAiB,IAGvE,GAAI,GAAoB,SAAC,EAAU,CACxC,GAAM,GAAU,UAAA,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAAc,MAAA,GAAW,KAAK,EAAE,SAAW,EAAI,EAAE,GAAK,IACjE,EAAW,EAAW,GAC5B,MAAO,GAAW,GAAiB,UAAA,CAAM,MAAA,GAAc,EAAS,IAAY,SCpB1E,YACJ,EACA,EACA,EAAyC,CAFzC,AAAA,IAAA,QAAA,GAAA,GAEA,IAAA,QAAA,GAAA,IAIA,GAAI,GAAmB,GAEvB,MAAI,IAAuB,MAIzB,CAAI,GAAY,GACd,EAAY,EAIZ,EAAmB,GAIhB,GAAI,GAAW,SAAC,EAAU,CAI/B,GAAI,GAAM,GAAY,GAAW,CAAC,EAAU,EAAW,MAAQ,EAE/D,AAAI,EAAM,GAER,GAAM,GAIR,GAAI,GAAI,EAGR,MAAO,GAAU,SAAS,UAAA,CACxB,AAAK,EAAW,QAEd,GAAW,KAAK,KAEhB,AAAI,GAAK,EAGP,KAAK,SAAS,OAAW,GAGzB,EAAW,aAGd,KC9FD,YAAe,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACpB,GAAM,GAAY,GAAa,GACzB,EAAa,GAAU,EAAM,KAC7B,EAAU,EAChB,MAAO,AAAC,GAAQ,OAGZ,EAAQ,SAAW,EAEnB,EAAU,EAAQ,IAElB,GAAS,GAAY,GAAK,EAAS,IALnC,EC3DC,GAAM,IAAQ,GAAI,GAAkB,ICpCnC,GAAA,IAAY,MAAK,QAMnB,YAA4B,EAAiB,CACjD,MAAO,GAAK,SAAW,GAAK,GAAQ,EAAK,IAAM,EAAK,GAAM,ECqDtD,WAAoB,EAAiD,EAAa,CACtF,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAEhC,GAAI,GAAQ,EAIZ,EAAO,UAIL,EAAyB,EAAY,SAAC,EAAK,CAAK,MAAA,GAAU,KAAK,EAAS,EAAO,MAAY,EAAW,KAAK,QCrB3G,aAAa,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAClB,GAAM,GAAiB,GAAkB,GAEnC,EAAU,GAAe,GAE/B,MAAO,GAAQ,OACX,GAAI,GAAsB,SAAC,EAAU,CAGnC,GAAI,GAAuB,EAAQ,IAAI,UAAA,CAAM,MAAA,KAKzC,EAAY,EAAQ,IAAI,UAAA,CAAM,MAAA,KAGlC,EAAW,IAAI,UAAA,CACb,EAAU,EAAY,OAMxB,mBAAS,EAAW,CAClB,EAAU,EAAQ,IAAc,UAC9B,EACE,EACA,SAAC,EAAK,CAKJ,GAJA,EAAQ,GAAa,KAAK,GAItB,EAAQ,MAAM,SAAC,EAAM,CAAK,MAAA,GAAO,SAAS,CAC5C,GAAM,GAAc,EAAQ,IAAI,SAAC,EAAM,CAAK,MAAA,GAAO,UAEnD,EAAW,KAAK,EAAiB,EAAc,MAAA,OAAA,EAAA,GAAA,EAAI,KAAU,GAIzD,EAAQ,KAAK,SAAC,EAAQ,EAAC,CAAK,MAAA,CAAC,EAAO,QAAU,EAAU,MAC1D,EAAW,aAIjB,UAAA,CAGE,EAAU,GAAe,GAIzB,CAAC,EAAQ,GAAa,QAAU,EAAW,eA5B1C,EAAc,EAAG,CAAC,EAAW,QAAU,EAAc,EAAQ,OAAQ,MAArE,GAmCT,MAAO,WAAA,CACL,EAAU,EAAY,QAG1B,EC7DA,YAAmB,EAAoD,CAC3E,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAW,GACX,EAAsB,KACtB,EAA6C,KAC7C,EAAa,GAEX,EAAc,UAAA,CAGlB,GAFA,GAAkB,MAAlB,EAAoB,cACpB,EAAqB,KACjB,EAAU,CACZ,EAAW,GACX,GAAM,GAAQ,EACd,EAAY,KACZ,EAAW,KAAK,GAElB,GAAc,EAAW,YAGrB,EAAkB,UAAA,CACtB,EAAqB,KACrB,GAAc,EAAW,YAG3B,EAAO,UACL,EACE,EACA,SAAC,EAAK,CACJ,EAAW,GACX,EAAY,EACP,GACH,EAAU,EAAiB,IAAQ,UAChC,EAAqB,EAAyB,EAAY,EAAa,KAI9E,UAAA,CACE,EAAa,GACZ,EAAC,GAAY,CAAC,GAAsB,EAAmB,SAAW,EAAW,gBCtClF,YAAuB,EAAkB,EAAyC,CAAzC,MAAA,KAAA,QAAA,GAAA,IACtC,GAAM,UAAA,CAAM,MAAA,IAAM,EAAU,KCG/B,YAAyB,EAAoB,EAAsC,CAAtC,MAAA,KAAA,QAAA,GAAA,MAGjD,EAAmB,GAAgB,KAAhB,EAAoB,EAEhC,EAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAiB,GACjB,EAAQ,EAEZ,EAAO,UACL,EACE,EACA,SAAC,EAAK,aACA,EAAuB,KAK3B,AAAI,IAAU,IAAsB,GAClC,EAAQ,KAAK,QAIf,OAAqB,GAAA,GAAA,GAAO,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAAzB,GAAM,GAAM,EAAA,MACf,EAAO,KAAK,GAMR,GAAc,EAAO,QACvB,GAAS,GAAM,KAAN,EAAU,GACnB,EAAO,KAAK,sGAIhB,GAAI,MAIF,OAAqB,GAAA,GAAA,GAAM,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAAxB,GAAM,GAAM,EAAA,MACf,GAAU,EAAS,GACnB,EAAW,KAAK,uGAItB,UAAA,aAGE,OAAqB,GAAA,GAAA,GAAO,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAAzB,GAAM,GAAM,EAAA,MACf,EAAW,KAAK,qGAElB,EAAW,YAGb,OACA,UAAA,CAEE,EAAU,UCRd,YACJ,EAAgD,CAEhD,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAgC,KAChC,EAAY,GACZ,EAEJ,EAAW,EAAO,UAChB,EAAyB,EAAY,OAAW,OAAW,SAAC,EAAG,CAC7D,EAAgB,EAAU,EAAS,EAAK,GAAW,GAAU,KAC7D,AAAI,EACF,GAAS,cACT,EAAW,KACX,EAAc,UAAU,IAIxB,EAAY,MAKd,GAMF,GAAS,cACT,EAAW,KACX,EAAe,UAAU,MC5HzB,YACJ,EACA,EACA,EACA,EACA,EAAqC,CAErC,MAAO,UAAC,EAAuB,EAA2B,CAIxD,GAAI,GAAW,EAIX,EAAa,EAEb,EAAQ,EAGZ,EAAO,UACL,EACE,EACA,SAAC,EAAK,CAEJ,GAAM,GAAI,IAEV,EAAQ,EAEJ,EAAY,EAAO,EAAO,GAIxB,GAAW,GAAO,GAGxB,GAAc,EAAW,KAAK,IAIhC,GACG,UAAA,CACC,GAAY,EAAW,KAAK,GAC5B,EAAW,eC9BjB,aAAuB,QAAO,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAClC,GAAM,GAAiB,GAAkB,GACzC,MAAO,GACH,GAAK,GAAa,MAAA,OAAA,EAAA,GAAA,EAAK,KAAuC,GAAiB,IAC/E,EAAQ,SAAC,EAAQ,EAAU,CACzB,GAAiB,EAAA,CAAE,GAAM,EAAK,GAAe,MAAQ,KCYvD,aAA2B,QAC/B,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAEA,MAAO,IAAa,MAAA,OAAA,EAAA,GAAA,EAAI,KCgCpB,YACJ,EACA,EAA6G,CAE7G,MAAO,GAAW,GAAkB,GAAS,EAAS,EAAgB,GAAK,GAAS,EAAS,GCnBzF,YAA0B,EAAiB,EAAyC,CAAzC,MAAA,KAAA,QAAA,GAAA,IACxC,EAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAkC,KAClC,EAAsB,KACtB,EAA0B,KAExB,EAAO,UAAA,CACX,GAAI,EAAY,CAEd,EAAW,cACX,EAAa,KACb,GAAM,GAAQ,EACd,EAAY,KACZ,EAAW,KAAK,KAGpB,YAAqB,CAInB,GAAM,GAAa,EAAY,EACzB,EAAM,EAAU,MACtB,GAAI,EAAM,EAAY,CAEpB,EAAa,KAAK,SAAS,OAAW,EAAa,GACnD,EAAW,IAAI,GACf,OAGF,IAGF,EAAO,UACL,EACE,EACA,SAAC,EAAQ,CACP,EAAY,EACZ,EAAW,EAAU,MAGhB,GACH,GAAa,EAAU,SAAS,EAAc,GAC9C,EAAW,IAAI,KAGnB,UAAA,CAGE,IACA,EAAW,YAGb,OACA,UAAA,CAEE,EAAY,EAAa,UC/E7B,YAA+B,EAAe,CAClD,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAW,GACf,EAAO,UACL,EACE,EACA,SAAC,EAAK,CACJ,EAAW,GACX,EAAW,KAAK,IAElB,UAAA,CACE,AAAK,GACH,EAAW,KAAK,GAElB,EAAW,gBCNf,YAAkB,EAAa,CACnC,MAAO,IAAS,EAEZ,UAAA,CAAM,MAAA,IACN,EAAQ,SAAC,EAAQ,EAAU,CACzB,GAAI,GAAO,EACX,EAAO,UACL,EAAyB,EAAY,SAAC,EAAK,CAIzC,AAAI,EAAE,GAAQ,GACZ,GAAW,KAAK,GAIZ,GAAS,GACX,EAAW,iBCxBrB,aAAwB,CAC5B,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,EAAO,UAAU,EAAyB,EAAY,OCHpD,WAAmB,EAAQ,CAC/B,MAAO,GAAI,UAAA,CAAM,MAAA,KCkCb,YACJ,EACA,EAAmC,CAEnC,MAAI,GAEK,SAAC,EAAqB,CAC3B,MAAA,IAAO,EAAkB,KAAK,GAAK,GAAI,MAAmB,EAAO,KAAK,GAAU,MAG7E,GAAS,SAAC,EAAO,EAAK,CAAK,MAAA,GAAsB,EAAO,GAAO,KAAK,GAAK,GAAI,EAAM,MCvBtF,YAAmB,EAAoB,EAAyC,CAAzC,AAAA,IAAA,QAAA,GAAA,IAC3C,GAAM,GAAW,GAAM,EAAK,GAC5B,MAAO,IAAU,UAAA,CAAM,MAAA,KC6EnB,WACJ,EACA,EAA0D,CAA1D,MAAA,KAAA,QAAA,GAA+B,IAK/B,EAAa,GAAU,KAAV,EAAc,GAEpB,EAAQ,SAAC,EAAQ,EAAU,CAGhC,GAAI,GAEA,EAAQ,GAEZ,EAAO,UACL,EAAyB,EAAY,SAAC,EAAK,CAEzC,GAAM,GAAa,EAAY,GAK/B,AAAI,IAAS,CAAC,EAAY,EAAa,KAMrC,GAAQ,GACR,EAAc,EAGd,EAAW,KAAK,SAO1B,YAAwB,EAAQ,EAAM,CACpC,MAAO,KAAM,EClHT,WAAwD,EAAQ,EAAuC,CAC3G,MAAO,GAAqB,SAAC,EAAM,EAAI,CAAK,MAAA,GAAU,EAAQ,EAAE,GAAM,EAAE,IAAQ,EAAE,KAAS,EAAE,KCJzF,aAAiB,QAAI,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACzB,MAAO,UAAC,EAAqB,CAAK,MAAA,IAAO,EAAQ,EAAE,MAAA,OAAA,EAAA,GAAA,EAAI,OCFnD,WAAsB,EAAoB,CAC9C,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAGhC,GAAI,CACF,EAAO,UAAU,WAEjB,EAAW,IAAI,MC3Bf,YAAsB,EAAa,CACvC,MAAO,IAAS,EACZ,UAAA,CAAM,MAAA,IACN,EAAQ,SAAC,EAAQ,EAAU,CAKzB,GAAI,GAAc,GAClB,EAAO,UACL,EACE,EACA,SAAC,EAAK,CAEJ,EAAO,KAAK,GAGZ,EAAQ,EAAO,QAAU,EAAO,SAElC,UAAA,aAGE,OAAoB,GAAA,GAAA,GAAM,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAAvB,GAAM,GAAK,EAAA,MACd,EAAW,KAAK,qGAElB,EAAW,YAGb,OACA,UAAA,CAEE,EAAS,UCrDjB,aAAe,QAAI,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACvB,GAAM,GAAY,GAAa,GACzB,EAAa,GAAU,EAAM,KACnC,SAAO,GAAe,GAEf,EAAQ,SAAC,EAAQ,EAAU,CAChC,GAAS,GAAY,GAAI,EAAA,CAAE,GAAM,EAAM,IAAgC,IAAY,UAAU,KCgB3F,aAAmB,QACvB,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAEA,MAAO,IAAK,MAAA,OAAA,EAAA,GAAA,EAAI,KCoEZ,YAAoB,EAAqC,OACzD,EAAQ,IACR,EAEJ,MAAI,IAAiB,MACnB,CAAI,MAAO,IAAkB,SACxB,GAA4B,EAAa,MAAzC,EAAK,IAAA,OAAG,IAAQ,EAAE,EAAU,EAAa,OAE5C,EAAQ,GAIL,GAAS,EACZ,UAAA,CAAM,MAAA,IACN,EAAQ,SAAC,EAAQ,EAAU,CACzB,GAAI,GAAQ,EACR,EAEE,EAAc,UAAA,CAGlB,GAFA,GAAS,MAAT,EAAW,cACX,EAAY,KACR,GAAS,KAAM,CACjB,GAAM,GAAW,MAAO,IAAU,SAAW,GAAM,GAAS,EAAU,EAAM,IACtE,EAAqB,EAAyB,EAAY,UAAA,CAC9D,EAAmB,cACnB,MAEF,EAAS,UAAU,OAEnB,MAIE,EAAoB,UAAA,CACxB,GAAI,GAAY,GAChB,EAAY,EAAO,UACjB,EAAyB,EAAY,OAAW,UAAA,CAC9C,AAAI,EAAE,EAAQ,EACZ,AAAI,EACF,IAEA,EAAY,GAGd,EAAW,cAKb,GACF,KAIJ,MC3HF,YAAoB,EAAyB,CACjD,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAW,GACX,EAAsB,KAC1B,EAAO,UACL,EAAyB,EAAY,SAAC,EAAK,CACzC,EAAW,GACX,EAAY,KAGhB,EAAS,UACP,EACE,EACA,UAAA,CACE,GAAI,EAAU,CACZ,EAAW,GACX,GAAM,GAAQ,EACd,EAAY,KACZ,EAAW,KAAK,KAGpB,OCoBF,YAAwB,EAA6D,EAAQ,CAMjG,MAAO,GAAQ,GAAc,EAAa,EAAW,UAAU,QAAU,EAAG,KCkDxE,YAAmB,EAA4B,CAA5B,AAAA,IAAA,QAAA,GAAA,IACf,GAAA,GAAgH,EAAO,UAAvH,EAAS,IAAA,OAAG,UAAA,CAAM,MAAA,IAAI,IAAY,EAAE,EAA4E,EAAO,aAAnF,EAAY,IAAA,OAAG,GAAI,EAAE,EAAuD,EAAO,gBAA9D,EAAe,IAAA,OAAG,GAAI,EAAE,EAA+B,EAAO,oBAAtC,EAAmB,IAAA,OAAG,GAAI,EAUnH,MAAO,UAAC,EAAa,CACnB,GAAI,GAAuC,KACvC,EAAuC,KACvC,EAAiC,KACjC,EAAW,EACX,EAAe,GACf,EAAa,GAEX,EAAc,UAAA,CAClB,GAAe,MAAf,EAAiB,cACjB,EAAkB,MAId,EAAQ,UAAA,CACZ,IACA,EAAa,EAAU,KACvB,EAAe,EAAa,IAExB,EAAsB,UAAA,CAG1B,GAAM,GAAO,EACb,IACA,GAAI,MAAJ,EAAM,eAGR,MAAO,GAAc,SAAC,EAAQ,GAAU,CACtC,IACI,CAAC,GAAc,CAAC,GAClB,IAOF,GAAM,IAAQ,EAAU,GAAO,KAAP,EAAW,IAOnC,GAAW,IAAI,UAAA,CACb,IAKI,IAAa,GAAK,CAAC,GAAc,CAAC,GACpC,GAAkB,GAAY,EAAqB,MAMvD,GAAK,UAAU,IAEV,GAMH,GAAa,GAAI,IAAe,CAC9B,KAAM,SAAC,GAAK,CAAK,MAAA,IAAK,KAAK,KAC3B,MAAO,SAAC,GAAG,CACT,EAAa,GACb,IACA,EAAkB,GAAY,EAAO,EAAc,IACnD,GAAK,MAAM,KAEb,SAAU,UAAA,CACR,EAAe,GACf,IACA,EAAkB,GAAY,EAAO,GACrC,GAAK,cAGT,GAAK,GAAQ,UAAU,MAExB,IAIP,YACE,EACA,EAA+C,QAC/C,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,EAAA,GAAA,UAAA,GAEA,MAAI,KAAO,GACT,KAEO,MAGL,IAAO,GACF,KAGF,EAAE,MAAA,OAAA,EAAA,GAAA,EAAI,KACV,KAAK,GAAK,IACV,UAAU,UAAA,CAAM,MAAA,OCxGf,WACJ,EACA,EACA,EAAyB,SAErB,EACA,EAAW,GACf,MAAI,IAAsB,MAAO,IAAuB,SACtD,GAAa,GAAA,EAAmB,cAAU,MAAA,IAAA,OAAA,EAAI,IAC9C,EAAa,GAAA,EAAmB,cAAU,MAAA,IAAA,OAAA,EAAI,IAC9C,EAAW,CAAC,CAAC,EAAmB,SAChC,EAAY,EAAmB,WAE/B,EAAa,GAAkB,KAAlB,EAAsB,IAE9B,GAAS,CACd,UAAW,UAAA,CAAM,MAAA,IAAI,IAAc,EAAY,EAAY,IAC3D,aAAc,GACd,gBAAiB,GACjB,oBAAqB,ICxInB,YAAkB,EAAa,CACnC,MAAO,GAAO,SAAC,EAAG,EAAK,CAAK,MAAA,IAAS,ICYjC,YAAuB,EAAyB,CACpD,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAS,GAEP,EAAiB,EACrB,EACA,UAAA,CACE,GAAc,MAAd,EAAgB,cAChB,EAAS,IAEX,IAGF,EAAU,GAAU,UAAU,GAE9B,EAAO,UAAU,EAAyB,EAAY,SAAC,EAAK,CAAK,MAAA,IAAU,EAAW,KAAK,QCNzF,YAAmB,QAAO,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAC9B,GAAM,GAAY,GAAa,GAC/B,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAIhC,AAAC,GAAY,GAAO,EAAQ,EAAQ,GAAa,GAAO,EAAQ,IAAS,UAAU,KCqBjF,WACJ,EACA,EAA6G,CAE7G,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAyD,KACzD,EAAQ,EAER,EAAa,GAIX,EAAgB,UAAA,CAAM,MAAA,IAAc,CAAC,GAAmB,EAAW,YAEzE,EAAO,UACL,EACE,EACA,SAAC,EAAK,CAEJ,GAAe,MAAf,EAAiB,cACjB,GAAI,GAAa,EACX,EAAa,IAEnB,EAAU,EAAQ,EAAO,IAAa,UACnC,EAAkB,EACjB,EAIA,SAAC,EAAU,CAAK,MAAA,GAAW,KAAK,EAAiB,EAAe,EAAO,EAAY,EAAY,KAAgB,IAC/G,UAAA,CAIE,EAAkB,KAClB,QAKR,UAAA,CACE,EAAa,GACb,SCrEJ,YACJ,EACA,EAA6G,CAE7G,MAAO,GAAW,GAAkB,EAAU,UAAA,CAAM,MAAA,IAAiB,GAAkB,EAAU,UAAA,CAAM,MAAA,KCjBnG,YAAuB,EAA8B,CACzD,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,EAAU,GAAU,UAAU,EAAyB,EAAY,UAAA,CAAM,MAAA,GAAW,YAAY,KAChG,CAAC,EAAW,QAAU,EAAO,UAAU,KCMrC,YAAuB,EAAiD,EAAiB,CAAjB,MAAA,KAAA,QAAA,GAAA,IACrE,EAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAQ,EACZ,EAAO,UACL,EAAyB,EAAY,SAAC,EAAK,CACzC,GAAM,GAAS,EAAU,EAAO,KAChC,AAAC,IAAU,IAAc,EAAW,KAAK,GACzC,CAAC,GAAU,EAAW,gBC6CxB,WACJ,EACA,EACA,EAA8B,CAK9B,GAAM,GACJ,EAAW,IAAmB,GAAS,EAElC,CAAE,KAAM,EAA2E,MAAK,EAAE,SAAQ,GACnG,EAEN,MAAO,GACH,EAAQ,SAAC,EAAQ,EAAU,OACzB,AAAA,GAAA,EAAY,aAAS,MAAA,IAAA,QAAA,EAAA,KAArB,GACA,GAAI,GAAU,GACd,EAAO,UACL,EACE,EACA,SAAC,EAAK,OACJ,AAAA,GAAA,EAAY,QAAI,MAAA,IAAA,QAAA,EAAA,KAAhB,EAAmB,GACnB,EAAW,KAAK,IAElB,UAAA,OACE,EAAU,GACV,GAAA,EAAY,YAAQ,MAAA,IAAA,QAAA,EAAA,KAApB,GACA,EAAW,YAEb,SAAC,EAAG,OACF,EAAU,GACV,GAAA,EAAY,SAAK,MAAA,IAAA,QAAA,EAAA,KAAjB,EAAoB,GACpB,EAAW,MAAM,IAEnB,UAAA,SACE,AAAI,GACF,IAAA,EAAY,eAAW,MAAA,IAAA,QAAA,EAAA,KAAvB,IAEF,GAAA,EAAY,YAAQ,MAAA,IAAA,QAAA,EAAA,KAApB,QAQR,GC7IC,GAAM,IAAwC,CACnD,QAAS,GACT,SAAU,IAiDN,YACJ,EACA,EAA8C,CAA9C,MAAA,KAAA,QAAA,GAAA,IAEO,EAAQ,SAAC,EAAQ,EAAU,CACxB,GAAA,GAAsB,EAAM,QAAnB,EAAa,EAAM,SAChC,EAAW,GACX,EAAsB,KACtB,EAAiC,KACjC,EAAa,GAEX,EAAgB,UAAA,CACpB,GAAS,MAAT,EAAW,cACX,EAAY,KACR,GACF,KACA,GAAc,EAAW,aAIvB,EAAoB,UAAA,CACxB,EAAY,KACZ,GAAc,EAAW,YAGrB,EAAgB,SAAC,EAAQ,CAC7B,MAAC,GAAY,EAAU,EAAiB,IAAQ,UAAU,EAAyB,EAAY,EAAe,KAE1G,EAAO,UAAA,CACX,GAAI,EAAU,CAIZ,EAAW,GACX,GAAM,GAAQ,EACd,EAAY,KAEZ,EAAW,KAAK,GAChB,CAAC,GAAc,EAAc,KAIjC,EAAO,UACL,EACE,EAMA,SAAC,EAAK,CACJ,EAAW,GACX,EAAY,EACZ,CAAE,IAAa,CAAC,EAAU,SAAY,GAAU,IAAS,EAAc,KAEzE,UAAA,CACE,EAAa,GACb,CAAE,IAAY,GAAY,GAAa,CAAC,EAAU,SAAW,EAAW,gBClE5E,YACJ,EACA,EACA,EAA8B,CAD9B,AAAA,IAAA,QAAA,GAAA,IACA,IAAA,QAAA,GAAA,IAEA,GAAM,GAAY,GAAM,EAAU,GAClC,MAAO,IAAS,UAAA,CAAM,MAAA,IAAW,GCH7B,aAAwB,QAAO,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACnC,GAAM,GAAU,GAAkB,GAElC,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAehC,OAdM,GAAM,EAAO,OACb,EAAc,GAAI,OAAM,GAI1B,EAAW,EAAO,IAAI,UAAA,CAAM,MAAA,KAG5B,EAAQ,cAMH,EAAC,CACR,EAAU,EAAO,IAAI,UACnB,EACE,EACA,SAAC,EAAK,CACJ,EAAY,GAAK,EACb,CAAC,GAAS,CAAC,EAAS,IAEtB,GAAS,GAAK,GAKb,GAAQ,EAAS,MAAM,MAAe,GAAW,QAKtD,MAlBG,EAAI,EAAG,EAAI,EAAK,MAAhB,GAwBT,EAAO,UACL,EAAyB,EAAY,SAAC,EAAK,CACzC,GAAI,EAAO,CAET,GAAM,GAAM,EAAA,CAAI,GAAK,EAAK,IAC1B,EAAW,KAAK,EAAU,EAAO,MAAA,OAAA,EAAA,GAAA,EAAI,KAAU,SCnFnD,aAAa,QAAO,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACxB,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,GAAS,MAAA,OAAA,EAAA,CAAC,GAA8B,EAAM,KAAyC,UAAU,KCG/F,aAAiB,QAAkC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACvD,MAAO,IAAG,MAAA,OAAA,EAAA,GAAA,EAAI,KCaT,aAA4C,CACjD,GAAM,GAAY,GAAI,IAAwB,GAC9C,SAAU,SAAU,mBAAoB,CAAE,KAAM,KAC7C,UAAU,IAAM,EAAU,KAAK,WAG3B,ECFF,WACL,EAAkB,EAAmB,SAChC,CACL,MAAO,OAAM,KAAK,EAAK,iBAAoB,IAwBtC,WACL,EAAkB,EAAmB,SAClC,CACH,GAAM,GAAK,GAAsB,EAAU,GAC3C,GAAI,MAAO,IAAO,YAChB,KAAM,IAAI,gBACR,8BAA8B,oBAIlC,MAAO,GAuBF,YACL,EAAkB,EAAmB,SACtB,CACf,MAAO,GAAK,cAAiB,IAAa,OAQrC,aAAqD,CAC1D,MAAO,UAAS,wBAAyB,cACrC,SAAS,eAAiB,OChEzB,YACL,EACqB,CACrB,MAAO,GACL,EAAU,SAAS,KAAM,WACzB,EAAU,SAAS,KAAM,aAExB,KACC,GAAa,GACb,EAAI,IAAM,CACR,GAAM,GAAS,KACf,MAAO,OAAO,IAAW,YACrB,EAAG,SAAS,GACZ,KAEN,EAAU,IAAO,MACjB,KCdC,YACL,EACe,CACf,MAAO,CACL,EAAG,EAAG,WACN,EAAG,EAAG,WAaH,YACL,EAC2B,CAC3B,MAAO,GACL,EAAU,OAAQ,QAClB,EAAU,OAAQ,WAEjB,KACC,GAAU,EAAG,IACb,EAAI,IAAM,GAAiB,IAC3B,EAAU,GAAiB,KCtC1B,YACL,EACe,CACf,MAAO,CACL,EAAG,EAAG,WACN,EAAG,EAAG,WAaH,YACL,EAC2B,CAC3B,MAAO,GACL,EAAU,EAAI,UACd,EAAU,OAAQ,WAEjB,KACC,GAAU,EAAG,IACb,EAAI,IAAM,GAAwB,IAClC,EAAU,GAAwB,KClExC,GAAI,IAAW,UAAY,CACvB,GAAI,MAAO,MAAQ,YACf,MAAO,KASX,WAAkB,EAAK,EAAK,CACxB,GAAI,GAAS,GACb,SAAI,KAAK,SAAU,EAAO,EAAO,CAC7B,MAAI,GAAM,KAAO,EACb,GAAS,EACF,IAEJ,KAEJ,EAEX,MAAsB,WAAY,CAC9B,YAAmB,CACf,KAAK,YAAc,GAEvB,cAAO,eAAe,EAAQ,UAAW,OAAQ,CAI7C,IAAK,UAAY,CACb,MAAO,MAAK,YAAY,QAE5B,WAAY,GACZ,aAAc,KAMlB,EAAQ,UAAU,IAAM,SAAU,EAAK,CACnC,GAAI,GAAQ,EAAS,KAAK,YAAa,GACnC,EAAQ,KAAK,YAAY,GAC7B,MAAO,IAAS,EAAM,IAO1B,EAAQ,UAAU,IAAM,SAAU,EAAK,EAAO,CAC1C,GAAI,GAAQ,EAAS,KAAK,YAAa,GACvC,AAAI,CAAC,EACD,KAAK,YAAY,GAAO,GAAK,EAG7B,KAAK,YAAY,KAAK,CAAC,EAAK,KAOpC,EAAQ,UAAU,OAAS,SAAU,EAAK,CACtC,GAAI,GAAU,KAAK,YACf,EAAQ,EAAS,EAAS,GAC9B,AAAI,CAAC,GACD,EAAQ,OAAO,EAAO,IAO9B,EAAQ,UAAU,IAAM,SAAU,EAAK,CACnC,MAAO,CAAC,CAAC,CAAC,EAAS,KAAK,YAAa,IAKzC,EAAQ,UAAU,MAAQ,UAAY,CAClC,KAAK,YAAY,OAAO,IAO5B,EAAQ,UAAU,QAAU,SAAU,EAAU,EAAK,CACjD,AAAI,IAAQ,QAAU,GAAM,MAC5B,OAAS,GAAK,EAAG,EAAK,KAAK,YAAa,EAAK,EAAG,OAAQ,IAAM,CAC1D,GAAI,GAAQ,EAAG,GACf,EAAS,KAAK,EAAK,EAAM,GAAI,EAAM,MAGpC,QAOX,GAAY,MAAO,SAAW,aAAe,MAAO,WAAa,aAAe,OAAO,WAAa,SAGpG,GAAY,UAAY,CACxB,MAAI,OAAO,SAAW,aAAe,OAAO,OAAS,KAC1C,OAEP,MAAO,OAAS,aAAe,KAAK,OAAS,KACtC,KAEP,MAAO,SAAW,aAAe,OAAO,OAAS,KAC1C,OAGJ,SAAS,oBAShB,GAA2B,UAAY,CACvC,MAAI,OAAO,wBAA0B,WAI1B,sBAAsB,KAAK,IAE/B,SAAU,EAAU,CAAE,MAAO,YAAW,UAAY,CAAE,MAAO,GAAS,KAAK,QAAW,IAAO,QAIpG,GAAkB,EAStB,YAAmB,EAAU,EAAO,CAChC,GAAI,GAAc,GAAO,EAAe,GAAO,EAAe,EAO9D,YAA0B,CACtB,AAAI,GACA,GAAc,GACd,KAEA,GACA,IAUR,YAA2B,CACvB,GAAwB,GAO5B,YAAiB,CACb,GAAI,GAAY,KAAK,MACrB,GAAI,EAAa,CAEb,GAAI,EAAY,EAAe,GAC3B,OAMJ,EAAe,OAGf,GAAc,GACd,EAAe,GACf,WAAW,EAAiB,GAEhC,EAAe,EAEnB,MAAO,GAIX,GAAI,IAAgB,GAGhB,GAAiB,CAAC,MAAO,QAAS,SAAU,OAAQ,QAAS,SAAU,OAAQ,UAE/E,GAA4B,MAAO,mBAAqB,YAIxD,GAA0C,UAAY,CAMtD,YAAoC,CAMhC,KAAK,WAAa,GAMlB,KAAK,qBAAuB,GAM5B,KAAK,mBAAqB,KAM1B,KAAK,WAAa,GAClB,KAAK,iBAAmB,KAAK,iBAAiB,KAAK,MACnD,KAAK,QAAU,GAAS,KAAK,QAAQ,KAAK,MAAO,IAQrD,SAAyB,UAAU,YAAc,SAAU,EAAU,CACjE,AAAK,CAAC,KAAK,WAAW,QAAQ,IAC1B,KAAK,WAAW,KAAK,GAGpB,KAAK,YACN,KAAK,YASb,EAAyB,UAAU,eAAiB,SAAU,EAAU,CACpE,GAAI,GAAY,KAAK,WACjB,EAAQ,EAAU,QAAQ,GAE9B,AAAI,CAAC,GACD,EAAU,OAAO,EAAO,GAGxB,CAAC,EAAU,QAAU,KAAK,YAC1B,KAAK,eASb,EAAyB,UAAU,QAAU,UAAY,CACrD,GAAI,GAAkB,KAAK,mBAG3B,AAAI,GACA,KAAK,WAWb,EAAyB,UAAU,iBAAmB,UAAY,CAE9D,GAAI,GAAkB,KAAK,WAAW,OAAO,SAAU,EAAU,CAC7D,MAAO,GAAS,eAAgB,EAAS,cAO7C,SAAgB,QAAQ,SAAU,EAAU,CAAE,MAAO,GAAS,oBACvD,EAAgB,OAAS,GAQpC,EAAyB,UAAU,SAAW,UAAY,CAGtD,AAAI,CAAC,IAAa,KAAK,YAMvB,UAAS,iBAAiB,gBAAiB,KAAK,kBAChD,OAAO,iBAAiB,SAAU,KAAK,SACvC,AAAI,GACA,MAAK,mBAAqB,GAAI,kBAAiB,KAAK,SACpD,KAAK,mBAAmB,QAAQ,SAAU,CACtC,WAAY,GACZ,UAAW,GACX,cAAe,GACf,QAAS,MAIb,UAAS,iBAAiB,qBAAsB,KAAK,SACrD,KAAK,qBAAuB,IAEhC,KAAK,WAAa,KAQtB,EAAyB,UAAU,YAAc,UAAY,CAGzD,AAAI,CAAC,IAAa,CAAC,KAAK,YAGxB,UAAS,oBAAoB,gBAAiB,KAAK,kBACnD,OAAO,oBAAoB,SAAU,KAAK,SACtC,KAAK,oBACL,KAAK,mBAAmB,aAExB,KAAK,sBACL,SAAS,oBAAoB,qBAAsB,KAAK,SAE5D,KAAK,mBAAqB,KAC1B,KAAK,qBAAuB,GAC5B,KAAK,WAAa,KAStB,EAAyB,UAAU,iBAAmB,SAAU,EAAI,CAChE,GAAI,GAAK,EAAG,aAAc,EAAe,IAAO,OAAS,GAAK,EAE1D,EAAmB,GAAe,KAAK,SAAU,EAAK,CACtD,MAAO,CAAC,CAAC,CAAC,EAAa,QAAQ,KAEnC,AAAI,GACA,KAAK,WAQb,EAAyB,YAAc,UAAY,CAC/C,MAAK,MAAK,WACN,MAAK,UAAY,GAAI,IAElB,KAAK,WAOhB,EAAyB,UAAY,KAC9B,KAUP,GAAsB,SAAU,EAAQ,EAAO,CAC/C,OAAS,GAAK,EAAG,EAAK,OAAO,KAAK,GAAQ,EAAK,EAAG,OAAQ,IAAM,CAC5D,GAAI,GAAM,EAAG,GACb,OAAO,eAAe,EAAQ,EAAK,CAC/B,MAAO,EAAM,GACb,WAAY,GACZ,SAAU,GACV,aAAc,KAGtB,MAAO,IASP,GAAe,SAAU,EAAQ,CAIjC,GAAI,GAAc,GAAU,EAAO,eAAiB,EAAO,cAAc,YAGzE,MAAO,IAAe,IAItB,GAAY,GAAe,EAAG,EAAG,EAAG,GAOxC,YAAiB,EAAO,CACpB,MAAO,YAAW,IAAU,EAShC,YAAwB,EAAQ,CAE5B,OADI,GAAY,GACP,EAAK,EAAG,EAAK,UAAU,OAAQ,IACpC,EAAU,EAAK,GAAK,UAAU,GAElC,MAAO,GAAU,OAAO,SAAU,EAAM,EAAU,CAC9C,GAAI,GAAQ,EAAO,UAAY,EAAW,UAC1C,MAAO,GAAO,GAAQ,IACvB,GAQP,YAAqB,EAAQ,CAGzB,OAFI,GAAY,CAAC,MAAO,QAAS,SAAU,QACvC,EAAW,GACN,EAAK,EAAG,EAAc,EAAW,EAAK,EAAY,OAAQ,IAAM,CACrE,GAAI,GAAW,EAAY,GACvB,EAAQ,EAAO,WAAa,GAChC,EAAS,GAAY,GAAQ,GAEjC,MAAO,GASX,YAA2B,EAAQ,CAC/B,GAAI,GAAO,EAAO,UAClB,MAAO,IAAe,EAAG,EAAG,EAAK,MAAO,EAAK,QAQjD,YAAmC,EAAQ,CAGvC,GAAI,GAAc,EAAO,YAAa,EAAe,EAAO,aAS5D,GAAI,CAAC,GAAe,CAAC,EACjB,MAAO,IAEX,GAAI,GAAS,GAAY,GAAQ,iBAAiB,GAC9C,EAAW,GAAY,GACvB,EAAW,EAAS,KAAO,EAAS,MACpC,EAAU,EAAS,IAAM,EAAS,OAKlC,EAAQ,GAAQ,EAAO,OAAQ,EAAS,GAAQ,EAAO,QAqB3D,GAlBI,EAAO,YAAc,cAOjB,MAAK,MAAM,EAAQ,KAAc,GACjC,IAAS,GAAe,EAAQ,OAAQ,SAAW,GAEnD,KAAK,MAAM,EAAS,KAAa,GACjC,IAAU,GAAe,EAAQ,MAAO,UAAY,IAOxD,CAAC,GAAkB,GAAS,CAK5B,GAAI,GAAgB,KAAK,MAAM,EAAQ,GAAY,EAC/C,EAAiB,KAAK,MAAM,EAAS,GAAW,EAMpD,AAAI,KAAK,IAAI,KAAmB,GAC5B,IAAS,GAET,KAAK,IAAI,KAAoB,GAC7B,IAAU,GAGlB,MAAO,IAAe,EAAS,KAAM,EAAS,IAAK,EAAO,GAQ9D,GAAI,IAAwB,UAAY,CAGpC,MAAI,OAAO,qBAAuB,YACvB,SAAU,EAAQ,CAAE,MAAO,aAAkB,IAAY,GAAQ,oBAKrE,SAAU,EAAQ,CAAE,MAAQ,aAAkB,IAAY,GAAQ,YACrE,MAAO,GAAO,SAAY,eAQlC,YAA2B,EAAQ,CAC/B,MAAO,KAAW,GAAY,GAAQ,SAAS,gBAQnD,YAAwB,EAAQ,CAC5B,MAAK,IAGD,GAAqB,GACd,GAAkB,GAEtB,GAA0B,GALtB,GAcf,YAA4B,EAAI,CAC5B,GAAI,GAAI,EAAG,EAAG,EAAI,EAAG,EAAG,EAAQ,EAAG,MAAO,EAAS,EAAG,OAElD,EAAS,MAAO,kBAAoB,YAAc,gBAAkB,OACpE,EAAO,OAAO,OAAO,EAAO,WAEhC,UAAmB,EAAM,CACrB,EAAG,EAAG,EAAG,EAAG,MAAO,EAAO,OAAQ,EAClC,IAAK,EACL,MAAO,EAAI,EACX,OAAQ,EAAS,EACjB,KAAM,IAEH,EAYX,YAAwB,EAAG,EAAG,EAAO,EAAQ,CACzC,MAAO,CAAE,EAAG,EAAG,EAAG,EAAG,MAAO,EAAO,OAAQ,GAO/C,GAAI,IAAmC,UAAY,CAM/C,WAA2B,EAAQ,CAM/B,KAAK,eAAiB,EAMtB,KAAK,gBAAkB,EAMvB,KAAK,aAAe,GAAe,EAAG,EAAG,EAAG,GAC5C,KAAK,OAAS,EAQlB,SAAkB,UAAU,SAAW,UAAY,CAC/C,GAAI,GAAO,GAAe,KAAK,QAC/B,YAAK,aAAe,EACZ,EAAK,QAAU,KAAK,gBACxB,EAAK,SAAW,KAAK,iBAQ7B,EAAkB,UAAU,cAAgB,UAAY,CACpD,GAAI,GAAO,KAAK,aAChB,YAAK,eAAiB,EAAK,MAC3B,KAAK,gBAAkB,EAAK,OACrB,GAEJ,KAGP,GAAqC,UAAY,CAOjD,WAA6B,EAAQ,EAAU,CAC3C,GAAI,GAAc,GAAmB,GAOrC,GAAmB,KAAM,CAAE,OAAQ,EAAQ,YAAa,IAE5D,MAAO,MAGP,GAAmC,UAAY,CAW/C,WAA2B,EAAU,EAAY,EAAa,CAc1D,GAPA,KAAK,oBAAsB,GAM3B,KAAK,cAAgB,GAAI,IACrB,MAAO,IAAa,WACpB,KAAM,IAAI,WAAU,2DAExB,KAAK,UAAY,EACjB,KAAK,YAAc,EACnB,KAAK,aAAe,EAQxB,SAAkB,UAAU,QAAU,SAAU,EAAQ,CACpD,GAAI,CAAC,UAAU,OACX,KAAM,IAAI,WAAU,4CAGxB,GAAI,QAAO,UAAY,aAAe,CAAE,mBAAmB,UAG3D,IAAI,CAAE,aAAkB,IAAY,GAAQ,SACxC,KAAM,IAAI,WAAU,yCAExB,GAAI,GAAe,KAAK,cAExB,AAAI,EAAa,IAAI,IAGrB,GAAa,IAAI,EAAQ,GAAI,IAAkB,IAC/C,KAAK,YAAY,YAAY,MAE7B,KAAK,YAAY,aAQrB,EAAkB,UAAU,UAAY,SAAU,EAAQ,CACtD,GAAI,CAAC,UAAU,OACX,KAAM,IAAI,WAAU,4CAGxB,GAAI,QAAO,UAAY,aAAe,CAAE,mBAAmB,UAG3D,IAAI,CAAE,aAAkB,IAAY,GAAQ,SACxC,KAAM,IAAI,WAAU,yCAExB,GAAI,GAAe,KAAK,cAExB,AAAI,CAAC,EAAa,IAAI,IAGtB,GAAa,OAAO,GACf,EAAa,MACd,KAAK,YAAY,eAAe,SAQxC,EAAkB,UAAU,WAAa,UAAY,CACjD,KAAK,cACL,KAAK,cAAc,QACnB,KAAK,YAAY,eAAe,OAQpC,EAAkB,UAAU,aAAe,UAAY,CACnD,GAAI,GAAQ,KACZ,KAAK,cACL,KAAK,cAAc,QAAQ,SAAU,EAAa,CAC9C,AAAI,EAAY,YACZ,EAAM,oBAAoB,KAAK,MAU3C,EAAkB,UAAU,gBAAkB,UAAY,CAEtD,GAAI,EAAC,KAAK,YAGV,IAAI,GAAM,KAAK,aAEX,EAAU,KAAK,oBAAoB,IAAI,SAAU,EAAa,CAC9D,MAAO,IAAI,IAAoB,EAAY,OAAQ,EAAY,mBAEnE,KAAK,UAAU,KAAK,EAAK,EAAS,GAClC,KAAK,gBAOT,EAAkB,UAAU,YAAc,UAAY,CAClD,KAAK,oBAAoB,OAAO,IAOpC,EAAkB,UAAU,UAAY,UAAY,CAChD,MAAO,MAAK,oBAAoB,OAAS,GAEtC,KAMP,GAAY,MAAO,UAAY,YAAc,GAAI,SAAY,GAAI,IAKjE,GAAgC,UAAY,CAO5C,WAAwB,EAAU,CAC9B,GAAI,CAAE,gBAAgB,IAClB,KAAM,IAAI,WAAU,sCAExB,GAAI,CAAC,UAAU,OACX,KAAM,IAAI,WAAU,4CAExB,GAAI,GAAa,GAAyB,cACtC,EAAW,GAAI,IAAkB,EAAU,EAAY,MAC3D,GAAU,IAAI,KAAM,GAExB,MAAO,MAGX,CACI,UACA,YACA,cACF,QAAQ,SAAU,EAAQ,CACxB,GAAe,UAAU,GAAU,UAAY,CAC3C,GAAI,GACJ,MAAQ,GAAK,GAAU,IAAI,OAAO,GAAQ,MAAM,EAAI,cAI5D,GAAI,IAAS,UAAY,CAErB,MAAI,OAAO,IAAS,gBAAmB,YAC5B,GAAS,eAEb,MAGJ,GAAQ,GCr2Bf,GAAM,IAAS,GAAI,GAYb,GAAY,EAAM,IAAM,EAC5B,GAAI,IAAe,GAAW,CAC5B,OAAW,KAAS,GAClB,GAAO,KAAK,OAGf,KACC,EAAU,GAAY,EAAM,GAAO,EAAG,IACnC,KACC,EAAS,IAAM,EAAS,gBAG5B,EAAY,IAcT,YACL,EACa,CACb,MAAO,CACL,MAAQ,EAAG,YACX,OAAQ,EAAG,cAyBR,YACL,EACyB,CACzB,MAAO,IACJ,KACC,EAAI,GAAY,EAAS,QAAQ,IACjC,EAAU,GAAY,GACnB,KACC,EAAO,CAAC,CAAE,YAAa,IAAW,GAClC,EAAS,IAAM,EAAS,UAAU,IAClC,EAAI,IAAM,GAAe,MAG7B,EAAU,GAAe,KCxGxB,YACL,EACa,CACb,MAAO,CACL,MAAQ,EAAG,YACX,OAAQ,EAAG,cCWf,GAAM,IAAS,GAAI,GAUb,GAAY,EAAM,IAAM,EAC5B,GAAI,sBAAqB,GAAW,CAClC,OAAW,KAAS,GAClB,GAAO,KAAK,IACb,CACD,UAAW,MAGZ,KACC,EAAU,GAAY,EAAM,GAAO,EAAG,IACnC,KACC,EAAS,IAAM,EAAS,gBAG5B,EAAY,IAyCT,YACL,EAAiB,EAAY,GACR,CACrB,MAAO,IAA0B,GAC9B,KACC,EAAI,CAAC,CAAE,OAAQ,CACb,GAAM,GAAU,GAAe,GACzB,EAAU,GAAsB,GACtC,MAAO,IACL,EAAQ,OAAS,EAAQ,OAAS,IAGtC,KC/EN,GAAM,IAA4C,CAChD,OAAQ,EAAW,2BACnB,OAAQ,EAAW,4BAcd,YAAmB,EAAuB,CAC/C,MAAO,IAAQ,GAAM,QAchB,YAAmB,EAAc,EAAsB,CAC5D,AAAI,GAAQ,GAAM,UAAY,GAC5B,GAAQ,GAAM,QAYX,YAAqB,EAAmC,CAC7D,GAAM,GAAK,GAAQ,GACnB,MAAO,GAAU,EAAI,UAClB,KACC,EAAI,IAAM,EAAG,SACb,EAAU,EAAG,UChCnB,YACE,EAAiB,EACR,CACT,OAAQ,EAAG,iBAGJ,kBAEH,MAAI,GAAG,OAAS,QACP,SAAS,KAAK,GAEd,OAGN,uBACA,qBACH,MAAO,WAIP,MAAO,GAAG,mBAaT,aAA+C,CACpD,MAAO,GAAyB,OAAQ,WACrC,KACC,EAAO,GAAM,CAAE,GAAG,SAAW,EAAG,UAChC,EAAI,GAAO,EACT,KAAM,GAAU,UAAY,SAAW,SACvC,KAAM,EAAG,IACT,OAAQ,CACN,EAAG,iBACH,EAAG,sBAGP,EAAO,CAAC,CAAE,OAAM,UAAW,CACzB,GAAI,IAAS,SAAU,CACrB,GAAM,GAAS,KACf,GAAI,MAAO,IAAW,YACpB,MAAO,CAAC,GAAwB,EAAQ,GAE5C,MAAO,KAET,MClFC,aAA4B,CACjC,MAAO,IAAI,KAAI,SAAS,MAQnB,YAAqB,EAAgB,CAC1C,SAAS,KAAO,EAAI,KAUf,aAAuC,CAC5C,MAAO,IAAI,GCJb,YAAqB,EAAiB,EAA8B,CAGlE,GAAI,MAAO,IAAU,UAAY,MAAO,IAAU,SAChD,EAAG,WAAa,EAAM,mBAGb,YAAiB,MAC1B,EAAG,YAAY,WAGN,MAAM,QAAQ,GACvB,OAAW,KAAQ,GACjB,GAAY,EAAI,GA2Bf,WACL,EAAa,KAAmC,EAC7C,CACH,GAAM,GAAK,SAAS,cAAc,GAGlC,GAAI,EACF,OAAW,KAAQ,QAAO,KAAK,GAC7B,AAAI,MAAO,GAAW,IAAU,UAC9B,EAAG,aAAa,EAAM,EAAW,IAC1B,EAAW,IAClB,EAAG,aAAa,EAAM,IAG5B,OAAW,KAAS,GAClB,GAAY,EAAI,GAGlB,MAAO,GC1EF,YAAkB,EAAe,EAAmB,CACzD,GAAI,GAAI,EACR,GAAI,EAAM,OAAS,EAAG,CACpB,KAAO,EAAM,KAAO,KAAO,EAAE,EAAI,GAAG,CACpC,MAAO,GAAG,EAAM,UAAU,EAAG,QAE/B,MAAO,GAmBF,YAAe,EAAuB,CAC3C,GAAI,EAAQ,IAAK,CACf,GAAM,GAAS,CAAG,IAAQ,KAAO,IAAO,IACxC,MAAO,GAAK,IAAQ,MAAY,KAAM,QAAQ,UAE9C,OAAO,GAAM,WC1BV,aAAmC,CACxC,MAAO,UAAS,KAAK,UAAU,GAa1B,YAAyB,EAAoB,CAClD,GAAM,GAAK,EAAE,IAAK,CAAE,KAAM,IAC1B,EAAG,iBAAiB,QAAS,GAAM,EAAG,mBACtC,EAAG,QAUE,aAAiD,CACtD,MAAO,GAA2B,OAAQ,cACvC,KACC,EAAI,IACJ,EAAU,MACV,EAAO,GAAQ,EAAK,OAAS,GAC7B,EAAY,IASX,aAAwD,CAC7D,MAAO,MACJ,KACC,EAAI,GAAM,GAAmB,QAAQ,QACrC,EAAO,GAAM,MAAO,IAAO,cCxC1B,YAAoB,EAAoC,CAC7D,GAAM,GAAQ,WAAW,GACzB,MAAO,IAA0B,GAC/B,EAAM,YAAY,IAAM,EAAK,EAAM,WAElC,KACC,EAAU,EAAM,UASf,aAA2C,CAChD,GAAM,GAAQ,WAAW,SACzB,MAAO,GACL,EAAU,OAAQ,eAAe,KAAK,EAAM,KAC5C,EAAU,OAAQ,cAAc,KAAK,EAAM,MAE1C,KACC,EAAU,EAAM,UAgBf,YACL,EAA6B,EACd,CACf,MAAO,GACJ,KACC,EAAU,GAAU,EAAS,IAAY,IC5CxC,YACL,EAAmB,EAAuB,CAAE,YAAa,eACnC,CACtB,MAAO,IAAK,MAAM,GAAG,IAAO,IACzB,KACC,EAAO,GAAO,EAAI,SAAW,KAC7B,GAAW,IAAM,IAchB,YACL,EAAmB,EACJ,CACf,MAAO,IAAQ,EAAK,GACjB,KACC,EAAU,GAAO,EAAI,QACrB,EAAY,IAYX,YACL,EAAmB,EACG,CACtB,GAAM,GAAM,GAAI,WAChB,MAAO,IAAQ,EAAK,GACjB,KACC,EAAU,GAAO,EAAI,QACrB,EAAI,GAAO,EAAI,gBAAgB,EAAK,aACpC,EAAY,IC5CX,YAAqB,EAA+B,CACzD,GAAM,GAAS,EAAE,SAAU,CAAE,QAC7B,MAAO,GAAM,IACX,UAAS,KAAK,YAAY,GACnB,EACL,EAAU,EAAQ,QAClB,EAAU,EAAQ,SACf,KACC,EAAU,IACR,GAAW,IAAM,GAAI,gBAAe,mBAAmB,SAI5D,KACC,EAAM,QACN,EAAS,IAAM,SAAS,KAAK,YAAY,IACzC,GAAK,MCZN,aAA6C,CAClD,MAAO,CACL,EAAG,KAAK,IAAI,EAAG,SACf,EAAG,KAAK,IAAI,EAAG,UAWZ,aAA2D,CAChE,MAAO,GACL,EAAU,OAAQ,SAAU,CAAE,QAAS,KACvC,EAAU,OAAQ,SAAU,CAAE,QAAS,MAEtC,KACC,EAAI,IACJ,EAAU,OCzBT,aAAyC,CAC9C,MAAO,CACL,MAAQ,WACR,OAAQ,aAWL,aAAuD,CAC5D,MAAO,GAAU,OAAQ,SAAU,CAAE,QAAS,KAC3C,KACC,EAAI,IACJ,EAAU,OCTT,aAA+C,CACpD,MAAO,GAAc,CACnB,KACA,OAEC,KACC,EAAI,CAAC,CAAC,EAAQ,KAAW,EAAE,SAAQ,UACnC,EAAY,ICRX,YACL,EAAiB,CAAE,YAAW,WACR,CACtB,GAAM,GAAQ,EACX,KACC,EAAwB,SAItB,EAAU,EAAc,CAAC,EAAO,IACnC,KACC,EAAI,IAAM,GAAiB,KAI/B,MAAO,GAAc,CAAC,EAAS,EAAW,IACvC,KACC,EAAI,CAAC,CAAC,CAAE,UAAU,CAAE,SAAQ,QAAQ,CAAE,IAAG,QAAU,EACjD,OAAQ,CACN,EAAG,EAAO,EAAI,EACd,EAAG,EAAO,EAAI,EAAI,GAEpB,WCOD,YACL,EAAgB,CAAE,OACH,CAGf,GAAM,GAAM,EAAwB,EAAQ,WACzC,KACC,EAAI,CAAC,CAAE,UAAW,IAItB,MAAO,GACJ,KACC,GAAS,IAAM,EAAK,CAAE,QAAS,GAAM,SAAU,KAC/C,EAAI,GAAW,EAAO,YAAY,IAClC,GAAY,GACZ,MCFN,GAAM,IAAS,EAAW,aACpB,GAAiB,KAAK,MAAM,GAAO,aACzC,GAAO,KAAO,GAAG,GAAI,KAAI,GAAO,KAAM,QAW/B,aAAiC,CACtC,MAAO,IAUF,YAAiB,EAAqB,CAC3C,MAAO,IAAO,SAAS,SAAS,GAW3B,YACL,EAAkB,EACV,CACR,MAAO,OAAO,IAAU,YACpB,GAAO,aAAa,GAAK,QAAQ,IAAK,EAAM,YAC5C,GAAO,aAAa,GC7BnB,YACL,EAAS,EAAmB,SACP,CACrB,MAAO,GAAW,sBAAsB,KAAS,GAa5C,YACL,EAAS,EAAmB,SACL,CACvB,MAAO,GAAY,sBAAsB,KAAS,GC9GpD,OAAwB,SCajB,YAA0B,EAAyB,CACxD,MACE,GAAC,QAAD,CAAO,MAAM,gBAAgB,SAAU,GACrC,EAAC,MAAD,CAAK,MAAM,mCACT,EAAC,MAAD,CAAK,MAAM,kCAEb,EAAC,OAAD,CAAM,MAAM,wBACV,EAAC,OAAD,CAAM,wBAAuB,MCN9B,YAA+B,EAAyB,CAC7D,MACE,GAAC,SAAD,CACE,MAAM,uBACN,MAAO,GAAY,kBACnB,wBAAuB,IAAI,aCejC,YACE,EAA2C,EAC9B,CACb,GAAM,GAAS,EAAO,EAChB,EAAS,EAAO,EAGhB,EAAU,OAAO,KAAK,EAAS,OAClC,OAAO,GAAO,CAAC,EAAS,MAAM,IAC9B,OAAyB,CAAC,EAAM,IAAQ,CACvC,GAAG,EAAM,EAAC,MAAD,KAAM,GAAY,KAC1B,IACF,MAAM,EAAG,IAGN,EAAM,GAAI,KAAI,EAAS,UAC7B,MAAI,IAAQ,qBACV,EAAI,aAAa,IAAI,IAAK,OAAO,QAAQ,EAAS,OAC/C,OAAO,CAAC,CAAC,CAAE,KAAW,GACtB,OAAO,CAAC,EAAW,CAAC,KAAW,GAAG,KAAa,IAAQ,OAAQ,KAKlE,EAAC,IAAD,CAAG,KAAM,GAAG,IAAO,MAAM,yBAAyB,SAAU,IAC1D,EAAC,UAAD,CACE,MAAO,CAAC,4BAA6B,GAAG,EACpC,CAAC,uCACD,IACF,KAAK,KACP,gBAAe,EAAS,MAAM,QAAQ,IAErC,EAAS,GAAK,EAAC,MAAD,CAAK,MAAM,mCAC1B,EAAC,KAAD,CAAI,MAAM,2BAA2B,EAAS,OAC7C,EAAS,GAAK,EAAS,KAAK,OAAS,GACpC,EAAC,IAAD,CAAG,MAAM,4BACN,GAAS,EAAS,KAAM,MAG5B,EAAS,MAAQ,EAAS,KAAK,IAAI,GAClC,EAAC,OAAD,CAAM,MAAM,UAAU,IAEvB,EAAS,GAAK,EAAQ,OAAS,GAC9B,EAAC,IAAD,CAAG,MAAM,2BACN,GAAY,8BAA8B,KAAM,KAmBtD,YACL,EACa,CACb,GAAM,GAAY,EAAO,GAAG,MACtB,EAAO,CAAC,GAAG,GAGX,EAAS,EAAK,UAAU,GAAO,CAAC,EAAI,SAAS,SAAS,MACtD,CAAC,GAAW,EAAK,OAAO,EAAQ,GAGlC,EAAQ,EAAK,UAAU,GAAO,EAAI,MAAQ,GAC9C,AAAI,IAAU,IACZ,GAAQ,EAAK,QAGf,GAAM,GAAO,EAAK,MAAM,EAAG,GACrB,EAAO,EAAK,MAAM,GAGlB,EAAW,CACf,GAAqB,EAAS,EAAc,CAAE,EAAC,GAAU,IAAU,IACnE,GAAG,EAAK,IAAI,GAAW,GAAqB,EAAS,IACrD,GAAG,EAAK,OAAS,CACf,EAAC,UAAD,CAAS,MAAM,0BACb,EAAC,UAAD,CAAS,SAAU,IAChB,EAAK,OAAS,GAAK,EAAK,SAAW,EAChC,GAAY,0BACZ,GAAY,2BAA4B,EAAK,SAG/C,EAAK,IAAI,GAAW,GAAqB,EAAS,MAEtD,IAIN,MACE,GAAC,KAAD,CAAI,MAAM,0BACP,GC1HA,YAA2B,EAAiC,CACjE,MACE,GAAC,KAAD,CAAI,MAAM,oBACP,OAAO,QAAQ,GAAO,IAAI,CAAC,CAAC,EAAK,KAChC,EAAC,KAAD,CAAI,MAAO,oCAAoC,KAC5C,MAAO,IAAU,SAAW,GAAM,GAAS,KCN/C,YAAqB,EAAiC,CAC3D,MACE,GAAC,MAAD,CAAK,MAAM,0BACT,EAAC,MAAD,CAAK,MAAM,qBACR,ICUT,YAAuB,EAA+B,CACpD,GAAM,GAAS,KAGT,EAAM,GAAI,KAAI,MAAM,EAAQ,WAAY,EAAO,MACrD,MACE,GAAC,KAAD,CAAI,MAAM,oBACR,EAAC,IAAD,CAAG,KAAM,EAAI,WAAY,MAAM,oBAC5B,EAAQ,QAkBV,YACL,EAAqB,EACR,CACb,MACE,GAAC,MAAD,CAAK,MAAM,cACT,EAAC,SAAD,CACE,MAAM,sBACN,aAAY,GAAY,yBAEvB,EAAO,OAEV,EAAC,KAAD,CAAI,MAAM,oBACP,EAAS,IAAI,MCdf,YACL,EAAiB,EACO,CACxB,GAAM,GAAU,EAAM,IAAM,EAAc,CACxC,GAAmB,GACnB,GAA0B,MAEzB,KACC,EAAI,CAAC,CAAC,CAAE,IAAG,KAAK,KAAY,CAC1B,GAAM,CAAE,SAAU,GAAe,GACjC,MAAQ,CACN,EAAG,EAAI,EAAO,EAAI,EAAQ,EAC1B,EAAG,EAAI,EAAO,MAMtB,MAAO,IAAkB,GACtB,KACC,EAAU,GAAU,EACjB,KACC,EAAI,GAAW,EAAE,SAAQ,YACzB,GAAK,CAAC,CAAC,GAAU,QAcpB,YACL,EAAiB,EACkB,CACnC,MAAO,GAAM,IAAM,CACjB,GAAM,GAAQ,GAAI,GAClB,EAAM,UAAU,CAGd,KAAK,CAAE,UAAU,CACf,EAAG,MAAM,YAAY,iBAAkB,GAAG,EAAO,OACjD,EAAG,MAAM,YAAY,iBAAkB,GAAG,EAAO,QAInD,UAAW,CACT,EAAG,MAAM,eAAe,kBACxB,EAAG,MAAM,eAAe,qBAK5B,EACG,KACC,GAAa,IAAK,IAClB,EAAI,IAAM,EAAU,yBACpB,EAAI,CAAC,CAAE,OAAQ,IAEd,UAAU,CAGT,KAAK,EAAQ,CACX,AAAI,EACF,EAAG,MAAM,YAAY,iBAAkB,GAAG,CAAC,OAE3C,EAAG,MAAM,eAAe,mBAI5B,UAAW,CACT,EAAG,MAAM,eAAe,qBAKhC,GAAM,GAAQ,EAAW,uBAAwB,GAC3C,EAAQ,EAAU,EAAO,YAAa,CAAE,KAAM,KACpD,SACG,KACC,EAAU,CAAC,CAAE,YAAa,EAAS,EAAQ,GAC3C,EAAI,GAAM,EAAG,mBAEZ,UAAU,IAAM,EAAG,QAGjB,GAAgB,EAAI,GACxB,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,OCnGpC,YAA+B,EAAgC,CAC7D,GAAM,GAAkB,GACxB,OAAW,KAAW,GAAY,eAAgB,GAAY,CAC5D,GAAI,GACA,EAAO,EAAQ,WAGnB,KAAQ,EAAQ,YAAY,KAAK,EAAK,cAAgB,CACpD,GAAM,GAAS,EAAK,UAAU,EAAM,OACpC,EAAO,EAAO,UAAU,EAAM,GAAG,QACjC,EAAQ,KAAK,IAGjB,MAAO,GAST,YAAc,EAAqB,EAA2B,CAC5D,EAAO,OAAO,GAAG,MAAM,KAAK,EAAO,aAqB9B,YACL,EAAiB,EAAwB,CAAE,UACR,CAGnC,GAAM,GAAc,GAAI,KACxB,OAAW,KAAU,IAAsB,GAAY,CACrD,GAAM,CAAC,CAAE,GAAM,EAAO,YAAa,MAAM,aACzC,AAAI,GAAmB,gBAAgB,KAAO,IAC5C,GAAY,IAAI,CAAC,EAAI,GAAiB,CAAC,IACvC,EAAO,YAAY,EAAY,IAAI,CAAC,KAKxC,MAAI,GAAY,OAAS,EAChB,EAGF,EAAM,IAAM,CACjB,GAAM,GAAQ,GAAI,GAGlB,SACG,KACC,GAAU,EAAM,KAAK,GAAS,MAE7B,UAAU,GAAU,CACnB,EAAG,OAAS,CAAC,EAGb,OAAW,CAAC,EAAI,IAAe,GAAa,CAC1C,GAAM,GAAQ,EAAW,cAAe,GAClC,EAAQ,EAAW,gBAAgB,KAAO,GAChD,AAAK,EAGH,GAAK,EAAO,GAFZ,GAAK,EAAO,MAOf,EAAM,GAAG,CAAC,GAAG,GACjB,IAAI,CAAC,CAAC,CAAE,KACP,GAAgB,EAAY,KAG7B,KACC,EAAS,IAAM,EAAM,YACrB,QRjFR,GAAI,IAAW,EAaf,YAA2B,EAA0C,CACnE,GAAI,EAAG,mBAAoB,CACzB,GAAM,GAAU,EAAG,mBACnB,GAAI,EAAQ,UAAY,KACtB,MAAO,GAGJ,GAAI,EAAQ,UAAY,KAAO,CAAC,EAAQ,SAAS,OACpD,MAAO,IAAkB,IAqBxB,YACL,EACuB,CACvB,MAAO,IAAiB,GACrB,KACC,EAAI,CAAC,CAAE,WAEE,EACL,WAAY,AAFE,GAAsB,GAEhB,MAAQ,KAGhC,EAAwB,eAiBvB,YACL,EAAiB,EAC8B,CAC/C,GAAM,CAAE,QAAS,GAAU,WAAW,WACtC,MAAO,GAAM,IAAM,CACjB,GAAM,GAAQ,GAAI,GASlB,GARA,EAAM,UAAU,CAAC,CAAE,gBAAiB,CAClC,AAAI,GAAc,EAChB,EAAG,aAAa,WAAY,KAE5B,EAAG,gBAAgB,cAInB,WAAY,cAAe,CAC7B,GAAM,GAAS,EAAG,QAAQ,OAC1B,EAAO,GAAK,UAAU,EAAE,KACxB,EAAO,aACL,GAAsB,EAAO,IAC7B,GAKJ,GAAM,GAAY,EAAG,QAAQ,CAC3B,mCACA,mBACA,KAAK,OACP,GAAI,YAAqB,aAAa,CACpC,GAAM,GAAO,GAAkB,GAG/B,GAAI,MAAO,IAAS,aAClB,GAAU,UAAU,SAAS,aAC7B,GAAQ,0BACP,CACD,GAAM,GAAe,GAAoB,EAAM,EAAI,GAGnD,MAAO,IAAe,GACnB,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,IAC5B,GAAU,GAAiB,GACxB,KACC,GAAU,EAAM,KAAK,GAAS,KAC9B,EAAI,CAAC,CAAE,QAAO,YAAa,GAAS,GACpC,IACA,EAAU,GAAU,EAAS,EAAe,OAQxD,MAAO,IAAe,GACnB,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,yvIS/JpC,GAAI,IAKA,GAAQ,EAWZ,aAA0C,CACxC,MAAO,OAAO,UAAY,YACtB,GAAY,wDACZ,EAAG,QAcF,YACL,EACgC,CAChC,SAAG,UAAU,OAAO,WACpB,QAAa,KACV,KACC,EAAI,IAAM,QAAQ,WAAW,CAC3B,YAAa,GACb,eAEF,EAAM,QACN,EAAY,KAIhB,GAAS,UAAU,IAAM,CACvB,EAAG,UAAU,IAAI,WACjB,GAAM,GAAK,aAAa,OAClB,EAAO,EAAE,MAAO,CAAE,MAAO,YAC/B,QAAQ,WAAW,OAAO,EAAI,EAAG,YAAa,AAAC,GAAgB,CAG7D,GAAM,GAAS,EAAK,aAAa,CAAE,KAAM,WACzC,EAAO,UAAY,EAGnB,EAAG,YAAY,OAKZ,GACJ,KACC,EAAM,CAAE,IAAK,KCvCZ,YACL,EAAwB,CAAE,UAAS,UACd,CACrB,GAAI,GAAO,GACX,MAAO,GAGL,EACG,KACC,EAAI,GAAU,EAAO,QAAQ,wBAC7B,EAAO,GAAW,IAAO,GACzB,EAAe,CAAE,OAAQ,OAAQ,OAAQ,MAI7C,EACG,KACC,EAAO,GAAU,GAAU,CAAC,GAC5B,EAAI,IAAM,EAAO,EAAG,MACpB,EAAI,GAAW,EACb,OAAQ,EAAS,OAAS,aAiB7B,YACL,EAAwB,EACQ,CAChC,MAAO,GAAM,IAAM,CACjB,GAAM,GAAQ,GAAI,GAClB,SAAM,UAAU,CAAC,CAAE,SAAQ,YAAa,CACtC,AAAI,IAAW,OACb,EAAG,aAAa,OAAQ,IAExB,EAAG,gBAAgB,QACjB,GACF,EAAG,mBAIA,GAAa,EAAI,GACrB,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,OC3FpC,GAAM,IAAW,EAAE,SAgBZ,YACL,EACkC,CAClC,SAAG,YAAY,IACf,GAAS,YAAY,GAAY,IAG1B,EAAG,CAAE,IAAK,ICIZ,YACL,EACyB,CACzB,GAAM,GAAS,EAAY,iBAAkB,GAC7C,MAAO,GAAM,GAAG,EAAO,IAAI,GAAS,EAAU,EAAO,UAClD,KACC,EAAmB,CACjB,OAAQ,EAAW,aAAa,EAAM,YAIzC,KACC,EAAU,CACR,OAAQ,EAAW,aAAa,EAAO,GAAG,UAiB3C,YACL,EACoC,CACpC,GAAM,GAAY,EAAW,iBAAkB,GAC/C,MAAO,GAAM,IAAM,CACjB,GAAM,GAAQ,GAAI,GAClB,SAAc,CAAC,EAAO,GAAiB,KACpC,KACC,GAAU,EAAG,IACb,GAAU,EAAM,KAAK,GAAS,MAE7B,UAAU,CAGT,KAAK,CAAC,CAAE,WAAW,CACjB,GAAM,GAAS,GAAiB,GAC1B,CAAE,SAAU,GAAe,GAGjC,EAAG,MAAM,YAAY,mBAAoB,GAAG,EAAO,OACnD,EAAG,MAAM,YAAY,uBAAwB,GAAG,OAGhD,EAAU,SAAS,CACjB,SAAU,SACV,KAAM,EAAO,KAKjB,UAAW,CACT,EAAG,MAAM,eAAe,oBACxB,EAAG,MAAM,eAAe,2BAKzB,GAAiB,GACrB,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,OCtD7B,YACL,EAAiB,CAAE,UAAS,UACI,CAChC,MAAO,GAGL,GAAG,EAAY,2BAA4B,GACxC,IAAI,GAAS,GAAe,EAAO,CAAE,YAGxC,GAAG,EAAY,cAAe,GAC3B,IAAI,GAAS,GAAa,IAG7B,GAAG,EAAY,qBAAsB,GAClC,IAAI,GAAS,GAAe,IAG/B,GAAG,EAAY,UAAW,GACvB,IAAI,GAAS,GAAa,EAAO,CAAE,UAAS,YAG/C,GAAG,EAAY,cAAe,GAC3B,IAAI,GAAS,GAAiB,KC/B9B,YACL,EAAkB,CAAE,UACA,CACpB,MAAO,GACJ,KACC,EAAU,GAAW,EACnB,EAAG,IACH,EAAG,IAAO,KAAK,GAAM,OAEpB,KACC,EAAI,GAAW,EAAE,UAAS,eAiB7B,YACL,EAAiB,EACc,CAC/B,GAAM,GAAQ,EAAW,cAAe,GACxC,MAAO,GAAM,IAAM,CACjB,GAAM,GAAQ,GAAI,GAClB,SAAM,UAAU,CAAC,CAAE,UAAS,YAAa,CACvC,EAAM,YAAc,EACpB,AAAI,EACF,EAAG,aAAa,gBAAiB,QAEjC,EAAG,gBAAgB,mBAIhB,GAAY,EAAI,GACpB,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,OC7BpC,YAAkB,CAAE,aAAgD,CAClE,GAAI,CAAC,GAAQ,mBACX,MAAO,GAAG,IAGZ,GAAM,GAAa,EAChB,KACC,EAAI,CAAC,CAAE,OAAQ,CAAE,QAAU,GAC3B,GAAY,EAAG,GACf,EAAI,CAAC,CAAC,EAAG,KAAO,CAAC,EAAI,EAAG,IACxB,EAAwB,IAItB,EAAU,EAAc,CAAC,EAAW,IACvC,KACC,EAAO,CAAC,CAAC,CAAE,UAAU,CAAC,CAAE,MAAQ,KAAK,IAAI,EAAI,EAAO,GAAK,KACzD,EAAI,CAAC,CAAC,CAAE,CAAC,MAAgB,GACzB,KAIE,EAAU,GAAY,UAC5B,MAAO,GAAc,CAAC,EAAW,IAC9B,KACC,EAAI,CAAC,CAAC,CAAE,UAAU,KAAY,EAAO,EAAI,KAAO,CAAC,GACjD,IACA,EAAU,GAAU,EAAS,EAAU,EAAG,KAC1C,EAAU,KAgBT,YACL,EAAiB,EACG,CACpB,MAAO,GAAM,IAAM,CACjB,GAAM,GAAS,iBAAiB,GAChC,MAAO,GACL,EAAO,WAAa,UACpB,EAAO,WAAa,oBAGrB,KACC,GAAkB,GAAiB,GAAK,GAAS,IACjD,EAAI,CAAC,CAAC,EAAQ,CAAE,UAAU,KAAa,EACrC,OAAQ,EAAS,EAAS,EAC1B,SACA,YAEF,EAAqB,CAAC,EAAG,IACvB,EAAE,SAAW,EAAE,QACf,EAAE,SAAW,EAAE,QACf,EAAE,SAAW,EAAE,QAEjB,EAAY,IAeX,YACL,EAAiB,CAAE,UAAS,SACG,CAC/B,MAAO,GAAM,IAAM,CACjB,GAAM,GAAQ,GAAI,GAClB,SACG,KACC,EAAwB,UACxB,GAAkB,IAEjB,UAAU,CAAC,CAAC,CAAE,UAAU,CAAE,aAAc,CACvC,AAAI,EACF,EAAG,aAAa,gBAAiB,EAAS,SAAW,UAErD,EAAG,gBAAgB,mBAI3B,EAAM,UAAU,GAGT,EACJ,KACC,GAAU,EAAM,KAAK,GAAS,KAC9B,EAAI,GAAU,GAAE,IAAK,GAAO,OCrH7B,YACL,EAAiB,CAAE,YAAW,WACL,CACzB,MAAO,IAAgB,EAAI,CAAE,YAAW,YACrC,KACC,EAAI,CAAC,CAAE,OAAQ,CAAE,QAAU,CACzB,GAAM,CAAE,UAAW,GAAe,GAClC,MAAO,CACL,OAAQ,GAAK,KAGjB,EAAwB,WAevB,YACL,EAAiB,EACmB,CACpC,MAAO,GAAM,IAAM,CACjB,GAAM,GAAQ,GAAI,GAClB,EAAM,UAAU,CAAC,CAAE,YAAa,CAC9B,AAAI,EACF,EAAG,aAAa,gBAAiB,UAEjC,EAAG,gBAAgB,mBAIvB,GAAM,GAAU,GAAmB,cACnC,MAAI,OAAO,IAAY,YACd,EAGF,GAAiB,EAAS,GAC9B,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,OCvD7B,YACL,EAAiB,CAAE,YAAW,WACZ,CAGlB,GAAM,GAAU,EACb,KACC,EAAI,CAAC,CAAE,YAAa,GACpB,KAIE,EAAU,EACb,KACC,EAAU,IAAM,GAAiB,GAC9B,KACC,EAAI,CAAC,CAAE,YAAc,EACnB,IAAQ,EAAG,UACX,OAAQ,EAAG,UAAY,KAEzB,EAAwB,aAMhC,MAAO,GAAc,CAAC,EAAS,EAAS,IACrC,KACC,EAAI,CAAC,CAAC,EAAQ,CAAE,MAAK,UAAU,CAAE,OAAQ,CAAE,KAAK,KAAM,CAAE,cACtD,GAAS,KAAK,IAAI,EAAG,EACjB,KAAK,IAAI,EAAG,EAAS,EAAI,GACzB,KAAK,IAAI,EAAG,EAAS,EAAI,IAEtB,CACL,OAAQ,EAAM,EACd,SACA,OAAQ,EAAM,GAAU,KAG5B,EAAqB,CAAC,EAAG,IACvB,EAAE,SAAW,EAAE,QACf,EAAE,SAAW,EAAE,QACf,EAAE,SAAW,EAAE,SChDhB,YACL,EACqB,CACrB,GAAM,GAAU,SAAkB,cAAgB,CAChD,MAAO,EAAO,UAAU,GAAS,WAC/B,EAAM,aAAa,wBACnB,UAIJ,MAAO,GAAG,GAAG,GACV,KACC,GAAS,GAAS,EAAU,EAAO,UAChC,KACC,EAAM,KAGV,EAAU,EAAO,KAAK,IAAI,EAAG,EAAQ,SACrC,EAAI,GAAU,EACZ,MAAO,EAAO,QAAQ,GACtB,MAAO,CACL,OAAS,EAAM,aAAa,wBAC5B,QAAS,EAAM,aAAa,yBAC5B,OAAS,EAAM,aAAa,4BAGhC,EAAY,IAWX,YACL,EACgC,CAChC,MAAO,GAAM,IAAM,CACjB,GAAM,GAAQ,GAAI,GAClB,EAAM,UAAU,GAAW,CAGzB,OAAW,CAAC,EAAK,IAAU,QAAO,QAAQ,EAAQ,OAChD,SAAS,KAAK,aAAa,iBAAiB,IAAO,GAGrD,OAAS,GAAQ,EAAG,EAAQ,EAAO,OAAQ,IAAS,CAClD,GAAM,GAAQ,EAAO,GAAO,mBAC5B,AAAI,YAAiB,cACnB,GAAM,OAAS,EAAQ,QAAU,GAIrC,SAAS,YAAa,KAIxB,GAAM,GAAS,EAA8B,QAAS,GACtD,MAAO,IAAa,GACjB,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,OCpHpC,OAAwB,SAiCxB,YAAiB,EAAyB,CACxC,EAAG,aAAa,kBAAmB,IACnC,GAAM,GAAO,EAAG,UAChB,SAAG,gBAAgB,mBACZ,EAYF,YACL,CAAE,UACI,CACN,AAAI,WAAY,eACd,GAAI,GAA8B,GAAc,CAC9C,GAAI,YAAY,iDAAkD,CAChE,KAAM,GACJ,EAAG,aAAa,wBAChB,GAAQ,EACN,EAAG,aAAa,6BAInB,GAAG,UAAW,GAAM,EAAW,KAAK,MAEtC,KACC,EAAI,GAAM,CAER,AADgB,EAAG,QACX,UAEV,EAAM,GAAY,sBAEjB,UAAU,GCrCnB,YAAoB,EAAwB,CAC1C,GAAI,EAAK,OAAS,EAChB,MAAO,CAAC,IAGV,GAAM,CAAC,EAAM,GAAQ,CAAC,GAAG,GACtB,KAAK,CAAC,EAAG,IAAM,EAAE,OAAS,EAAE,QAC5B,IAAI,GAAO,EAAI,QAAQ,SAAU,KAGhC,EAAQ,EACZ,GAAI,IAAS,EACX,EAAQ,EAAK,WAEb,MAAO,EAAK,WAAW,KAAW,EAAK,WAAW,IAChD,IAGJ,MAAO,GAAK,IAAI,GAAO,EAAI,QAAQ,EAAK,MAAM,EAAG,GAAQ,KAcpD,YAAsB,EAAiC,CAC5D,GAAM,GAAS,SAAkB,YAAa,eAAgB,GAC9D,GAAI,EACF,MAAO,GAAG,GACL,CACL,GAAM,GAAS,KACf,MAAO,IAAW,GAAI,KAAI,cAAe,GAAQ,EAAO,OACrD,KACC,EAAI,GAAW,GAAW,EAAY,MAAO,GAC1C,IAAI,GAAQ,EAAK,eAEpB,GAAe,IACf,EAAI,GAAW,SAAS,YAAa,EAAS,eAAgB,MCU/D,YACL,CAAE,YAAW,YAAW,aAClB,CACN,GAAM,GAAS,KACf,GAAI,SAAS,WAAa,QACxB,OAGF,AAAI,qBAAuB,UACzB,SAAQ,kBAAoB,SAG5B,EAAU,OAAQ,gBACf,UAAU,IAAM,CACf,QAAQ,kBAAoB,UAKlC,GAAM,GAAU,GAAoC,kBACpD,AAAI,MAAO,IAAY,aACrB,GAAQ,KAAO,EAAQ,MAGzB,GAAM,GAAQ,KACX,KACC,EAAI,GAAS,EAAM,IAAI,GAAQ,GAAG,GAAI,KAAI,EAAM,EAAO,UACvD,EAAU,GAAQ,EAAsB,SAAS,KAAM,SACpD,KACC,EAAO,GAAM,CAAC,EAAG,SAAW,CAAC,EAAG,SAChC,EAAU,GAAM,CACd,GAAI,EAAG,iBAAkB,SAAS,CAChC,GAAM,GAAK,EAAG,OAAO,QAAQ,KAC7B,GAAI,GAAM,CAAC,EAAG,OAAQ,CACpB,GAAM,GAAM,GAAI,KAAI,EAAG,MAOvB,GAJA,EAAI,OAAS,GACb,EAAI,KAAO,GAIT,EAAI,WAAa,SAAS,UAC1B,EAAK,SAAS,EAAI,YAElB,SAAG,iBACI,EAAG,CACR,IAAK,GAAI,KAAI,EAAG,SAKxB,MAAO,QAIb,MAIE,EAAO,EAAyB,OAAQ,YAC3C,KACC,EAAO,GAAM,EAAG,QAAU,MAC1B,EAAI,GAAO,EACT,IAAK,GAAI,KAAI,SAAS,MACtB,OAAQ,EAAG,SAEb,MAIJ,EAAM,EAAO,GACV,KACC,EAAqB,CAAC,EAAG,IAAM,EAAE,IAAI,OAAS,EAAE,IAAI,MACpD,EAAI,CAAC,CAAE,SAAU,IAEhB,UAAU,GAGf,GAAM,GAAY,EACf,KACC,EAAwB,YACxB,EAAU,GAAO,GAAQ,EAAI,MAC1B,KACC,GAAW,IACT,IAAY,GACL,OAIb,MAIJ,EACG,KACC,GAAO,IAEN,UAAU,CAAC,CAAE,SAAU,CACtB,QAAQ,UAAU,GAAI,GAAI,GAAG,OAInC,GAAM,GAAM,GAAI,WAChB,EACG,KACC,EAAU,GAAO,EAAI,QACrB,EAAI,GAAO,EAAI,gBAAgB,EAAK,eAEnC,UAAU,GAGf,EACG,KACC,GAAK,IAEJ,UAAU,GAAe,CACxB,OAAW,KAAY,CAGrB,QACA,sBACA,oBACA,yBAGA,+BACA,gCACA,mCACA,2BACA,2BACA,GAAG,GAAQ,0BACP,CAAC,4BACD,IACH,CACD,GAAM,GAAS,GAAmB,GAC5B,EAAS,GAAmB,EAAU,GAC5C,AACE,MAAO,IAAW,aAClB,MAAO,IAAW,aAElB,EAAO,YAAY,MAM7B,EACG,KACC,GAAK,GACL,EAAI,IAAM,GAAoB,cAC9B,EAAU,GAAM,EAAG,GAAG,EAAY,SAAU,KAC5C,GAAU,GAAM,CACd,GAAM,GAAS,EAAE,UACjB,GAAI,EAAG,IAAK,CACV,OAAW,KAAQ,GAAG,oBACpB,EAAO,aAAa,EAAM,EAAG,aAAa,IAC5C,SAAG,YAAY,GAGR,GAAI,GAAW,GAAY,CAChC,EAAO,OAAS,IAAM,EAAS,iBAKjC,UAAO,YAAc,EAAG,YACxB,EAAG,YAAY,GACR,KAIV,YAGL,EAAM,EAAO,GACV,KACC,GAAO,IAEN,UAAU,CAAC,CAAE,MAAK,YAAa,CAC9B,AAAI,EAAI,MAAQ,CAAC,EACf,GAAgB,EAAI,MAEpB,OAAO,SAAS,EAAG,kBAAQ,IAAK,KAKxC,EACG,KACC,GAAU,GACV,GAAa,KACb,EAAwB,WAEvB,UAAU,CAAC,CAAE,YAAa,CACzB,QAAQ,aAAa,EAAQ,MAInC,EAAM,EAAO,GACV,KACC,GAAY,EAAG,GACf,EAAO,CAAC,CAAC,EAAG,KAAO,EAAE,IAAI,WAAa,EAAE,IAAI,UAC5C,EAAI,CAAC,CAAC,CAAE,KAAW,IAElB,UAAU,CAAC,CAAE,YAAa,CACzB,OAAO,SAAS,EAAG,kBAAQ,IAAK,KCtSxC,OAAuB,SCAvB,OAAuB,SAsChB,YACL,EAA2B,EACD,CAC1B,GAAM,GAAY,GAAI,QAAO,EAAO,UAAW,OACzC,EAAY,CAAC,EAAY,EAAc,IACpC,GAAG,4BAA+B,WAI3C,MAAO,AAAC,IAAkB,CACxB,EAAQ,EACL,QAAQ,gBAAiB,KACzB,OAGH,GAAM,GAAQ,GAAI,QAAO,MAAM,EAAO,cACpC,EACG,QAAQ,uBAAwB,QAChC,QAAQ,EAAW,QACnB,OAGL,MAAO,IACL,GACI,eAAW,GACX,GAED,QAAQ,EAAO,GACf,QAAQ,8BAA+B,OC5BzC,YAA0B,EAAuB,CACtD,MAAO,GACJ,MAAM,cACJ,IAAI,CAAC,EAAO,IAAU,EAAQ,EAC3B,EAAM,QAAQ,+BAAgC,MAC9C,GAEH,KAAK,IACP,QAAQ,kCAAmC,IAC3C,OCqCE,YACL,EAC+B,CAC/B,MAAO,GAAQ,OAAS,EAUnB,YACL,EAC+B,CAC/B,MAAO,GAAQ,OAAS,EAUnB,YACL,EACgC,CAChC,MAAO,GAAQ,OAAS,ECtE1B,YAA0B,CAAE,SAAQ,QAAkC,CAGpE,AAAI,EAAO,KAAK,SAAW,GAAK,EAAO,KAAK,KAAO,MACjD,GAAO,KAAO,CACZ,GAAY,wBAIZ,EAAO,YAAc,aACvB,GAAO,UAAY,GAAY,4BAQjC,GAAM,GAAyB,CAC7B,SANe,GAAY,0BAC1B,MAAM,WACN,OAAO,SAKR,YAAa,GAAQ,mBAIvB,MAAO,CAAE,SAAQ,OAAM,WAmBlB,YACL,EAAa,EACC,CACd,GAAM,GAAS,KACT,EAAS,GAAI,QAAO,GAGpB,EAAM,GAAI,GACV,EAAM,GAAY,EAAQ,CAAE,QAC/B,KACC,EAAI,GAAW,CACb,GAAI,GAAsB,GACxB,OAAW,KAAU,GAAQ,KAAK,MAChC,OAAW,KAAY,GACrB,EAAS,SAAW,GAAG,GAAI,KAAI,EAAS,SAAU,EAAO,QAE/D,MAAO,KAET,MAIJ,UAAK,GACF,KACC,EAAI,GAAS,EACX,KAAM,EACN,KAAM,GAAiB,OAGxB,UAAU,EAAI,KAAK,KAAK,IAGtB,CAAE,MAAK,OCtFT,aAAsC,CAC3C,GAAM,GAAS,KACT,EAAY,GAChB,GAAI,KAAI,mBAAoB,EAAO,OAI/B,EAAW,EACd,KACC,EAAI,GAAY,CACd,GAAM,CAAC,CAAE,GAAW,EAAO,KAAK,MAAM,eACtC,MAAO,GAAS,KAAK,CAAC,CAAE,UAAS,aAC/B,IAAY,GAAW,EAAQ,SAAS,KACpC,EAAS,MAKrB,EAAc,CAAC,EAAW,IACvB,KACC,EAAI,CAAC,CAAC,EAAU,KAAa,GAAI,KAAI,EAClC,OAAO,GAAW,IAAY,GAC9B,IAAI,GAAW,CACd,GAAG,GAAI,KAAI,MAAM,EAAQ,WAAY,EAAO,QAC5C,MAGJ,EAAU,GAAQ,EAAsB,SAAS,KAAM,SACpD,KACC,EAAO,GAAM,CAAC,EAAG,SAAW,CAAC,EAAG,SAChC,EAAU,GAAM,CACd,GAAI,EAAG,iBAAkB,SAAS,CAChC,GAAM,GAAK,EAAG,OAAO,QAAQ,KAC7B,GAAI,GAAM,CAAC,EAAG,QAAU,EAAK,IAAI,EAAG,MAClC,SAAG,iBACI,EAAG,EAAG,MAGjB,MAAO,KAET,EAAU,GAAO,CACf,GAAM,CAAE,WAAY,EAAK,IAAI,GAC7B,MAAO,IAAa,GAAI,KAAI,IACzB,KACC,EAAI,GAAW,CAEb,GAAM,GAAO,AADI,KACK,KAAK,QAAQ,EAAO,KAAM,IAChD,MAAO,GAAQ,SAAS,GACpB,GAAI,KAAI,MAAM,KAAW,IAAQ,EAAO,MACxC,GAAI,KAAI,WAOvB,UAAU,GAAO,GAAY,IAGlC,EAAc,CAAC,EAAW,IACvB,UAAU,CAAC,CAAC,EAAU,KAAa,CAlHxC,MAuHM,GAHA,AADc,EAAW,qBACnB,YAAY,GAAsB,EAAU,IAG9C,SAAS,aAAc,kBAAoB,KAAM,CACnD,GAAM,GAAS,MAAO,UAAP,cAAgB,UAAW,SACpC,EAAW,CAAC,EAAQ,QAAQ,SAAS,GAI3C,GADA,SAAS,aAAc,EAAU,gBAC7B,EACF,OAAW,KAAW,IAAqB,YACzC,EAAQ,OAAS,MC1CtB,YACL,EAAsB,CAAE,OACC,CACzB,GAAM,GAAK,gCAAU,YAAa,GAG5B,CAAE,gBAAiB,KACzB,AAAI,EAAa,IAAI,MACnB,GAAU,SAAU,IAGtB,GAAM,GAAS,EACZ,KACC,EAAO,IACP,GAAK,GACL,EAAI,IAAM,EAAa,IAAI,MAAQ,KAIvC,EAAO,UAAU,GAAS,CACxB,AAAI,GACF,GAAG,MAAQ,KAIf,GAAM,GAAS,GAAkB,GAC3B,EAAS,EACb,EAAU,EAAI,SACd,EAAU,EAAI,SAAS,KAAK,GAAM,IAClC,GAEC,KACC,EAAI,IAAM,EAAG,EAAG,QAChB,EAAU,IACV,KAIJ,MAAO,GAAc,CAAC,EAAQ,IAC3B,KACC,EAAI,CAAC,CAAC,EAAO,KAAY,EAAE,QAAO,WAClC,EAAY,IAYX,YACL,EAAsB,CAAE,MAAK,OACyB,CACtD,GAAM,GAAQ,GAAI,GAGlB,SACG,KACC,EAAwB,SACxB,EAAI,CAAC,CAAE,WAAiC,EACtC,KAAM,EACN,KAAM,MAGP,UAAU,EAAI,KAAK,KAAK,IAG7B,EACG,KACC,EAAwB,UAEvB,UAAU,CAAC,CAAE,WAAY,CACxB,AAAI,EACF,IAAU,SAAU,GACpB,EAAG,YAAc,IAEjB,EAAG,YAAc,GAAY,wBAKrC,EAAU,EAAG,KAAO,SACjB,KACC,GAAU,EAAM,KAAK,GAAS,MAE7B,UAAU,IAAM,EAAG,SAGjB,GAAiB,EAAI,CAAE,MAAK,QAChC,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,KCjG3B,YACL,EAAiB,CAAE,OAAqB,CAAE,UACL,CACrC,GAAM,GAAQ,GAAI,GACZ,EAAY,GAAqB,EAAG,eACvC,KACC,EAAO,UAIL,EAAO,EAAW,wBAAyB,GAC3C,EAAO,EAAW,uBAAwB,GAG1C,EAAS,EACZ,KACC,EAAO,IACP,GAAK,IAIT,SACG,KACC,GAAe,GACf,GAAU,IAET,UAAU,CAAC,CAAC,CAAE,SAAS,CAAE,YAAa,CACrC,GAAI,EACF,OAAQ,EAAM,YAGP,GACH,EAAK,YAAc,GAAY,sBAC/B,UAGG,GACH,EAAK,YAAc,GAAY,qBAC/B,cAIA,EAAK,YAAc,GACjB,sBACA,GAAM,EAAM,aAIlB,GAAK,YAAc,GAAY,+BAKvC,EACG,KACC,EAAI,IAAM,EAAK,UAAY,IAC3B,EAAU,CAAC,CAAE,WAAY,EACvB,EAAG,GAAG,EAAM,MAAM,EAAG,KACrB,EAAG,GAAG,EAAM,MAAM,KACf,KACC,GAAY,GACZ,GAAQ,GACR,EAAU,CAAC,CAAC,KAAW,EAAG,GAAG,QAIlC,UAAU,GAAU,EAAK,YACxB,GAAuB,KAWtB,AAPS,EACb,KACC,EAAO,IACP,EAAI,CAAC,CAAE,UAAW,IAKnB,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,KCxF3B,YACL,EAAkB,CAAE,UACK,CACzB,MAAO,GACJ,KACC,EAAI,CAAC,CAAE,WAAY,CACjB,GAAM,GAAM,KACZ,SAAI,KAAO,GACX,EAAI,aAAa,OAAO,KACxB,EAAI,aAAa,IAAI,IAAK,GACnB,CAAE,UAaV,YACL,EAAuB,EACa,CACpC,GAAM,GAAQ,GAAI,GAClB,SAAM,UAAU,CAAC,CAAE,SAAU,CAC3B,EAAG,aAAa,sBAAuB,EAAG,MAC1C,EAAG,KAAO,GAAG,MAIf,EAAU,EAAI,SACX,UAAU,GAAM,EAAG,kBAGf,GAAiB,EAAI,GACzB,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,KCpC3B,YACL,EAAiB,CAAE,OAAqB,CAAE,aACJ,CACtC,GAAM,GAAQ,GAAI,GAGZ,EAAS,GAAoB,gBAC7B,EAAS,EACb,EAAU,EAAO,WACjB,EAAU,EAAO,UAEhB,KACC,GAAU,IACV,EAAI,IAAM,EAAM,OAChB,KAIJ,SACG,KACC,GAAkB,GAClB,EAAI,CAAC,CAAC,CAAE,eAAe,KAAW,CAChC,GAAM,GAAQ,EAAM,MAAM,YAC1B,GAAI,kBAAa,SAAU,EAAM,EAAM,OAAS,GAAI,CAClD,GAAM,GAAO,EAAY,EAAY,OAAS,GAC9C,AAAI,EAAK,WAAW,EAAM,EAAM,OAAS,KACvC,GAAM,EAAM,OAAS,GAAK,OAE5B,GAAM,OAAS,EAEjB,MAAO,MAGR,UAAU,GAAS,EAAG,UAAY,EAChC,KAAK,IACL,QAAQ,MAAO,WAItB,EACG,KACC,EAAO,CAAC,CAAE,UAAW,IAAS,WAE7B,UAAU,GAAO,CAChB,OAAQ,EAAI,UAGL,aACH,AACE,EAAG,UAAU,QACb,EAAM,iBAAmB,EAAM,MAAM,QAErC,GAAM,MAAQ,EAAG,WACnB,SAYH,AAPS,EACb,KACC,EAAO,IACP,EAAI,CAAC,CAAE,UAAW,IAKnB,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,IAAO,EAAE,IAAK,MC5CjB,YACL,EAAiB,CAAE,SAAQ,aACI,CAC/B,GAAM,GAAS,KACf,GAAI,CACF,GAAM,GAAM,gCAAU,SAAU,EAAO,OACjC,EAAS,GAAkB,EAAK,GAGhC,EAAS,GAAoB,eAAgB,GAC7C,EAAS,GAAoB,gBAAiB,GAG9C,CAAE,MAAK,OAAQ,EACrB,EACG,KACC,EAAO,IACP,GAAO,EAAI,KAAK,EAAO,MACvB,GAAK,IAEJ,UAAU,EAAI,KAAK,KAAK,IAG7B,EACG,KACC,EAAO,CAAC,CAAE,UAAW,IAAS,WAE7B,UAAU,GAAO,CAChB,GAAM,GAAS,KACf,OAAQ,EAAI,UAGL,QACH,GAAI,IAAW,EAAO,CACpB,GAAM,GAAU,GAAI,KACpB,OAAW,KAAU,GACnB,sBAAuB,GACtB,CACD,GAAM,GAAU,EAAO,kBACvB,EAAQ,IAAI,EAAQ,WAClB,EAAQ,aAAa,mBAKzB,GAAI,EAAQ,KAAM,CAChB,GAAM,CAAC,CAAC,IAAS,CAAC,GAAG,GAAS,KAAK,CAAC,CAAC,CAAE,GAAI,CAAC,CAAE,KAAO,EAAI,GACzD,EAAK,QAIP,EAAI,QAEN,UAGG,aACA,MACH,GAAU,SAAU,IACpB,EAAM,OACN,UAGG,cACA,YACH,GAAI,MAAO,IAAW,YACpB,EAAM,YACD,CACL,GAAM,GAAM,CAAC,EAAO,GAAG,EACrB,wDACA,IAEI,EAAI,KAAK,IAAI,EACjB,MAAK,IAAI,EAAG,EAAI,QAAQ,IAAW,EAAI,OACrC,GAAI,OAAS,UAAY,GAAK,IAE9B,EAAI,QACR,EAAI,GAAG,QAIT,EAAI,QACJ,cAIA,AAAI,IAAU,MACZ,EAAM,WAKlB,EACG,KACC,EAAO,CAAC,CAAE,UAAW,IAAS,WAE7B,UAAU,GAAO,CAChB,OAAQ,EAAI,UAGL,QACA,QACA,IACH,EAAM,QACN,EAAM,SAGN,EAAI,QACJ,SAKV,GAAM,GAAU,GAAiB,EAAO,GAClC,EAAU,GAAkB,EAAQ,EAAQ,CAAE,WACpD,MAAO,GAAM,EAAQ,GAClB,KACC,GAGE,GAAG,GAAqB,eAAgB,GACrC,IAAI,GAAS,GAAiB,EAAO,CAAE,YAG1C,GAAG,GAAqB,iBAAkB,GACvC,IAAI,GAAS,GAAmB,EAAO,EAAQ,CAAE,uBAKnD,EAAP,CACA,SAAG,OAAS,GACL,ICpKJ,YACL,EAAiB,CAAE,SAAQ,aACa,CACxC,MAAO,GAAc,CACnB,EACA,EACG,KACC,EAAU,MACV,EAAO,GAAO,CAAC,CAAC,EAAI,aAAa,IAAI,SAGxC,KACC,EAAI,CAAC,CAAC,EAAO,KAAS,GAAuB,EAAM,OAAQ,IACzD,EAAI,aAAa,IAAI,OAEvB,EAAI,GAAM,CA1FhB,MA2FQ,GAAM,GAAQ,GAAI,KAGZ,EAAK,SAAS,mBAAmB,EAAI,WAAW,WACtD,OAAS,GAAO,EAAG,WAAY,EAAM,EAAO,EAAG,WAC7C,GAAI,KAAK,gBAAL,cAAoB,aAAc,CACpC,GAAM,GAAW,EAAK,YAChB,EAAW,EAAG,GACpB,AAAI,EAAS,OAAS,EAAS,QAC7B,EAAM,IAAI,EAAmB,GAKnC,OAAW,CAAC,EAAM,IAAS,GAAO,CAChC,GAAM,CAAE,cAAe,EAAE,OAAQ,KAAM,GACvC,EAAK,YAAY,GAAG,MAAM,KAAK,IAIjC,MAAO,CAAE,IAAK,EAAI,YCfnB,YACL,EAAiB,CAAE,YAAW,SACT,CACrB,GAAM,GAAS,EAAG,cACZ,EACJ,EAAO,UACP,EAAO,cAAe,UAGxB,MAAO,GAAc,CAAC,EAAO,IAC1B,KACC,EAAI,CAAC,CAAC,CAAE,SAAQ,UAAU,CAAE,OAAQ,CAAE,SACpC,GAAS,EACL,KAAK,IAAI,EAAQ,KAAK,IAAI,EAAG,EAAI,IACjC,EACG,CACL,SACA,OAAQ,GAAK,EAAS,KAG1B,EAAqB,CAAC,EAAG,IACvB,EAAE,SAAW,EAAE,QACf,EAAE,SAAW,EAAE,SA0BhB,YACL,EAAiB,EACe,CADf,QAAE,YAAF,EAAc,KAAd,EAAc,CAAZ,YAEnB,GAAM,GAAQ,EAAW,0BAA2B,GAC9C,CAAE,KAAM,GAAiB,GAC/B,MAAO,GAAM,IAAM,CACjB,GAAM,GAAQ,GAAI,GAClB,SACG,KACC,GAAU,EAAG,IACb,GAAe,IAEd,UAAU,CAGT,KAAK,CAAC,CAAE,UAAU,CAAE,OAAQ,IAAW,CACrC,EAAM,MAAM,OAAS,GAAG,EAAS,EAAI,MACrC,EAAG,MAAM,IAAY,GAAG,OAI1B,UAAW,CACT,EAAM,MAAM,OAAS,GACrB,EAAG,MAAM,IAAY,MAKtB,GAAa,EAAI,GACrB,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,OCvH7B,YACL,EAAc,EACW,CACzB,GAAI,MAAO,IAAS,YAAa,CAC/B,GAAM,GAAM,gCAAgC,KAAQ,IACpD,MAAO,IAGL,GAAqB,GAAG,qBACrB,KACC,EAAI,GAAY,EACd,QAAS,EAAQ,YAEnB,GAAe,KAInB,GAAkB,GACf,KACC,EAAI,GAAS,EACX,MAAO,EAAK,iBACZ,MAAO,EAAK,eAEd,GAAe,MAGlB,KACC,EAAI,CAAC,CAAC,EAAS,KAAW,OAAK,GAAY,SAI1C,CACL,GAAM,GAAM,gCAAgC,IAC5C,MAAO,IAAkB,GACtB,KACC,EAAI,GAAS,EACX,aAAc,EAAK,gBAErB,GAAe,MClDhB,YACL,EAAc,EACW,CACzB,GAAM,GAAM,WAAW,qBAAwB,mBAAmB,KAClE,MAAO,IAA2B,GAC/B,KACC,EAAI,CAAC,CAAE,aAAY,iBAAmB,EACpC,MAAO,EACP,MAAO,KAET,GAAe,KCYd,YACL,EACyB,CACzB,GAAM,CAAC,GAAQ,EAAI,MAAM,sBAAwB,GACjD,OAAQ,EAAK,mBAGN,SACH,GAAM,CAAC,CAAE,EAAM,GAAQ,EAAI,MAAM,uCACjC,MAAO,IAA2B,EAAM,OAGrC,SACH,GAAM,CAAC,CAAE,EAAM,GAAQ,EAAI,MAAM,sCACjC,MAAO,IAA2B,EAAM,WAIxC,MAAO,ICtBb,GAAI,IAgBG,YACL,EACoB,CACpB,MAAO,SAAW,EAAM,IAAM,CAC5B,GAAM,GAAS,SAAsB,WAAY,gBACjD,MAAI,GACK,EAAG,GAEH,GAAiB,EAAG,MACxB,KACC,EAAI,GAAS,SAAS,WAAY,EAAO,oBAG9C,KACC,GAAW,IAAM,GACjB,EAAO,GAAS,OAAO,KAAK,GAAO,OAAS,GAC5C,EAAI,GAAU,EAAE,WAChB,EAAY,KAWX,YACL,EAC+B,CAC/B,GAAM,GAAQ,EAAW,uBAAwB,GACjD,MAAO,GAAM,IAAM,CACjB,GAAM,GAAQ,GAAI,GAClB,SAAM,UAAU,CAAC,CAAE,WAAY,CAC7B,EAAM,YAAY,GAAkB,IACpC,EAAM,aAAa,gBAAiB,UAI/B,GAAY,GAChB,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,OCpC7B,YACL,EAAiB,CAAE,YAAW,WACZ,CAClB,MAAO,IAAiB,SAAS,MAC9B,KACC,EAAU,IAAM,GAAgB,EAAI,CAAE,UAAS,eAC/C,EAAI,CAAC,CAAE,OAAQ,CAAE,QACR,EACL,OAAQ,GAAK,MAGjB,EAAwB,WAevB,YACL,EAAiB,EACY,CAC7B,MAAO,GAAM,IAAM,CACjB,GAAM,GAAQ,GAAI,GAClB,SAAM,UAAU,CAGd,KAAK,CAAE,UAAU,CACf,AAAI,EACF,EAAG,aAAa,gBAAiB,UAEjC,EAAG,gBAAgB,kBAIvB,UAAW,CACT,EAAG,gBAAgB,oBAMrB,IAAQ,0BACJ,EAAG,CAAE,OAAQ,KACb,GAAU,EAAI,IAEjB,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,OChC7B,YACL,EAAiB,CAAE,YAAW,WACD,CAC7B,GAAM,GAAQ,GAAI,KAGZ,EAAU,EAA+B,cAAe,GAC9D,OAAW,KAAU,GAAS,CAC5B,GAAM,GAAK,mBAAmB,EAAO,KAAK,UAAU,IAC9C,EAAS,GAAmB,QAAQ,OAC1C,AAAI,MAAO,IAAW,aACpB,EAAM,IAAI,EAAQ,GAItB,GAAM,GAAU,EACb,KACC,EAAI,GAAU,GAAK,EAAO,SAgF9B,MAAO,AA5EY,IAAiB,SAAS,MAC1C,KACC,EAAwB,UAGxB,EAAU,GAAQ,EAAM,IAAM,CAC5B,GAAI,GAA4B,GAChC,MAAO,GAAG,CAAC,GAAG,GAAO,OAAO,CAAC,EAAO,CAAC,EAAQ,KAAY,CACvD,KAAO,EAAK,QAEN,AADS,EAAM,IAAI,EAAK,EAAK,OAAS,IACjC,SAAW,EAAO,SACzB,EAAK,MAOT,GAAI,GAAS,EAAO,UACpB,KAAO,CAAC,GAAU,EAAO,eACvB,EAAS,EAAO,cAChB,EAAS,EAAO,UAIlB,MAAO,GAAM,IACX,CAAC,GAAG,EAAO,CAAC,GAAG,EAAM,IAAS,UAC9B,IAED,GAAI,SAEN,KAGC,EAAI,GAAS,GAAI,KAAI,CAAC,GAAG,GAAO,KAAK,CAAC,CAAC,CAAE,GAAI,CAAC,CAAE,KAAO,EAAI,KAG3D,EAAU,GAAS,EAAc,CAAC,EAAW,IAC1C,KACC,GAAK,CAAC,CAAC,EAAM,GAAO,CAAC,CAAE,OAAQ,CAAE,KAAK,QAAQ,KAAY,CACxD,GAAM,GAAO,EAAI,EAAK,QAAU,KAAK,MAAM,EAAK,QAGhD,KAAO,EAAK,QAAQ,CAClB,GAAM,CAAC,CAAE,GAAU,EAAK,GACxB,GAAI,EAAS,EAAS,GAAK,EACzB,EAAO,CAAC,GAAG,EAAM,EAAK,aAEtB,OAKJ,KAAO,EAAK,QAAQ,CAClB,GAAM,CAAC,CAAE,GAAU,EAAK,EAAK,OAAS,GACtC,GAAI,EAAS,GAAU,GAAK,CAAC,EAC3B,EAAO,CAAC,EAAK,MAAQ,GAAG,OAExB,OAKJ,MAAO,CAAC,EAAM,IACb,CAAC,GAAI,CAAC,GAAG,KACZ,EAAqB,CAAC,EAAG,IACvB,EAAE,KAAO,EAAE,IACX,EAAE,KAAO,EAAE,SAUtB,KACC,EAAI,CAAC,CAAC,EAAM,KAAW,EACrB,KAAM,EAAK,IAAI,CAAC,CAAC,KAAU,GAC3B,KAAM,EAAK,IAAI,CAAC,CAAC,KAAU,MAI7B,EAAU,CAAE,KAAM,GAAI,KAAM,KAC5B,GAAY,EAAG,GACf,EAAI,CAAC,CAAC,EAAG,KAGH,EAAE,KAAK,OAAS,EAAE,KAAK,OAClB,CACL,KAAM,EAAE,KAAK,MAAM,KAAK,IAAI,EAAG,EAAE,KAAK,OAAS,GAAI,EAAE,KAAK,QAC1D,KAAM,IAKD,CACL,KAAM,EAAE,KAAK,MAAM,IACnB,KAAM,EAAE,KAAK,MAAM,EAAG,EAAE,KAAK,OAAS,EAAE,KAAK,WAiBlD,YACL,EAAiB,CAAE,YAAW,WACU,CACxC,MAAO,GAAM,IAAM,CACjB,GAAM,GAAQ,GAAI,GAClB,SAAM,UAAU,CAAC,CAAE,OAAM,UAAW,CAGlC,OAAW,CAAC,IAAW,GACrB,EAAO,gBAAgB,iBACvB,EAAO,UAAU,OACf,wBAKJ,OAAW,CAAC,EAAO,CAAC,KAAY,GAAK,UACnC,EAAO,aAAa,gBAAiB,QACrC,EAAO,UAAU,OACf,uBACA,IAAU,EAAK,OAAS,KAM1B,GAAQ,wBACV,EACG,KACC,GAAU,EAAM,KAAK,GAAS,KAC9B,EAAwB,UACxB,GAAa,KACb,GAAe,IAEd,UAAU,CAAC,CAAC,CAAE,CAAE,WAAY,CAC3B,GAAM,GAAM,KAGN,EAAS,EAAK,EAAK,OAAS,GAClC,GAAI,GAAU,EAAO,OAAQ,CAC3B,GAAM,CAAC,GAAU,EACX,CAAE,QAAS,GAAI,KAAI,EAAO,MAChC,AAAI,EAAI,OAAS,GACf,GAAI,KAAO,EACX,QAAQ,aAAa,GAAI,GAAI,GAAG,UAKlC,GAAI,KAAO,GACX,QAAQ,aAAa,GAAI,GAAI,GAAG,OAKnC,GAAqB,EAAI,CAAE,YAAW,YAC1C,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,OCxN7B,YACL,EAAkB,CAAE,YAAW,QAAO,WACf,CAGvB,GAAM,GAAa,EAChB,KACC,EAAI,CAAC,CAAE,OAAQ,CAAE,QAAU,GAC3B,GAAY,EAAG,GACf,EAAI,CAAC,CAAC,EAAG,KAAO,EAAI,GAAK,EAAI,GAC7B,KAIE,EAAU,EACb,KACC,EAAI,CAAC,CAAE,YAAa,IAIxB,MAAO,GAAc,CAAC,EAAS,IAC5B,KACC,EAAI,CAAC,CAAC,EAAQ,KAAe,CAAE,IAAU,IACzC,IACA,GAAU,EAAQ,KAAK,GAAK,KAC5B,GAAQ,IACR,GAAO,CAAE,MAAO,MAChB,EAAI,GAAW,EAAE,aAchB,YACL,EAAiB,CAAE,YAAW,UAAS,QAAO,WACZ,CAClC,GAAM,GAAQ,GAAI,GAClB,SAAM,UAAU,CAGd,KAAK,CAAE,UAAU,CACf,AAAI,EACF,GAAG,aAAa,gBAAiB,UACjC,EAAG,aAAa,WAAY,MAC5B,EAAG,QAEH,GAAG,gBAAgB,iBACnB,EAAG,gBAAgB,cAKvB,UAAW,CACT,EAAG,MAAM,IAAM,GACf,EAAG,aAAa,gBAAiB,UACjC,EAAG,gBAAgB,eAKvB,EACG,KACC,GAAU,EAAM,KAAK,GAAQ,GAAI,GAAS,KAC1C,EAAwB,WAEvB,UAAU,CAAC,CAAE,YAAa,CACzB,EAAG,MAAM,IAAM,GAAG,EAAS,SAI1B,GAAe,EAAI,CAAE,YAAW,QAAO,YAC3C,KACC,EAAI,GAAS,EAAM,KAAK,IACxB,EAAS,IAAM,EAAM,YACrB,EAAI,GAAU,GAAE,IAAK,GAAO,KCjH3B,YACL,CAAE,YAAW,WACP,CACN,EACG,KACC,EAAU,IAAM,EAAG,GAAG,EACpB,mCAEF,EAAI,GAAM,CACR,EAAG,cAAgB,GACnB,EAAG,QAAU,KAEf,GAAS,GAAM,EAAU,EAAI,UAC1B,KACC,GAAU,IAAM,EAAG,aAAa,kBAChC,EAAM,KAGV,GAAe,IAEd,UAAU,CAAC,CAAC,EAAI,KAAY,CAC3B,EAAG,gBAAgB,iBACf,GACF,GAAG,QAAU,MC5BvB,aAAkC,CAChC,MAAO,qBAAqB,KAAK,UAAU,WAkBtC,YACL,CAAE,aACI,CACN,EACG,KACC,EAAU,IAAM,EAAG,GAAG,EAAY,yBAClC,EAAI,GAAM,EAAG,gBAAgB,sBAC7B,EAAO,IACP,GAAS,GAAM,EAAU,EAAI,cAC1B,KACC,EAAM,MAIT,UAAU,GAAM,CACf,GAAM,GAAM,EAAG,UAGf,AAAI,IAAQ,EACV,EAAG,UAAY,EAGN,EAAM,EAAG,eAAiB,EAAG,cACtC,GAAG,UAAY,EAAM,KClCxB,YACL,CAAE,YAAW,WACP,CACN,EAAc,CAAC,GAAY,UAAW,IACnC,KACC,EAAI,CAAC,CAAC,EAAQ,KAAY,GAAU,CAAC,GACrC,EAAU,GAAU,EAAG,GACpB,KACC,GAAM,EAAS,IAAM,OAGzB,GAAe,IAEd,UAAU,CAAC,CAAC,EAAQ,CAAE,OAAQ,CAAE,SAAU,CACzC,GAAI,EACF,SAAS,KAAK,aAAa,gBAAiB,QAC5C,SAAS,KAAK,MAAM,IAAM,IAAI,UACzB,CACL,GAAM,GAAQ,GAAK,SAAS,SAAS,KAAK,MAAM,IAAK,IACrD,SAAS,KAAK,gBAAgB,iBAC9B,SAAS,KAAK,MAAM,IAAM,GACtB,GACF,OAAO,SAAS,EAAG,MC1D/B,AAAK,OAAO,SACV,QAAO,QAAU,SAAU,EAAa,CACtC,GAAM,GAA2B,GACjC,OAAW,KAAO,QAAO,KAAK,GAE5B,EAAK,KAAK,CAAC,EAAK,EAAI,KAGtB,MAAO,KAIX,AAAK,OAAO,QACV,QAAO,OAAS,SAAU,EAAa,CACrC,GAAM,GAAiB,GACvB,OAAW,KAAO,QAAO,KAAK,GAE5B,EAAK,KAAK,EAAI,IAGhB,MAAO,KAMX,AAAI,MAAO,UAAY,aAGhB,SAAQ,UAAU,UACrB,SAAQ,UAAU,SAAW,SAC3B,EAA8B,EACxB,CACN,AAAI,MAAO,IAAM,SACf,MAAK,WAAa,EAAE,KACpB,KAAK,UAAY,EAAE,KAEnB,MAAK,WAAa,EAClB,KAAK,UAAY,KAKlB,QAAQ,UAAU,aACrB,SAAQ,UAAU,YAAc,YAC3B,EACG,CACN,GAAM,GAAS,KAAK,WACpB,GAAI,EAAQ,CACV,AAAI,EAAM,SAAW,GACnB,EAAO,YAAY,MAGrB,OAAS,GAAI,EAAM,OAAS,EAAG,GAAK,EAAG,IAAK,CAC1C,GAAI,GAAO,EAAM,GACjB,AAAI,MAAO,IAAS,SAClB,EAAO,SAAS,eAAe,GACxB,EAAK,YACZ,EAAK,WAAW,YAAY,GAG9B,AAAK,EAGH,EAAO,aAAa,KAAK,gBAAkB,GAF3C,EAAO,aAAa,EAAM,W9LEtC,SAAS,gBAAgB,UAAU,OAAO,SAC1C,SAAS,gBAAgB,UAAU,IAAI,MAGvC,GAAM,IAAY,KACZ,GAAY,KACZ,GAAY,KACZ,GAAY,KAGZ,GAAY,KACZ,GAAY,GAAW,sBACvB,GAAY,GAAW,uBACvB,GAAY,KAGZ,GAAS,KACT,GAAS,SAAS,MAAM,UAAU,UACpC,gCAAU,QAAS,GACnB,GAAI,KAAI,2BAA4B,GAAO,OAE3C,GAGE,GAAS,GAAI,GACnB,GAAiB,CAAE,YAGnB,AAAI,GAAQ,uBACV,GAAoB,CAAE,aAAW,aAAW,eAxH9C,OA2HA,AAAI,QAAO,UAAP,eAAgB,YAAa,QAC/B,KAGF,EAAM,GAAW,IACd,KACC,GAAM,MAEL,UAAU,IAAM,CACf,GAAU,SAAU,IACpB,GAAU,SAAU,MAI1B,GACG,KACC,EAAO,CAAC,CAAE,UAAW,IAAS,WAE7B,UAAU,GAAO,CAChB,OAAQ,EAAI,UAGL,QACA,IACH,GAAM,GAAO,GAAmB,oBAChC,AAAI,MAAO,IAAS,aAClB,EAAK,QACP,UAGG,QACA,IACH,GAAM,GAAO,GAAmB,oBAChC,AAAI,MAAO,IAAS,aAClB,EAAK,QACP,SAKV,GAAmB,CAAE,aAAW,aAChC,GAAe,CAAE,eACjB,GAAgB,CAAE,aAAW,aAG7B,GAAM,IAAU,GAAY,GAAoB,UAAW,CAAE,eACvD,GAAQ,GACX,KACC,EAAI,IAAM,GAAoB,SAC9B,EAAU,GAAM,GAAU,EAAI,CAAE,aAAW,cAC3C,EAAY,IAIV,GAAW,EAGf,GAAG,GAAqB,UACrB,IAAI,GAAM,GAAY,EAAI,CAAE,aAG/B,GAAG,GAAqB,UACrB,IAAI,GAAM,GAAY,EAAI,CAAE,aAAW,WAAS,YAGnD,GAAG,GAAqB,WACrB,IAAI,GAAM,GAAa,IAG1B,GAAG,GAAqB,UACrB,IAAI,GAAM,GAAY,EAAI,CAAE,UAAQ,gBAGvC,GAAG,GAAqB,UACrB,IAAI,GAAM,GAAY,KAIrB,GAAW,EAAM,IAAM,EAG3B,GAAG,GAAqB,WACrB,IAAI,GAAM,GAAa,EAAI,CAAE,WAAS,aAGzC,GAAG,GAAqB,WACrB,IAAI,GAAM,GAAQ,oBACf,GAAoB,EAAI,CAAE,UAAQ,eAClC,GAIN,GAAG,GAAqB,gBACrB,IAAI,GAAM,GAAiB,EAAI,CAAE,aAAW,cAG/C,GAAG,GAAqB,WACrB,IAAI,GAAM,EAAG,aAAa,kBAAoB,aAC3C,GAAG,GAAS,IAAM,GAAa,EAAI,CAAE,aAAW,WAAS,YACzD,GAAG,GAAS,IAAM,GAAa,EAAI,CAAE,aAAW,WAAS,aAI/D,GAAG,GAAqB,QACrB,IAAI,GAAM,GAAU,EAAI,CAAE,aAAW,cAGxC,GAAG,GAAqB,OACrB,IAAI,GAAM,GAAqB,EAAI,CAAE,aAAW,cAGnD,GAAG,GAAqB,OACrB,IAAI,GAAM,GAAe,EAAI,CAAE,aAAW,WAAS,SAAO,gBAIzD,GAAa,GAChB,KACC,EAAU,IAAM,IAChB,GAAU,IACV,EAAY,IAIhB,GAAW,YAMX,OAAO,UAAa,GACpB,OAAO,UAAa,GACpB,OAAO,QAAa,GACpB,OAAO,UAAa,GACpB,OAAO,UAAa,GACpB,OAAO,QAAa,GACpB,OAAO,QAAa,GACpB,OAAO,OAAa,GACpB,OAAO,OAAa,GACpB,OAAO,WAAa", + "names": [] +} diff --git a/site/assets/javascripts/lunr/min/lunr.ar.min.js b/site/assets/javascripts/lunr/min/lunr.ar.min.js new file mode 100644 index 0000000000..248ddc5d14 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.ar.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ar=function(){this.pipeline.reset(),this.pipeline.add(e.ar.trimmer,e.ar.stopWordFilter,e.ar.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ar.stemmer))},e.ar.wordCharacters="ء-ٛٱـ",e.ar.trimmer=e.trimmerSupport.generateTrimmer(e.ar.wordCharacters),e.Pipeline.registerFunction(e.ar.trimmer,"trimmer-ar"),e.ar.stemmer=function(){var e=this;return e.result=!1,e.preRemoved=!1,e.sufRemoved=!1,e.pre={pre1:"ف ك ب و س ل ن ا ي ت",pre2:"ال لل",pre3:"بال وال فال تال كال ولل",pre4:"فبال كبال وبال وكال"},e.suf={suf1:"ه ك ت ن ا ي",suf2:"نك نه ها وك يا اه ون ين تن تم نا وا ان كم كن ني نن ما هم هن تك ته ات يه",suf3:"تين كهم نيه نهم ونه وها يهم ونا ونك وني وهم تكم تنا تها تني تهم كما كها ناه نكم هنا تان يها",suf4:"كموه ناها ونني ونهم تكما تموه تكاه كماه ناكم ناهم نيها وننا"},e.patterns=JSON.parse('{"pt43":[{"pt":[{"c":"ا","l":1}]},{"pt":[{"c":"ا,ت,ن,ي","l":0}],"mPt":[{"c":"ف","l":0,"m":1},{"c":"ع","l":1,"m":2},{"c":"ل","l":2,"m":3}]},{"pt":[{"c":"و","l":2}],"mPt":[{"c":"ف","l":0,"m":0},{"c":"ع","l":1,"m":1},{"c":"ل","l":2,"m":3}]},{"pt":[{"c":"ا","l":2}]},{"pt":[{"c":"ي","l":2}],"mPt":[{"c":"ف","l":0,"m":0},{"c":"ع","l":1,"m":1},{"c":"ا","l":2},{"c":"ل","l":3,"m":3}]},{"pt":[{"c":"م","l":0}]}],"pt53":[{"pt":[{"c":"ت","l":0},{"c":"ا","l":2}]},{"pt":[{"c":"ا,ن,ت,ي","l":0},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ت","l":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"ا","l":0},{"c":"ا","l":2}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ع","l":2,"m":3},{"c":"ل","l":3,"m":4},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"ا","l":0},{"c":"ا","l":3}],"mPt":[{"c":"ف","l":0,"m":1},{"c":"ع","l":1,"m":2},{"c":"ل","l":2,"m":4}]},{"pt":[{"c":"ا","l":3},{"c":"ن","l":4}]},{"pt":[{"c":"ت","l":0},{"c":"ي","l":3}]},{"pt":[{"c":"م","l":0},{"c":"و","l":3}]},{"pt":[{"c":"ا","l":1},{"c":"و","l":3}]},{"pt":[{"c":"و","l":1},{"c":"ا","l":2}]},{"pt":[{"c":"م","l":0},{"c":"ا","l":3}]},{"pt":[{"c":"م","l":0},{"c":"ي","l":3}]},{"pt":[{"c":"ا","l":2},{"c":"ن","l":3}]},{"pt":[{"c":"م","l":0},{"c":"ن","l":1}],"mPt":[{"c":"ا","l":0},{"c":"ن","l":1},{"c":"ف","l":2,"m":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"م","l":0},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ت","l":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"م","l":0},{"c":"ا","l":2}]},{"pt":[{"c":"م","l":1},{"c":"ا","l":3}]},{"pt":[{"c":"ي,ت,ا,ن","l":0},{"c":"ت","l":1}],"mPt":[{"c":"ف","l":0,"m":2},{"c":"ع","l":1,"m":3},{"c":"ا","l":2},{"c":"ل","l":3,"m":4}]},{"pt":[{"c":"ت,ي,ا,ن","l":0},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ت","l":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"ا","l":2},{"c":"ي","l":3}]},{"pt":[{"c":"ا,ي,ت,ن","l":0},{"c":"ن","l":1}],"mPt":[{"c":"ا","l":0},{"c":"ن","l":1},{"c":"ف","l":2,"m":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"ا","l":3},{"c":"ء","l":4}]}],"pt63":[{"pt":[{"c":"ا","l":0},{"c":"ت","l":2},{"c":"ا","l":4}]},{"pt":[{"c":"ا,ت,ن,ي","l":0},{"c":"س","l":1},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"س","l":1},{"c":"ت","l":2},{"c":"ف","l":3,"m":3},{"c":"ع","l":4,"m":4},{"c":"ا","l":5},{"c":"ل","l":6,"m":5}]},{"pt":[{"c":"ا,ن,ت,ي","l":0},{"c":"و","l":3}]},{"pt":[{"c":"م","l":0},{"c":"س","l":1},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"س","l":1},{"c":"ت","l":2},{"c":"ف","l":3,"m":3},{"c":"ع","l":4,"m":4},{"c":"ا","l":5},{"c":"ل","l":6,"m":5}]},{"pt":[{"c":"ي","l":1},{"c":"ي","l":3},{"c":"ا","l":4},{"c":"ء","l":5}]},{"pt":[{"c":"ا","l":0},{"c":"ن","l":1},{"c":"ا","l":4}]}],"pt54":[{"pt":[{"c":"ت","l":0}]},{"pt":[{"c":"ا,ي,ت,ن","l":0}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ع","l":2,"m":2},{"c":"ل","l":3,"m":3},{"c":"ر","l":4,"m":4},{"c":"ا","l":5},{"c":"ر","l":6,"m":4}]},{"pt":[{"c":"م","l":0}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ع","l":2,"m":2},{"c":"ل","l":3,"m":3},{"c":"ر","l":4,"m":4},{"c":"ا","l":5},{"c":"ر","l":6,"m":4}]},{"pt":[{"c":"ا","l":2}]},{"pt":[{"c":"ا","l":0},{"c":"ن","l":2}]}],"pt64":[{"pt":[{"c":"ا","l":0},{"c":"ا","l":4}]},{"pt":[{"c":"م","l":0},{"c":"ت","l":1}]}],"pt73":[{"pt":[{"c":"ا","l":0},{"c":"س","l":1},{"c":"ت","l":2},{"c":"ا","l":5}]}],"pt75":[{"pt":[{"c":"ا","l":0},{"c":"ا","l":5}]}]}'),e.execArray=["cleanWord","removeDiacritics","cleanAlef","removeStopWords","normalizeHamzaAndAlef","removeStartWaw","removePre432","removeEndTaa","wordCheck"],e.stem=function(){var r=0;for(e.result=!1,e.preRemoved=!1,e.sufRemoved=!1;r=0)return!0},e.normalizeHamzaAndAlef=function(){return e.word=e.word.replace("ؤ","ء"),e.word=e.word.replace("ئ","ء"),e.word=e.word.replace(/([\u0627])\1+/gi,"ا"),!1},e.removeEndTaa=function(){return!(e.word.length>2)||(e.word=e.word.replace(/[\u0627]$/,""),e.word=e.word.replace("ة",""),!1)},e.removeStartWaw=function(){return e.word.length>3&&"و"==e.word[0]&&"و"==e.word[1]&&(e.word=e.word.slice(1)),!1},e.removePre432=function(){var r=e.word;if(e.word.length>=7){var t=new RegExp("^("+e.pre.pre4.split(" ").join("|")+")");e.word=e.word.replace(t,"")}if(e.word==r&&e.word.length>=6){var c=new RegExp("^("+e.pre.pre3.split(" ").join("|")+")");e.word=e.word.replace(c,"")}if(e.word==r&&e.word.length>=5){var l=new RegExp("^("+e.pre.pre2.split(" ").join("|")+")");e.word=e.word.replace(l,"")}return r!=e.word&&(e.preRemoved=!0),!1},e.patternCheck=function(r){for(var t=0;t3){var t=new RegExp("^("+e.pre.pre1.split(" ").join("|")+")");e.word=e.word.replace(t,"")}return r!=e.word&&(e.preRemoved=!0),!1},e.removeSuf1=function(){var r=e.word;if(0==e.sufRemoved&&e.word.length>3){var t=new RegExp("("+e.suf.suf1.split(" ").join("|")+")$");e.word=e.word.replace(t,"")}return r!=e.word&&(e.sufRemoved=!0),!1},e.removeSuf432=function(){var r=e.word;if(e.word.length>=6){var t=new RegExp("("+e.suf.suf4.split(" ").join("|")+")$");e.word=e.word.replace(t,"")}if(e.word==r&&e.word.length>=5){var c=new RegExp("("+e.suf.suf3.split(" ").join("|")+")$");e.word=e.word.replace(c,"")}if(e.word==r&&e.word.length>=4){var l=new RegExp("("+e.suf.suf2.split(" ").join("|")+")$");e.word=e.word.replace(l,"")}return r!=e.word&&(e.sufRemoved=!0),!1},e.wordCheck=function(){for(var r=(e.word,[e.removeSuf432,e.removeSuf1,e.removePre1]),t=0,c=!1;e.word.length>=7&&!e.result&&t=f.limit)return;f.cursor++}for(;!f.out_grouping(w,97,248);){if(f.cursor>=f.limit)return;f.cursor++}d=f.cursor,d=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(c,32),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del();break;case 2:f.in_grouping_b(p,97,229)&&f.slice_del()}}function t(){var e,r=f.limit-f.cursor;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.find_among_b(l,4)?(f.bra=f.cursor,f.limit_backward=e,f.cursor=f.limit-r,f.cursor>f.limit_backward&&(f.cursor--,f.bra=f.cursor,f.slice_del())):f.limit_backward=e)}function s(){var e,r,i,n=f.limit-f.cursor;if(f.ket=f.cursor,f.eq_s_b(2,"st")&&(f.bra=f.cursor,f.eq_s_b(2,"ig")&&f.slice_del()),f.cursor=f.limit-n,f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(m,5),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del(),i=f.limit-f.cursor,t(),f.cursor=f.limit-i;break;case 2:f.slice_from("løs")}}function o(){var e;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.out_grouping_b(w,97,248)?(f.bra=f.cursor,u=f.slice_to(u),f.limit_backward=e,f.eq_v_b(u)&&f.slice_del()):f.limit_backward=e)}var a,d,u,c=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],l=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],w=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],p=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],f=new i;this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var r=f.cursor;return e(),f.limit_backward=r,f.cursor=f.limit,n(),f.cursor=f.limit,t(),f.cursor=f.limit,s(),f.cursor=f.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.de.min.js b/site/assets/javascripts/lunr/min/lunr.de.min.js new file mode 100644 index 0000000000..f3b5c108c9 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.de.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `German` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.de=function(){this.pipeline.reset(),this.pipeline.add(e.de.trimmer,e.de.stopWordFilter,e.de.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.de.stemmer))},e.de.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.de.trimmer=e.trimmerSupport.generateTrimmer(e.de.wordCharacters),e.Pipeline.registerFunction(e.de.trimmer,"trimmer-de"),e.de.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,n){return!(!v.eq_s(1,e)||(v.ket=v.cursor,!v.in_grouping(p,97,252)))&&(v.slice_from(r),v.cursor=n,!0)}function i(){for(var r,n,i,s,t=v.cursor;;)if(r=v.cursor,v.bra=r,v.eq_s(1,"ß"))v.ket=v.cursor,v.slice_from("ss");else{if(r>=v.limit)break;v.cursor=r+1}for(v.cursor=t;;)for(n=v.cursor;;){if(i=v.cursor,v.in_grouping(p,97,252)){if(s=v.cursor,v.bra=s,e("u","U",i))break;if(v.cursor=s,e("y","Y",i))break}if(i>=v.limit)return void(v.cursor=n);v.cursor=i+1}}function s(){for(;!v.in_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}for(;!v.out_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}return!1}function t(){m=v.limit,l=m;var e=v.cursor+3;0<=e&&e<=v.limit&&(d=e,s()||(m=v.cursor,m=v.limit)return;v.cursor++}}}function c(){return m<=v.cursor}function u(){return l<=v.cursor}function a(){var e,r,n,i,s=v.limit-v.cursor;if(v.ket=v.cursor,(e=v.find_among_b(w,7))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:v.slice_del(),v.ket=v.cursor,v.eq_s_b(1,"s")&&(v.bra=v.cursor,v.eq_s_b(3,"nis")&&v.slice_del());break;case 3:v.in_grouping_b(g,98,116)&&v.slice_del()}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(f,4))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:if(v.in_grouping_b(k,98,116)){var t=v.cursor-3;v.limit_backward<=t&&t<=v.limit&&(v.cursor=t,v.slice_del())}}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(_,8))&&(v.bra=v.cursor,u()))switch(e){case 1:v.slice_del(),v.ket=v.cursor,v.eq_s_b(2,"ig")&&(v.bra=v.cursor,r=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-r,u()&&v.slice_del()));break;case 2:n=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-n,v.slice_del());break;case 3:if(v.slice_del(),v.ket=v.cursor,i=v.limit-v.cursor,!v.eq_s_b(2,"er")&&(v.cursor=v.limit-i,!v.eq_s_b(2,"en")))break;v.bra=v.cursor,c()&&v.slice_del();break;case 4:v.slice_del(),v.ket=v.cursor,e=v.find_among_b(b,2),e&&(v.bra=v.cursor,u()&&1==e&&v.slice_del())}}var d,l,m,h=[new r("",-1,6),new r("U",0,2),new r("Y",0,1),new r("ä",0,3),new r("ö",0,4),new r("ü",0,5)],w=[new r("e",-1,2),new r("em",-1,1),new r("en",-1,2),new r("ern",-1,1),new r("er",-1,1),new r("s",-1,3),new r("es",5,2)],f=[new r("en",-1,1),new r("er",-1,1),new r("st",-1,2),new r("est",2,1)],b=[new r("ig",-1,1),new r("lich",-1,1)],_=[new r("end",-1,1),new r("ig",-1,2),new r("ung",-1,1),new r("lich",-1,3),new r("isch",-1,2),new r("ik",-1,2),new r("heit",-1,3),new r("keit",-1,4)],p=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32,8],g=[117,30,5],k=[117,30,4],v=new n;this.setCurrent=function(e){v.setCurrent(e)},this.getCurrent=function(){return v.getCurrent()},this.stem=function(){var e=v.cursor;return i(),v.cursor=e,t(),v.limit_backward=e,v.cursor=v.limit,a(),v.cursor=v.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.de.stemmer,"stemmer-de"),e.de.stopWordFilter=e.generateStopWordFilter("aber alle allem allen aller alles als also am an ander andere anderem anderen anderer anderes anderm andern anderr anders auch auf aus bei bin bis bist da damit dann das dasselbe dazu daß dein deine deinem deinen deiner deines dem demselben den denn denselben der derer derselbe derselben des desselben dessen dich die dies diese dieselbe dieselben diesem diesen dieser dieses dir doch dort du durch ein eine einem einen einer eines einig einige einigem einigen einiger einiges einmal er es etwas euch euer eure eurem euren eurer eures für gegen gewesen hab habe haben hat hatte hatten hier hin hinter ich ihm ihn ihnen ihr ihre ihrem ihren ihrer ihres im in indem ins ist jede jedem jeden jeder jedes jene jenem jenen jener jenes jetzt kann kein keine keinem keinen keiner keines können könnte machen man manche manchem manchen mancher manches mein meine meinem meinen meiner meines mich mir mit muss musste nach nicht nichts noch nun nur ob oder ohne sehr sein seine seinem seinen seiner seines selbst sich sie sind so solche solchem solchen solcher solches soll sollte sondern sonst um und uns unse unsem unsen unser unses unter viel vom von vor war waren warst was weg weil weiter welche welchem welchen welcher welches wenn werde werden wie wieder will wir wird wirst wo wollen wollte während würde würden zu zum zur zwar zwischen über".split(" ")),e.Pipeline.registerFunction(e.de.stopWordFilter,"stopWordFilter-de")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.du.min.js b/site/assets/javascripts/lunr/min/lunr.du.min.js new file mode 100644 index 0000000000..49a0f3f0ac --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.du.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Dutch` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");console.warn('[Lunr Languages] Please use the "nl" instead of the "du". The "nl" code is the standard code for Dutch language, and "du" will be removed in the next major versions.'),e.du=function(){this.pipeline.reset(),this.pipeline.add(e.du.trimmer,e.du.stopWordFilter,e.du.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.du.stemmer))},e.du.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.du.trimmer=e.trimmerSupport.generateTrimmer(e.du.wordCharacters),e.Pipeline.registerFunction(e.du.trimmer,"trimmer-du"),e.du.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){for(var e,r,i,o=C.cursor;;){if(C.bra=C.cursor,e=C.find_among(b,11))switch(C.ket=C.cursor,e){case 1:C.slice_from("a");continue;case 2:C.slice_from("e");continue;case 3:C.slice_from("i");continue;case 4:C.slice_from("o");continue;case 5:C.slice_from("u");continue;case 6:if(C.cursor>=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(r=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=r);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=r;else if(n(r))break}else if(n(r))break}function n(e){return C.cursor=e,e>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,f=_,t()||(_=C.cursor,_<3&&(_=3),t()||(f=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var e;;)if(C.bra=C.cursor,e=C.find_among(p,3))switch(C.ket=C.cursor,e){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return f<=C.cursor}function a(){var e=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-e,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var e;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.slice_del(),w=!0,a())))}function m(){var e;u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.eq_s_b(3,"gem")||(C.cursor=C.limit-e,C.slice_del(),a())))}function d(){var e,r,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,e=C.find_among_b(h,5))switch(C.bra=C.cursor,e){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(z,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(r=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-r,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,e=C.find_among_b(k,6))switch(C.bra=C.cursor,e){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(j,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var f,_,w,b=[new r("",-1,6),new r("á",0,1),new r("ä",0,1),new r("é",0,2),new r("ë",0,2),new r("í",0,3),new r("ï",0,3),new r("ó",0,4),new r("ö",0,4),new r("ú",0,5),new r("ü",0,5)],p=[new r("",-1,3),new r("I",0,2),new r("Y",0,1)],g=[new r("dd",-1,-1),new r("kk",-1,-1),new r("tt",-1,-1)],h=[new r("ene",-1,2),new r("se",-1,3),new r("en",-1,2),new r("heden",2,1),new r("s",-1,3)],k=[new r("end",-1,1),new r("ig",-1,2),new r("ing",-1,1),new r("lijk",-1,3),new r("baar",-1,4),new r("bar",-1,5)],v=[new r("aa",-1,-1),new r("ee",-1,-1),new r("oo",-1,-1),new r("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(e){C.setCurrent(e)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var r=C.cursor;return e(),C.cursor=r,o(),C.limit_backward=r,C.cursor=C.limit,d(),C.cursor=C.limit_backward,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.du.stemmer,"stemmer-du"),e.du.stopWordFilter=e.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),e.Pipeline.registerFunction(e.du.stopWordFilter,"stopWordFilter-du")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.es.min.js b/site/assets/javascripts/lunr/min/lunr.es.min.js new file mode 100644 index 0000000000..2989d34265 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.es.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Spanish` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,s){"function"==typeof define&&define.amd?define(s):"object"==typeof exports?module.exports=s():s()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.es=function(){this.pipeline.reset(),this.pipeline.add(e.es.trimmer,e.es.stopWordFilter,e.es.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.es.stemmer))},e.es.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.es.trimmer=e.trimmerSupport.generateTrimmer(e.es.wordCharacters),e.Pipeline.registerFunction(e.es.trimmer,"trimmer-es"),e.es.stemmer=function(){var s=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,n=new function(){function e(){if(A.out_grouping(x,97,252)){for(;!A.in_grouping(x,97,252);){if(A.cursor>=A.limit)return!0;A.cursor++}return!1}return!0}function n(){if(A.in_grouping(x,97,252)){var s=A.cursor;if(e()){if(A.cursor=s,!A.in_grouping(x,97,252))return!0;for(;!A.out_grouping(x,97,252);){if(A.cursor>=A.limit)return!0;A.cursor++}}return!1}return!0}function i(){var s,r=A.cursor;if(n()){if(A.cursor=r,!A.out_grouping(x,97,252))return;if(s=A.cursor,e()){if(A.cursor=s,!A.in_grouping(x,97,252)||A.cursor>=A.limit)return;A.cursor++}}g=A.cursor}function a(){for(;!A.in_grouping(x,97,252);){if(A.cursor>=A.limit)return!1;A.cursor++}for(;!A.out_grouping(x,97,252);){if(A.cursor>=A.limit)return!1;A.cursor++}return!0}function t(){var e=A.cursor;g=A.limit,p=g,v=g,i(),A.cursor=e,a()&&(p=A.cursor,a()&&(v=A.cursor))}function o(){for(var e;;){if(A.bra=A.cursor,e=A.find_among(k,6))switch(A.ket=A.cursor,e){case 1:A.slice_from("a");continue;case 2:A.slice_from("e");continue;case 3:A.slice_from("i");continue;case 4:A.slice_from("o");continue;case 5:A.slice_from("u");continue;case 6:if(A.cursor>=A.limit)break;A.cursor++;continue}break}}function u(){return g<=A.cursor}function w(){return p<=A.cursor}function c(){return v<=A.cursor}function m(){var e;if(A.ket=A.cursor,A.find_among_b(y,13)&&(A.bra=A.cursor,(e=A.find_among_b(q,11))&&u()))switch(e){case 1:A.bra=A.cursor,A.slice_from("iendo");break;case 2:A.bra=A.cursor,A.slice_from("ando");break;case 3:A.bra=A.cursor,A.slice_from("ar");break;case 4:A.bra=A.cursor,A.slice_from("er");break;case 5:A.bra=A.cursor,A.slice_from("ir");break;case 6:A.slice_del();break;case 7:A.eq_s_b(1,"u")&&A.slice_del()}}function l(e,s){if(!c())return!0;A.slice_del(),A.ket=A.cursor;var r=A.find_among_b(e,s);return r&&(A.bra=A.cursor,1==r&&c()&&A.slice_del()),!1}function d(e){return!c()||(A.slice_del(),A.ket=A.cursor,A.eq_s_b(2,e)&&(A.bra=A.cursor,c()&&A.slice_del()),!1)}function b(){var e;if(A.ket=A.cursor,e=A.find_among_b(S,46)){switch(A.bra=A.cursor,e){case 1:if(!c())return!1;A.slice_del();break;case 2:if(d("ic"))return!1;break;case 3:if(!c())return!1;A.slice_from("log");break;case 4:if(!c())return!1;A.slice_from("u");break;case 5:if(!c())return!1;A.slice_from("ente");break;case 6:if(!w())return!1;A.slice_del(),A.ket=A.cursor,e=A.find_among_b(C,4),e&&(A.bra=A.cursor,c()&&(A.slice_del(),1==e&&(A.ket=A.cursor,A.eq_s_b(2,"at")&&(A.bra=A.cursor,c()&&A.slice_del()))));break;case 7:if(l(P,3))return!1;break;case 8:if(l(F,3))return!1;break;case 9:if(d("at"))return!1}return!0}return!1}function f(){var e,s;if(A.cursor>=g&&(s=A.limit_backward,A.limit_backward=g,A.ket=A.cursor,e=A.find_among_b(W,12),A.limit_backward=s,e)){if(A.bra=A.cursor,1==e){if(!A.eq_s_b(1,"u"))return!1;A.slice_del()}return!0}return!1}function _(){var e,s,r,n;if(A.cursor>=g&&(s=A.limit_backward,A.limit_backward=g,A.ket=A.cursor,e=A.find_among_b(L,96),A.limit_backward=s,e))switch(A.bra=A.cursor,e){case 1:r=A.limit-A.cursor,A.eq_s_b(1,"u")?(n=A.limit-A.cursor,A.eq_s_b(1,"g")?A.cursor=A.limit-n:A.cursor=A.limit-r):A.cursor=A.limit-r,A.bra=A.cursor;case 2:A.slice_del()}}function h(){var e,s;if(A.ket=A.cursor,e=A.find_among_b(z,8))switch(A.bra=A.cursor,e){case 1:u()&&A.slice_del();break;case 2:u()&&(A.slice_del(),A.ket=A.cursor,A.eq_s_b(1,"u")&&(A.bra=A.cursor,s=A.limit-A.cursor,A.eq_s_b(1,"g")&&(A.cursor=A.limit-s,u()&&A.slice_del())))}}var v,p,g,k=[new s("",-1,6),new s("á",0,1),new s("é",0,2),new s("í",0,3),new s("ó",0,4),new s("ú",0,5)],y=[new s("la",-1,-1),new s("sela",0,-1),new s("le",-1,-1),new s("me",-1,-1),new s("se",-1,-1),new s("lo",-1,-1),new s("selo",5,-1),new s("las",-1,-1),new s("selas",7,-1),new s("les",-1,-1),new s("los",-1,-1),new s("selos",10,-1),new s("nos",-1,-1)],q=[new s("ando",-1,6),new s("iendo",-1,6),new s("yendo",-1,7),new s("ándo",-1,2),new s("iéndo",-1,1),new s("ar",-1,6),new s("er",-1,6),new s("ir",-1,6),new s("ár",-1,3),new s("ér",-1,4),new s("ír",-1,5)],C=[new s("ic",-1,-1),new s("ad",-1,-1),new s("os",-1,-1),new s("iv",-1,1)],P=[new s("able",-1,1),new s("ible",-1,1),new s("ante",-1,1)],F=[new s("ic",-1,1),new s("abil",-1,1),new s("iv",-1,1)],S=[new s("ica",-1,1),new s("ancia",-1,2),new s("encia",-1,5),new s("adora",-1,2),new s("osa",-1,1),new s("ista",-1,1),new s("iva",-1,9),new s("anza",-1,1),new s("logía",-1,3),new s("idad",-1,8),new s("able",-1,1),new s("ible",-1,1),new s("ante",-1,2),new s("mente",-1,7),new s("amente",13,6),new s("ación",-1,2),new s("ución",-1,4),new s("ico",-1,1),new s("ismo",-1,1),new s("oso",-1,1),new s("amiento",-1,1),new s("imiento",-1,1),new s("ivo",-1,9),new s("ador",-1,2),new s("icas",-1,1),new s("ancias",-1,2),new s("encias",-1,5),new s("adoras",-1,2),new s("osas",-1,1),new s("istas",-1,1),new s("ivas",-1,9),new s("anzas",-1,1),new s("logías",-1,3),new s("idades",-1,8),new s("ables",-1,1),new s("ibles",-1,1),new s("aciones",-1,2),new s("uciones",-1,4),new s("adores",-1,2),new s("antes",-1,2),new s("icos",-1,1),new s("ismos",-1,1),new s("osos",-1,1),new s("amientos",-1,1),new s("imientos",-1,1),new s("ivos",-1,9)],W=[new s("ya",-1,1),new s("ye",-1,1),new s("yan",-1,1),new s("yen",-1,1),new s("yeron",-1,1),new s("yendo",-1,1),new s("yo",-1,1),new s("yas",-1,1),new s("yes",-1,1),new s("yais",-1,1),new s("yamos",-1,1),new s("yó",-1,1)],L=[new s("aba",-1,2),new s("ada",-1,2),new s("ida",-1,2),new s("ara",-1,2),new s("iera",-1,2),new s("ía",-1,2),new s("aría",5,2),new s("ería",5,2),new s("iría",5,2),new s("ad",-1,2),new s("ed",-1,2),new s("id",-1,2),new s("ase",-1,2),new s("iese",-1,2),new s("aste",-1,2),new s("iste",-1,2),new s("an",-1,2),new s("aban",16,2),new s("aran",16,2),new s("ieran",16,2),new s("ían",16,2),new s("arían",20,2),new s("erían",20,2),new s("irían",20,2),new s("en",-1,1),new s("asen",24,2),new s("iesen",24,2),new s("aron",-1,2),new s("ieron",-1,2),new s("arán",-1,2),new s("erán",-1,2),new s("irán",-1,2),new s("ado",-1,2),new s("ido",-1,2),new s("ando",-1,2),new s("iendo",-1,2),new s("ar",-1,2),new s("er",-1,2),new s("ir",-1,2),new s("as",-1,2),new s("abas",39,2),new s("adas",39,2),new s("idas",39,2),new s("aras",39,2),new s("ieras",39,2),new s("ías",39,2),new s("arías",45,2),new s("erías",45,2),new s("irías",45,2),new s("es",-1,1),new s("ases",49,2),new s("ieses",49,2),new s("abais",-1,2),new s("arais",-1,2),new s("ierais",-1,2),new s("íais",-1,2),new s("aríais",55,2),new s("eríais",55,2),new s("iríais",55,2),new s("aseis",-1,2),new s("ieseis",-1,2),new s("asteis",-1,2),new s("isteis",-1,2),new s("áis",-1,2),new s("éis",-1,1),new s("aréis",64,2),new s("eréis",64,2),new s("iréis",64,2),new s("ados",-1,2),new s("idos",-1,2),new s("amos",-1,2),new s("ábamos",70,2),new s("áramos",70,2),new s("iéramos",70,2),new s("íamos",70,2),new s("aríamos",74,2),new s("eríamos",74,2),new s("iríamos",74,2),new s("emos",-1,1),new s("aremos",78,2),new s("eremos",78,2),new s("iremos",78,2),new s("ásemos",78,2),new s("iésemos",78,2),new s("imos",-1,2),new s("arás",-1,2),new s("erás",-1,2),new s("irás",-1,2),new s("ís",-1,2),new s("ará",-1,2),new s("erá",-1,2),new s("irá",-1,2),new s("aré",-1,2),new s("eré",-1,2),new s("iré",-1,2),new s("ió",-1,2)],z=[new s("a",-1,1),new s("e",-1,2),new s("o",-1,1),new s("os",-1,1),new s("á",-1,1),new s("é",-1,2),new s("í",-1,1),new s("ó",-1,1)],x=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,4,10],A=new r;this.setCurrent=function(e){A.setCurrent(e)},this.getCurrent=function(){return A.getCurrent()},this.stem=function(){var e=A.cursor;return t(),A.limit_backward=e,A.cursor=A.limit,m(),A.cursor=A.limit,b()||(A.cursor=A.limit,f()||(A.cursor=A.limit,_())),A.cursor=A.limit,h(),A.cursor=A.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.es.stemmer,"stemmer-es"),e.es.stopWordFilter=e.generateStopWordFilter("a al algo algunas algunos ante antes como con contra cual cuando de del desde donde durante e el ella ellas ellos en entre era erais eran eras eres es esa esas ese eso esos esta estaba estabais estaban estabas estad estada estadas estado estados estamos estando estar estaremos estará estarán estarás estaré estaréis estaría estaríais estaríamos estarían estarías estas este estemos esto estos estoy estuve estuviera estuvierais estuvieran estuvieras estuvieron estuviese estuvieseis estuviesen estuvieses estuvimos estuviste estuvisteis estuviéramos estuviésemos estuvo está estábamos estáis están estás esté estéis estén estés fue fuera fuerais fueran fueras fueron fuese fueseis fuesen fueses fui fuimos fuiste fuisteis fuéramos fuésemos ha habida habidas habido habidos habiendo habremos habrá habrán habrás habré habréis habría habríais habríamos habrían habrías habéis había habíais habíamos habían habías han has hasta hay haya hayamos hayan hayas hayáis he hemos hube hubiera hubierais hubieran hubieras hubieron hubiese hubieseis hubiesen hubieses hubimos hubiste hubisteis hubiéramos hubiésemos hubo la las le les lo los me mi mis mucho muchos muy más mí mía mías mío míos nada ni no nos nosotras nosotros nuestra nuestras nuestro nuestros o os otra otras otro otros para pero poco por porque que quien quienes qué se sea seamos sean seas seremos será serán serás seré seréis sería seríais seríamos serían serías seáis sido siendo sin sobre sois somos son soy su sus suya suyas suyo suyos sí también tanto te tendremos tendrá tendrán tendrás tendré tendréis tendría tendríais tendríamos tendrían tendrías tened tenemos tenga tengamos tengan tengas tengo tengáis tenida tenidas tenido tenidos teniendo tenéis tenía teníais teníamos tenían tenías ti tiene tienen tienes todo todos tu tus tuve tuviera tuvierais tuvieran tuvieras tuvieron tuviese tuvieseis tuviesen tuvieses tuvimos tuviste tuvisteis tuviéramos tuviésemos tuvo tuya tuyas tuyo tuyos tú un una uno unos vosotras vosotros vuestra vuestras vuestro vuestros y ya yo él éramos".split(" ")),e.Pipeline.registerFunction(e.es.stopWordFilter,"stopWordFilter-es")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.fi.min.js b/site/assets/javascripts/lunr/min/lunr.fi.min.js new file mode 100644 index 0000000000..29f5dfcea8 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.fi.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Finnish` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(i,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():e()(i.lunr)}(this,function(){return function(i){if(void 0===i)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===i.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");i.fi=function(){this.pipeline.reset(),this.pipeline.add(i.fi.trimmer,i.fi.stopWordFilter,i.fi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(i.fi.stemmer))},i.fi.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",i.fi.trimmer=i.trimmerSupport.generateTrimmer(i.fi.wordCharacters),i.Pipeline.registerFunction(i.fi.trimmer,"trimmer-fi"),i.fi.stemmer=function(){var e=i.stemmerSupport.Among,r=i.stemmerSupport.SnowballProgram,n=new function(){function i(){f=A.limit,d=f,n()||(f=A.cursor,n()||(d=A.cursor))}function n(){for(var i;;){if(i=A.cursor,A.in_grouping(W,97,246))break;if(A.cursor=i,i>=A.limit)return!0;A.cursor++}for(A.cursor=i;!A.out_grouping(W,97,246);){if(A.cursor>=A.limit)return!0;A.cursor++}return!1}function t(){return d<=A.cursor}function s(){var i,e;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(h,10)){switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:if(!A.in_grouping_b(x,97,246))return;break;case 2:if(!t())return}A.slice_del()}else A.limit_backward=e}function o(){var i,e,r;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(v,9))switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:r=A.limit-A.cursor,A.eq_s_b(1,"k")||(A.cursor=A.limit-r,A.slice_del());break;case 2:A.slice_del(),A.ket=A.cursor,A.eq_s_b(3,"kse")&&(A.bra=A.cursor,A.slice_from("ksi"));break;case 3:A.slice_del();break;case 4:A.find_among_b(p,6)&&A.slice_del();break;case 5:A.find_among_b(g,6)&&A.slice_del();break;case 6:A.find_among_b(j,2)&&A.slice_del()}else A.limit_backward=e}function l(){return A.find_among_b(q,7)}function a(){return A.eq_s_b(1,"i")&&A.in_grouping_b(L,97,246)}function u(){var i,e,r;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(C,30)){switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:if(!A.eq_s_b(1,"a"))return;break;case 2:case 9:if(!A.eq_s_b(1,"e"))return;break;case 3:if(!A.eq_s_b(1,"i"))return;break;case 4:if(!A.eq_s_b(1,"o"))return;break;case 5:if(!A.eq_s_b(1,"ä"))return;break;case 6:if(!A.eq_s_b(1,"ö"))return;break;case 7:if(r=A.limit-A.cursor,!l()&&(A.cursor=A.limit-r,!A.eq_s_b(2,"ie"))){A.cursor=A.limit-r;break}if(A.cursor=A.limit-r,A.cursor<=A.limit_backward){A.cursor=A.limit-r;break}A.cursor--,A.bra=A.cursor;break;case 8:if(!A.in_grouping_b(W,97,246)||!A.out_grouping_b(W,97,246))return}A.slice_del(),k=!0}else A.limit_backward=e}function c(){var i,e,r;if(A.cursor>=d)if(e=A.limit_backward,A.limit_backward=d,A.ket=A.cursor,i=A.find_among_b(P,14)){if(A.bra=A.cursor,A.limit_backward=e,1==i){if(r=A.limit-A.cursor,A.eq_s_b(2,"po"))return;A.cursor=A.limit-r}A.slice_del()}else A.limit_backward=e}function m(){var i;A.cursor>=f&&(i=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,A.find_among_b(F,2)?(A.bra=A.cursor,A.limit_backward=i,A.slice_del()):A.limit_backward=i)}function w(){var i,e,r,n,t,s;if(A.cursor>=f){if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,A.eq_s_b(1,"t")&&(A.bra=A.cursor,r=A.limit-A.cursor,A.in_grouping_b(W,97,246)&&(A.cursor=A.limit-r,A.slice_del(),A.limit_backward=e,n=A.limit-A.cursor,A.cursor>=d&&(A.cursor=d,t=A.limit_backward,A.limit_backward=A.cursor,A.cursor=A.limit-n,A.ket=A.cursor,i=A.find_among_b(S,2))))){if(A.bra=A.cursor,A.limit_backward=t,1==i){if(s=A.limit-A.cursor,A.eq_s_b(2,"po"))return;A.cursor=A.limit-s}return void A.slice_del()}A.limit_backward=e}}function _(){var i,e,r,n;if(A.cursor>=f){for(i=A.limit_backward,A.limit_backward=f,e=A.limit-A.cursor,l()&&(A.cursor=A.limit-e,A.ket=A.cursor,A.cursor>A.limit_backward&&(A.cursor--,A.bra=A.cursor,A.slice_del())),A.cursor=A.limit-e,A.ket=A.cursor,A.in_grouping_b(y,97,228)&&(A.bra=A.cursor,A.out_grouping_b(W,97,246)&&A.slice_del()),A.cursor=A.limit-e,A.ket=A.cursor,A.eq_s_b(1,"j")&&(A.bra=A.cursor,r=A.limit-A.cursor,A.eq_s_b(1,"o")?A.slice_del():(A.cursor=A.limit-r,A.eq_s_b(1,"u")&&A.slice_del())),A.cursor=A.limit-e,A.ket=A.cursor,A.eq_s_b(1,"o")&&(A.bra=A.cursor,A.eq_s_b(1,"j")&&A.slice_del()),A.cursor=A.limit-e,A.limit_backward=i;;){if(n=A.limit-A.cursor,A.out_grouping_b(W,97,246)){A.cursor=A.limit-n;break}if(A.cursor=A.limit-n,A.cursor<=A.limit_backward)return;A.cursor--}A.ket=A.cursor,A.cursor>A.limit_backward&&(A.cursor--,A.bra=A.cursor,b=A.slice_to(),A.eq_v_b(b)&&A.slice_del())}}var k,b,d,f,h=[new e("pa",-1,1),new e("sti",-1,2),new e("kaan",-1,1),new e("han",-1,1),new e("kin",-1,1),new e("hän",-1,1),new e("kään",-1,1),new e("ko",-1,1),new e("pä",-1,1),new e("kö",-1,1)],p=[new e("lla",-1,-1),new e("na",-1,-1),new e("ssa",-1,-1),new e("ta",-1,-1),new e("lta",3,-1),new e("sta",3,-1)],g=[new e("llä",-1,-1),new e("nä",-1,-1),new e("ssä",-1,-1),new e("tä",-1,-1),new e("ltä",3,-1),new e("stä",3,-1)],j=[new e("lle",-1,-1),new e("ine",-1,-1)],v=[new e("nsa",-1,3),new e("mme",-1,3),new e("nne",-1,3),new e("ni",-1,2),new e("si",-1,1),new e("an",-1,4),new e("en",-1,6),new e("än",-1,5),new e("nsä",-1,3)],q=[new e("aa",-1,-1),new e("ee",-1,-1),new e("ii",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1),new e("ää",-1,-1),new e("öö",-1,-1)],C=[new e("a",-1,8),new e("lla",0,-1),new e("na",0,-1),new e("ssa",0,-1),new e("ta",0,-1),new e("lta",4,-1),new e("sta",4,-1),new e("tta",4,9),new e("lle",-1,-1),new e("ine",-1,-1),new e("ksi",-1,-1),new e("n",-1,7),new e("han",11,1),new e("den",11,-1,a),new e("seen",11,-1,l),new e("hen",11,2),new e("tten",11,-1,a),new e("hin",11,3),new e("siin",11,-1,a),new e("hon",11,4),new e("hän",11,5),new e("hön",11,6),new e("ä",-1,8),new e("llä",22,-1),new e("nä",22,-1),new e("ssä",22,-1),new e("tä",22,-1),new e("ltä",26,-1),new e("stä",26,-1),new e("ttä",26,9)],P=[new e("eja",-1,-1),new e("mma",-1,1),new e("imma",1,-1),new e("mpa",-1,1),new e("impa",3,-1),new e("mmi",-1,1),new e("immi",5,-1),new e("mpi",-1,1),new e("impi",7,-1),new e("ejä",-1,-1),new e("mmä",-1,1),new e("immä",10,-1),new e("mpä",-1,1),new e("impä",12,-1)],F=[new e("i",-1,-1),new e("j",-1,-1)],S=[new e("mma",-1,1),new e("imma",0,-1)],y=[17,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8],W=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],L=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],x=[17,97,24,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],A=new r;this.setCurrent=function(i){A.setCurrent(i)},this.getCurrent=function(){return A.getCurrent()},this.stem=function(){var e=A.cursor;return i(),k=!1,A.limit_backward=e,A.cursor=A.limit,s(),A.cursor=A.limit,o(),A.cursor=A.limit,u(),A.cursor=A.limit,c(),A.cursor=A.limit,k?(m(),A.cursor=A.limit):(A.cursor=A.limit,w(),A.cursor=A.limit),_(),!0}};return function(i){return"function"==typeof i.update?i.update(function(i){return n.setCurrent(i),n.stem(),n.getCurrent()}):(n.setCurrent(i),n.stem(),n.getCurrent())}}(),i.Pipeline.registerFunction(i.fi.stemmer,"stemmer-fi"),i.fi.stopWordFilter=i.generateStopWordFilter("ei eivät emme en et ette että he heidän heidät heihin heille heillä heiltä heissä heistä heitä hän häneen hänelle hänellä häneltä hänen hänessä hänestä hänet häntä itse ja johon joiden joihin joiksi joilla joille joilta joina joissa joista joita joka joksi jolla jolle jolta jona jonka jos jossa josta jota jotka kanssa keiden keihin keiksi keille keillä keiltä keinä keissä keistä keitä keneen keneksi kenelle kenellä keneltä kenen kenenä kenessä kenestä kenet ketkä ketkä ketä koska kuin kuka kun me meidän meidät meihin meille meillä meiltä meissä meistä meitä mihin miksi mikä mille millä miltä minkä minkä minua minulla minulle minulta minun minussa minusta minut minuun minä minä missä mistä mitkä mitä mukaan mutta ne niiden niihin niiksi niille niillä niiltä niin niin niinä niissä niistä niitä noiden noihin noiksi noilla noille noilta noin noina noissa noista noita nuo nyt näiden näihin näiksi näille näillä näiltä näinä näissä näistä näitä nämä ole olemme olen olet olette oli olimme olin olisi olisimme olisin olisit olisitte olisivat olit olitte olivat olla olleet ollut on ovat poikki se sekä sen siihen siinä siitä siksi sille sillä sillä siltä sinua sinulla sinulle sinulta sinun sinussa sinusta sinut sinuun sinä sinä sitä tai te teidän teidät teihin teille teillä teiltä teissä teistä teitä tuo tuohon tuoksi tuolla tuolle tuolta tuon tuona tuossa tuosta tuota tähän täksi tälle tällä tältä tämä tämän tänä tässä tästä tätä vaan vai vaikka yli".split(" ")),i.Pipeline.registerFunction(i.fi.stopWordFilter,"stopWordFilter-fi")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.fr.min.js b/site/assets/javascripts/lunr/min/lunr.fr.min.js new file mode 100644 index 0000000000..68cd0094ae --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.fr.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `French` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.fr=function(){this.pipeline.reset(),this.pipeline.add(e.fr.trimmer,e.fr.stopWordFilter,e.fr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.fr.stemmer))},e.fr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.fr.trimmer=e.trimmerSupport.generateTrimmer(e.fr.wordCharacters),e.Pipeline.registerFunction(e.fr.trimmer,"trimmer-fr"),e.fr.stemmer=function(){var r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,s){return!(!W.eq_s(1,e)||(W.ket=W.cursor,!W.in_grouping(F,97,251)))&&(W.slice_from(r),W.cursor=s,!0)}function i(e,r,s){return!!W.eq_s(1,e)&&(W.ket=W.cursor,W.slice_from(r),W.cursor=s,!0)}function n(){for(var r,s;;){if(r=W.cursor,W.in_grouping(F,97,251)){if(W.bra=W.cursor,s=W.cursor,e("u","U",r))continue;if(W.cursor=s,e("i","I",r))continue;if(W.cursor=s,i("y","Y",r))continue}if(W.cursor=r,W.bra=r,!e("y","Y",r)){if(W.cursor=r,W.eq_s(1,"q")&&(W.bra=W.cursor,i("u","U",r)))continue;if(W.cursor=r,r>=W.limit)return;W.cursor++}}}function t(){for(;!W.in_grouping(F,97,251);){if(W.cursor>=W.limit)return!0;W.cursor++}for(;!W.out_grouping(F,97,251);){if(W.cursor>=W.limit)return!0;W.cursor++}return!1}function u(){var e=W.cursor;if(q=W.limit,g=q,p=q,W.in_grouping(F,97,251)&&W.in_grouping(F,97,251)&&W.cursor=W.limit){W.cursor=q;break}W.cursor++}while(!W.in_grouping(F,97,251))}q=W.cursor,W.cursor=e,t()||(g=W.cursor,t()||(p=W.cursor))}function o(){for(var e,r;;){if(r=W.cursor,W.bra=r,!(e=W.find_among(h,4)))break;switch(W.ket=W.cursor,e){case 1:W.slice_from("i");break;case 2:W.slice_from("u");break;case 3:W.slice_from("y");break;case 4:if(W.cursor>=W.limit)return;W.cursor++}}}function c(){return q<=W.cursor}function a(){return g<=W.cursor}function l(){return p<=W.cursor}function w(){var e,r;if(W.ket=W.cursor,e=W.find_among_b(C,43)){switch(W.bra=W.cursor,e){case 1:if(!l())return!1;W.slice_del();break;case 2:if(!l())return!1;W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"ic")&&(W.bra=W.cursor,l()?W.slice_del():W.slice_from("iqU"));break;case 3:if(!l())return!1;W.slice_from("log");break;case 4:if(!l())return!1;W.slice_from("u");break;case 5:if(!l())return!1;W.slice_from("ent");break;case 6:if(!c())return!1;if(W.slice_del(),W.ket=W.cursor,e=W.find_among_b(z,6))switch(W.bra=W.cursor,e){case 1:l()&&(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"at")&&(W.bra=W.cursor,l()&&W.slice_del()));break;case 2:l()?W.slice_del():a()&&W.slice_from("eux");break;case 3:l()&&W.slice_del();break;case 4:c()&&W.slice_from("i")}break;case 7:if(!l())return!1;if(W.slice_del(),W.ket=W.cursor,e=W.find_among_b(y,3))switch(W.bra=W.cursor,e){case 1:l()?W.slice_del():W.slice_from("abl");break;case 2:l()?W.slice_del():W.slice_from("iqU");break;case 3:l()&&W.slice_del()}break;case 8:if(!l())return!1;if(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"at")&&(W.bra=W.cursor,l()&&(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"ic")))){W.bra=W.cursor,l()?W.slice_del():W.slice_from("iqU");break}break;case 9:W.slice_from("eau");break;case 10:if(!a())return!1;W.slice_from("al");break;case 11:if(l())W.slice_del();else{if(!a())return!1;W.slice_from("eux")}break;case 12:if(!a()||!W.out_grouping_b(F,97,251))return!1;W.slice_del();break;case 13:return c()&&W.slice_from("ant"),!1;case 14:return c()&&W.slice_from("ent"),!1;case 15:return r=W.limit-W.cursor,W.in_grouping_b(F,97,251)&&c()&&(W.cursor=W.limit-r,W.slice_del()),!1}return!0}return!1}function f(){var e,r;if(W.cursor=q){if(s=W.limit_backward,W.limit_backward=q,W.ket=W.cursor,e=W.find_among_b(P,7))switch(W.bra=W.cursor,e){case 1:if(l()){if(i=W.limit-W.cursor,!W.eq_s_b(1,"s")&&(W.cursor=W.limit-i,!W.eq_s_b(1,"t")))break;W.slice_del()}break;case 2:W.slice_from("i");break;case 3:W.slice_del();break;case 4:W.eq_s_b(2,"gu")&&W.slice_del()}W.limit_backward=s}}function b(){var e=W.limit-W.cursor;W.find_among_b(U,5)&&(W.cursor=W.limit-e,W.ket=W.cursor,W.cursor>W.limit_backward&&(W.cursor--,W.bra=W.cursor,W.slice_del()))}function d(){for(var e,r=1;W.out_grouping_b(F,97,251);)r--;if(r<=0){if(W.ket=W.cursor,e=W.limit-W.cursor,!W.eq_s_b(1,"é")&&(W.cursor=W.limit-e,!W.eq_s_b(1,"è")))return;W.bra=W.cursor,W.slice_from("e")}}function k(){if(!w()&&(W.cursor=W.limit,!f()&&(W.cursor=W.limit,!m())))return W.cursor=W.limit,void _();W.cursor=W.limit,W.ket=W.cursor,W.eq_s_b(1,"Y")?(W.bra=W.cursor,W.slice_from("i")):(W.cursor=W.limit,W.eq_s_b(1,"ç")&&(W.bra=W.cursor,W.slice_from("c")))}var p,g,q,v=[new r("col",-1,-1),new r("par",-1,-1),new r("tap",-1,-1)],h=[new r("",-1,4),new r("I",0,1),new r("U",0,2),new r("Y",0,3)],z=[new r("iqU",-1,3),new r("abl",-1,3),new r("Ièr",-1,4),new r("ièr",-1,4),new r("eus",-1,2),new r("iv",-1,1)],y=[new r("ic",-1,2),new r("abil",-1,1),new r("iv",-1,3)],C=[new r("iqUe",-1,1),new r("atrice",-1,2),new r("ance",-1,1),new r("ence",-1,5),new r("logie",-1,3),new r("able",-1,1),new r("isme",-1,1),new r("euse",-1,11),new r("iste",-1,1),new r("ive",-1,8),new r("if",-1,8),new r("usion",-1,4),new r("ation",-1,2),new r("ution",-1,4),new r("ateur",-1,2),new r("iqUes",-1,1),new r("atrices",-1,2),new r("ances",-1,1),new r("ences",-1,5),new r("logies",-1,3),new r("ables",-1,1),new r("ismes",-1,1),new r("euses",-1,11),new r("istes",-1,1),new r("ives",-1,8),new r("ifs",-1,8),new r("usions",-1,4),new r("ations",-1,2),new r("utions",-1,4),new r("ateurs",-1,2),new r("ments",-1,15),new r("ements",30,6),new r("issements",31,12),new r("ités",-1,7),new r("ment",-1,15),new r("ement",34,6),new r("issement",35,12),new r("amment",34,13),new r("emment",34,14),new r("aux",-1,10),new r("eaux",39,9),new r("eux",-1,1),new r("ité",-1,7)],x=[new r("ira",-1,1),new r("ie",-1,1),new r("isse",-1,1),new r("issante",-1,1),new r("i",-1,1),new r("irai",4,1),new r("ir",-1,1),new r("iras",-1,1),new r("ies",-1,1),new r("îmes",-1,1),new r("isses",-1,1),new r("issantes",-1,1),new r("îtes",-1,1),new r("is",-1,1),new r("irais",13,1),new r("issais",13,1),new r("irions",-1,1),new r("issions",-1,1),new r("irons",-1,1),new r("issons",-1,1),new r("issants",-1,1),new r("it",-1,1),new r("irait",21,1),new r("issait",21,1),new r("issant",-1,1),new r("iraIent",-1,1),new r("issaIent",-1,1),new r("irent",-1,1),new r("issent",-1,1),new r("iront",-1,1),new r("ît",-1,1),new r("iriez",-1,1),new r("issiez",-1,1),new r("irez",-1,1),new r("issez",-1,1)],I=[new r("a",-1,3),new r("era",0,2),new r("asse",-1,3),new r("ante",-1,3),new r("ée",-1,2),new r("ai",-1,3),new r("erai",5,2),new r("er",-1,2),new r("as",-1,3),new r("eras",8,2),new r("âmes",-1,3),new r("asses",-1,3),new r("antes",-1,3),new r("âtes",-1,3),new r("ées",-1,2),new r("ais",-1,3),new r("erais",15,2),new r("ions",-1,1),new r("erions",17,2),new r("assions",17,3),new r("erons",-1,2),new r("ants",-1,3),new r("és",-1,2),new r("ait",-1,3),new r("erait",23,2),new r("ant",-1,3),new r("aIent",-1,3),new r("eraIent",26,2),new r("èrent",-1,2),new r("assent",-1,3),new r("eront",-1,2),new r("ât",-1,3),new r("ez",-1,2),new r("iez",32,2),new r("eriez",33,2),new r("assiez",33,3),new r("erez",32,2),new r("é",-1,2)],P=[new r("e",-1,3),new r("Ière",0,2),new r("ière",0,2),new r("ion",-1,1),new r("Ier",-1,2),new r("ier",-1,2),new r("ë",-1,4)],U=[new r("ell",-1,-1),new r("eill",-1,-1),new r("enn",-1,-1),new r("onn",-1,-1),new r("ett",-1,-1)],F=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,128,130,103,8,5],S=[1,65,20,0,0,0,0,0,0,0,0,0,0,0,0,0,128],W=new s;this.setCurrent=function(e){W.setCurrent(e)},this.getCurrent=function(){return W.getCurrent()},this.stem=function(){var e=W.cursor;return n(),W.cursor=e,u(),W.limit_backward=e,W.cursor=W.limit,k(),W.cursor=W.limit,b(),W.cursor=W.limit,d(),W.cursor=W.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.fr.stemmer,"stemmer-fr"),e.fr.stopWordFilter=e.generateStopWordFilter("ai aie aient aies ait as au aura aurai auraient aurais aurait auras aurez auriez aurions aurons auront aux avaient avais avait avec avez aviez avions avons ayant ayez ayons c ce ceci celà ces cet cette d dans de des du elle en es est et eu eue eues eurent eus eusse eussent eusses eussiez eussions eut eux eûmes eût eûtes furent fus fusse fussent fusses fussiez fussions fut fûmes fût fûtes ici il ils j je l la le les leur leurs lui m ma mais me mes moi mon même n ne nos notre nous on ont ou par pas pour qu que quel quelle quelles quels qui s sa sans se sera serai seraient serais serait seras serez seriez serions serons seront ses soi soient sois soit sommes son sont soyez soyons suis sur t ta te tes toi ton tu un une vos votre vous y à étaient étais était étant étiez étions été étée étées étés êtes".split(" ")),e.Pipeline.registerFunction(e.fr.stopWordFilter,"stopWordFilter-fr")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.hi.min.js b/site/assets/javascripts/lunr/min/lunr.hi.min.js new file mode 100644 index 0000000000..7dbc41402c --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.hi.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hi=function(){this.pipeline.reset(),this.pipeline.add(e.hi.trimmer,e.hi.stopWordFilter,e.hi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hi.stemmer))},e.hi.wordCharacters="ऀ-ःऄ-एऐ-टठ-यर-िी-ॏॐ-य़ॠ-९॰-ॿa-zA-Za-zA-Z0-90-9",e.hi.trimmer=e.trimmerSupport.generateTrimmer(e.hi.wordCharacters),e.Pipeline.registerFunction(e.hi.trimmer,"trimmer-hi"),e.hi.stopWordFilter=e.generateStopWordFilter("अत अपना अपनी अपने अभी अंदर आदि आप इत्यादि इन इनका इन्हीं इन्हें इन्हों इस इसका इसकी इसके इसमें इसी इसे उन उनका उनकी उनके उनको उन्हीं उन्हें उन्हों उस उसके उसी उसे एक एवं एस ऐसे और कई कर करता करते करना करने करें कहते कहा का काफ़ी कि कितना किन्हें किन्हों किया किर किस किसी किसे की कुछ कुल के को कोई कौन कौनसा गया घर जब जहाँ जा जितना जिन जिन्हें जिन्हों जिस जिसे जीधर जैसा जैसे जो तक तब तरह तिन तिन्हें तिन्हों तिस तिसे तो था थी थे दबारा दिया दुसरा दूसरे दो द्वारा न नके नहीं ना निहायत नीचे ने पर पहले पूरा पे फिर बनी बही बहुत बाद बाला बिलकुल भी भीतर मगर मानो मे में यदि यह यहाँ यही या यिह ये रखें रहा रहे ऱ्वासा लिए लिये लेकिन व वग़ैरह वर्ग वह वहाँ वहीं वाले वुह वे वो सकता सकते सबसे सभी साथ साबुत साभ सारा से सो संग ही हुआ हुई हुए है हैं हो होता होती होते होना होने".split(" ")),e.hi.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.hi.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var t=i.toString().toLowerCase().replace(/^\s+/,"");return r.cut(t).split("|")},e.Pipeline.registerFunction(e.hi.stemmer,"stemmer-hi"),e.Pipeline.registerFunction(e.hi.stopWordFilter,"stopWordFilter-hi")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.hu.min.js b/site/assets/javascripts/lunr/min/lunr.hu.min.js new file mode 100644 index 0000000000..ed9d909f73 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.hu.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Hungarian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hu=function(){this.pipeline.reset(),this.pipeline.add(e.hu.trimmer,e.hu.stopWordFilter,e.hu.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hu.stemmer))},e.hu.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.hu.trimmer=e.trimmerSupport.generateTrimmer(e.hu.wordCharacters),e.Pipeline.registerFunction(e.hu.trimmer,"trimmer-hu"),e.hu.stemmer=function(){var n=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,n=L.cursor;if(d=L.limit,L.in_grouping(W,97,252))for(;;){if(e=L.cursor,L.out_grouping(W,97,252))return L.cursor=e,L.find_among(g,8)||(L.cursor=e,e=L.limit)return void(d=e);L.cursor++}if(L.cursor=n,L.out_grouping(W,97,252)){for(;!L.in_grouping(W,97,252);){if(L.cursor>=L.limit)return;L.cursor++}d=L.cursor}}function i(){return d<=L.cursor}function a(){var e;if(L.ket=L.cursor,(e=L.find_among_b(h,2))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("a");break;case 2:L.slice_from("e")}}function t(){var e=L.limit-L.cursor;return!!L.find_among_b(p,23)&&(L.cursor=L.limit-e,!0)}function s(){if(L.cursor>L.limit_backward){L.cursor--,L.ket=L.cursor;var e=L.cursor-1;L.limit_backward<=e&&e<=L.limit&&(L.cursor=e,L.bra=e,L.slice_del())}}function c(){var e;if(L.ket=L.cursor,(e=L.find_among_b(_,2))&&(L.bra=L.cursor,i())){if((1==e||2==e)&&!t())return;L.slice_del(),s()}}function o(){L.ket=L.cursor,L.find_among_b(v,44)&&(L.bra=L.cursor,i()&&(L.slice_del(),a()))}function w(){var e;if(L.ket=L.cursor,(e=L.find_among_b(z,3))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("e");break;case 2:case 3:L.slice_from("a")}}function l(){var e;if(L.ket=L.cursor,(e=L.find_among_b(y,6))&&(L.bra=L.cursor,i()))switch(e){case 1:case 2:L.slice_del();break;case 3:L.slice_from("a");break;case 4:L.slice_from("e")}}function u(){var e;if(L.ket=L.cursor,(e=L.find_among_b(j,2))&&(L.bra=L.cursor,i())){if((1==e||2==e)&&!t())return;L.slice_del(),s()}}function m(){var e;if(L.ket=L.cursor,(e=L.find_among_b(C,7))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("a");break;case 2:L.slice_from("e");break;case 3:case 4:case 5:case 6:case 7:L.slice_del()}}function k(){var e;if(L.ket=L.cursor,(e=L.find_among_b(P,12))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 7:case 9:L.slice_del();break;case 2:case 5:case 8:L.slice_from("e");break;case 3:case 6:L.slice_from("a")}}function f(){var e;if(L.ket=L.cursor,(e=L.find_among_b(F,31))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 7:case 8:case 9:case 12:case 13:case 16:case 17:case 18:L.slice_del();break;case 2:case 5:case 10:case 14:case 19:L.slice_from("a");break;case 3:case 6:case 11:case 15:case 20:L.slice_from("e")}}function b(){var e;if(L.ket=L.cursor,(e=L.find_among_b(S,42))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 5:case 6:case 9:case 10:case 11:case 14:case 15:case 16:case 17:case 20:case 21:case 24:case 25:case 26:case 29:L.slice_del();break;case 2:case 7:case 12:case 18:case 22:case 27:L.slice_from("a");break;case 3:case 8:case 13:case 19:case 23:case 28:L.slice_from("e")}}var d,g=[new n("cs",-1,-1),new n("dzs",-1,-1),new n("gy",-1,-1),new n("ly",-1,-1),new n("ny",-1,-1),new n("sz",-1,-1),new n("ty",-1,-1),new n("zs",-1,-1)],h=[new n("á",-1,1),new n("é",-1,2)],p=[new n("bb",-1,-1),new n("cc",-1,-1),new n("dd",-1,-1),new n("ff",-1,-1),new n("gg",-1,-1),new n("jj",-1,-1),new n("kk",-1,-1),new n("ll",-1,-1),new n("mm",-1,-1),new n("nn",-1,-1),new n("pp",-1,-1),new n("rr",-1,-1),new n("ccs",-1,-1),new n("ss",-1,-1),new n("zzs",-1,-1),new n("tt",-1,-1),new n("vv",-1,-1),new n("ggy",-1,-1),new n("lly",-1,-1),new n("nny",-1,-1),new n("tty",-1,-1),new n("ssz",-1,-1),new n("zz",-1,-1)],_=[new n("al",-1,1),new n("el",-1,2)],v=[new n("ba",-1,-1),new n("ra",-1,-1),new n("be",-1,-1),new n("re",-1,-1),new n("ig",-1,-1),new n("nak",-1,-1),new n("nek",-1,-1),new n("val",-1,-1),new n("vel",-1,-1),new n("ul",-1,-1),new n("nál",-1,-1),new n("nél",-1,-1),new n("ból",-1,-1),new n("ról",-1,-1),new n("tól",-1,-1),new n("bõl",-1,-1),new n("rõl",-1,-1),new n("tõl",-1,-1),new n("ül",-1,-1),new n("n",-1,-1),new n("an",19,-1),new n("ban",20,-1),new n("en",19,-1),new n("ben",22,-1),new n("képpen",22,-1),new n("on",19,-1),new n("ön",19,-1),new n("képp",-1,-1),new n("kor",-1,-1),new n("t",-1,-1),new n("at",29,-1),new n("et",29,-1),new n("ként",29,-1),new n("anként",32,-1),new n("enként",32,-1),new n("onként",32,-1),new n("ot",29,-1),new n("ért",29,-1),new n("öt",29,-1),new n("hez",-1,-1),new n("hoz",-1,-1),new n("höz",-1,-1),new n("vá",-1,-1),new n("vé",-1,-1)],z=[new n("án",-1,2),new n("én",-1,1),new n("ánként",-1,3)],y=[new n("stul",-1,2),new n("astul",0,1),new n("ástul",0,3),new n("stül",-1,2),new n("estül",3,1),new n("éstül",3,4)],j=[new n("á",-1,1),new n("é",-1,2)],C=[new n("k",-1,7),new n("ak",0,4),new n("ek",0,6),new n("ok",0,5),new n("ák",0,1),new n("ék",0,2),new n("ök",0,3)],P=[new n("éi",-1,7),new n("áéi",0,6),new n("ééi",0,5),new n("é",-1,9),new n("ké",3,4),new n("aké",4,1),new n("eké",4,1),new n("oké",4,1),new n("áké",4,3),new n("éké",4,2),new n("öké",4,1),new n("éé",3,8)],F=[new n("a",-1,18),new n("ja",0,17),new n("d",-1,16),new n("ad",2,13),new n("ed",2,13),new n("od",2,13),new n("ád",2,14),new n("éd",2,15),new n("öd",2,13),new n("e",-1,18),new n("je",9,17),new n("nk",-1,4),new n("unk",11,1),new n("ánk",11,2),new n("énk",11,3),new n("ünk",11,1),new n("uk",-1,8),new n("juk",16,7),new n("ájuk",17,5),new n("ük",-1,8),new n("jük",19,7),new n("éjük",20,6),new n("m",-1,12),new n("am",22,9),new n("em",22,9),new n("om",22,9),new n("ám",22,10),new n("ém",22,11),new n("o",-1,18),new n("á",-1,19),new n("é",-1,20)],S=[new n("id",-1,10),new n("aid",0,9),new n("jaid",1,6),new n("eid",0,9),new n("jeid",3,6),new n("áid",0,7),new n("éid",0,8),new n("i",-1,15),new n("ai",7,14),new n("jai",8,11),new n("ei",7,14),new n("jei",10,11),new n("ái",7,12),new n("éi",7,13),new n("itek",-1,24),new n("eitek",14,21),new n("jeitek",15,20),new n("éitek",14,23),new n("ik",-1,29),new n("aik",18,26),new n("jaik",19,25),new n("eik",18,26),new n("jeik",21,25),new n("áik",18,27),new n("éik",18,28),new n("ink",-1,20),new n("aink",25,17),new n("jaink",26,16),new n("eink",25,17),new n("jeink",28,16),new n("áink",25,18),new n("éink",25,19),new n("aitok",-1,21),new n("jaitok",32,20),new n("áitok",-1,22),new n("im",-1,5),new n("aim",35,4),new n("jaim",36,1),new n("eim",35,4),new n("jeim",38,1),new n("áim",35,2),new n("éim",35,3)],W=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,52,14],L=new r;this.setCurrent=function(e){L.setCurrent(e)},this.getCurrent=function(){return L.getCurrent()},this.stem=function(){var n=L.cursor;return e(),L.limit_backward=n,L.cursor=L.limit,c(),L.cursor=L.limit,o(),L.cursor=L.limit,w(),L.cursor=L.limit,l(),L.cursor=L.limit,u(),L.cursor=L.limit,k(),L.cursor=L.limit,f(),L.cursor=L.limit,b(),L.cursor=L.limit,m(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.hu.stemmer,"stemmer-hu"),e.hu.stopWordFilter=e.generateStopWordFilter("a abban ahhoz ahogy ahol aki akik akkor alatt amely amelyek amelyekben amelyeket amelyet amelynek ami amikor amit amolyan amíg annak arra arról az azok azon azonban azt aztán azután azzal azért be belül benne bár cikk cikkek cikkeket csak de e ebben eddig egy egyes egyetlen egyik egyre egyéb egész ehhez ekkor el ellen elsõ elég elõ elõször elõtt emilyen ennek erre ez ezek ezen ezt ezzel ezért fel felé hanem hiszen hogy hogyan igen ill ill. illetve ilyen ilyenkor ismét ison itt jobban jó jól kell kellett keressünk keresztül ki kívül között közül legalább legyen lehet lehetett lenne lenni lesz lett maga magát majd majd meg mellett mely melyek mert mi mikor milyen minden mindenki mindent mindig mint mintha mit mivel miért most már más másik még míg nagy nagyobb nagyon ne nekem neki nem nincs néha néhány nélkül olyan ott pedig persze rá s saját sem semmi sok sokat sokkal szemben szerint szinte számára talán tehát teljes tovább továbbá több ugyanis utolsó után utána vagy vagyis vagyok valaki valami valamint való van vannak vele vissza viszont volna volt voltak voltam voltunk által általában át én éppen és így õ õk õket össze úgy új újabb újra".split(" ")),e.Pipeline.registerFunction(e.hu.stopWordFilter,"stopWordFilter-hu")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.it.min.js b/site/assets/javascripts/lunr/min/lunr.it.min.js new file mode 100644 index 0000000000..344b6a3c0c --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.it.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Italian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.it=function(){this.pipeline.reset(),this.pipeline.add(e.it.trimmer,e.it.stopWordFilter,e.it.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.it.stemmer))},e.it.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.it.trimmer=e.trimmerSupport.generateTrimmer(e.it.wordCharacters),e.Pipeline.registerFunction(e.it.trimmer,"trimmer-it"),e.it.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,n){return!(!x.eq_s(1,e)||(x.ket=x.cursor,!x.in_grouping(L,97,249)))&&(x.slice_from(r),x.cursor=n,!0)}function i(){for(var r,n,i,o,t=x.cursor;;){if(x.bra=x.cursor,r=x.find_among(h,7))switch(x.ket=x.cursor,r){case 1:x.slice_from("à");continue;case 2:x.slice_from("è");continue;case 3:x.slice_from("ì");continue;case 4:x.slice_from("ò");continue;case 5:x.slice_from("ù");continue;case 6:x.slice_from("qU");continue;case 7:if(x.cursor>=x.limit)break;x.cursor++;continue}break}for(x.cursor=t;;)for(n=x.cursor;;){if(i=x.cursor,x.in_grouping(L,97,249)){if(x.bra=x.cursor,o=x.cursor,e("u","U",i))break;if(x.cursor=o,e("i","I",i))break}if(x.cursor=i,x.cursor>=x.limit)return void(x.cursor=n);x.cursor++}}function o(e){if(x.cursor=e,!x.in_grouping(L,97,249))return!1;for(;!x.out_grouping(L,97,249);){if(x.cursor>=x.limit)return!1;x.cursor++}return!0}function t(){if(x.in_grouping(L,97,249)){var e=x.cursor;if(x.out_grouping(L,97,249)){for(;!x.in_grouping(L,97,249);){if(x.cursor>=x.limit)return o(e);x.cursor++}return!0}return o(e)}return!1}function s(){var e,r=x.cursor;if(!t()){if(x.cursor=r,!x.out_grouping(L,97,249))return;if(e=x.cursor,x.out_grouping(L,97,249)){for(;!x.in_grouping(L,97,249);){if(x.cursor>=x.limit)return x.cursor=e,void(x.in_grouping(L,97,249)&&x.cursor=x.limit)return;x.cursor++}k=x.cursor}function a(){for(;!x.in_grouping(L,97,249);){if(x.cursor>=x.limit)return!1;x.cursor++}for(;!x.out_grouping(L,97,249);){if(x.cursor>=x.limit)return!1;x.cursor++}return!0}function u(){var e=x.cursor;k=x.limit,p=k,g=k,s(),x.cursor=e,a()&&(p=x.cursor,a()&&(g=x.cursor))}function c(){for(var e;;){if(x.bra=x.cursor,!(e=x.find_among(q,3)))break;switch(x.ket=x.cursor,e){case 1:x.slice_from("i");break;case 2:x.slice_from("u");break;case 3:if(x.cursor>=x.limit)return;x.cursor++}}}function w(){return k<=x.cursor}function l(){return p<=x.cursor}function m(){return g<=x.cursor}function f(){var e;if(x.ket=x.cursor,x.find_among_b(C,37)&&(x.bra=x.cursor,(e=x.find_among_b(z,5))&&w()))switch(e){case 1:x.slice_del();break;case 2:x.slice_from("e")}}function v(){var e;if(x.ket=x.cursor,!(e=x.find_among_b(S,51)))return!1;switch(x.bra=x.cursor,e){case 1:if(!m())return!1;x.slice_del();break;case 2:if(!m())return!1;x.slice_del(),x.ket=x.cursor,x.eq_s_b(2,"ic")&&(x.bra=x.cursor,m()&&x.slice_del());break;case 3:if(!m())return!1;x.slice_from("log");break;case 4:if(!m())return!1;x.slice_from("u");break;case 5:if(!m())return!1;x.slice_from("ente");break;case 6:if(!w())return!1;x.slice_del();break;case 7:if(!l())return!1;x.slice_del(),x.ket=x.cursor,e=x.find_among_b(P,4),e&&(x.bra=x.cursor,m()&&(x.slice_del(),1==e&&(x.ket=x.cursor,x.eq_s_b(2,"at")&&(x.bra=x.cursor,m()&&x.slice_del()))));break;case 8:if(!m())return!1;x.slice_del(),x.ket=x.cursor,e=x.find_among_b(F,3),e&&(x.bra=x.cursor,1==e&&m()&&x.slice_del());break;case 9:if(!m())return!1;x.slice_del(),x.ket=x.cursor,x.eq_s_b(2,"at")&&(x.bra=x.cursor,m()&&(x.slice_del(),x.ket=x.cursor,x.eq_s_b(2,"ic")&&(x.bra=x.cursor,m()&&x.slice_del())))}return!0}function b(){var e,r;x.cursor>=k&&(r=x.limit_backward,x.limit_backward=k,x.ket=x.cursor,e=x.find_among_b(W,87),e&&(x.bra=x.cursor,1==e&&x.slice_del()),x.limit_backward=r)}function d(){var e=x.limit-x.cursor;if(x.ket=x.cursor,x.in_grouping_b(y,97,242)&&(x.bra=x.cursor,w()&&(x.slice_del(),x.ket=x.cursor,x.eq_s_b(1,"i")&&(x.bra=x.cursor,w()))))return void x.slice_del();x.cursor=x.limit-e}function _(){d(),x.ket=x.cursor,x.eq_s_b(1,"h")&&(x.bra=x.cursor,x.in_grouping_b(U,99,103)&&w()&&x.slice_del())}var g,p,k,h=[new r("",-1,7),new r("qu",0,6),new r("á",0,1),new r("é",0,2),new r("í",0,3),new r("ó",0,4),new r("ú",0,5)],q=[new r("",-1,3),new r("I",0,1),new r("U",0,2)],C=[new r("la",-1,-1),new r("cela",0,-1),new r("gliela",0,-1),new r("mela",0,-1),new r("tela",0,-1),new r("vela",0,-1),new r("le",-1,-1),new r("cele",6,-1),new r("gliele",6,-1),new r("mele",6,-1),new r("tele",6,-1),new r("vele",6,-1),new r("ne",-1,-1),new r("cene",12,-1),new r("gliene",12,-1),new r("mene",12,-1),new r("sene",12,-1),new r("tene",12,-1),new r("vene",12,-1),new r("ci",-1,-1),new r("li",-1,-1),new r("celi",20,-1),new r("glieli",20,-1),new r("meli",20,-1),new r("teli",20,-1),new r("veli",20,-1),new r("gli",20,-1),new r("mi",-1,-1),new r("si",-1,-1),new r("ti",-1,-1),new r("vi",-1,-1),new r("lo",-1,-1),new r("celo",31,-1),new r("glielo",31,-1),new r("melo",31,-1),new r("telo",31,-1),new r("velo",31,-1)],z=[new r("ando",-1,1),new r("endo",-1,1),new r("ar",-1,2),new r("er",-1,2),new r("ir",-1,2)],P=[new r("ic",-1,-1),new r("abil",-1,-1),new r("os",-1,-1),new r("iv",-1,1)],F=[new r("ic",-1,1),new r("abil",-1,1),new r("iv",-1,1)],S=[new r("ica",-1,1),new r("logia",-1,3),new r("osa",-1,1),new r("ista",-1,1),new r("iva",-1,9),new r("anza",-1,1),new r("enza",-1,5),new r("ice",-1,1),new r("atrice",7,1),new r("iche",-1,1),new r("logie",-1,3),new r("abile",-1,1),new r("ibile",-1,1),new r("usione",-1,4),new r("azione",-1,2),new r("uzione",-1,4),new r("atore",-1,2),new r("ose",-1,1),new r("ante",-1,1),new r("mente",-1,1),new r("amente",19,7),new r("iste",-1,1),new r("ive",-1,9),new r("anze",-1,1),new r("enze",-1,5),new r("ici",-1,1),new r("atrici",25,1),new r("ichi",-1,1),new r("abili",-1,1),new r("ibili",-1,1),new r("ismi",-1,1),new r("usioni",-1,4),new r("azioni",-1,2),new r("uzioni",-1,4),new r("atori",-1,2),new r("osi",-1,1),new r("anti",-1,1),new r("amenti",-1,6),new r("imenti",-1,6),new r("isti",-1,1),new r("ivi",-1,9),new r("ico",-1,1),new r("ismo",-1,1),new r("oso",-1,1),new r("amento",-1,6),new r("imento",-1,6),new r("ivo",-1,9),new r("ità",-1,8),new r("istà",-1,1),new r("istè",-1,1),new r("istì",-1,1)],W=[new r("isca",-1,1),new r("enda",-1,1),new r("ata",-1,1),new r("ita",-1,1),new r("uta",-1,1),new r("ava",-1,1),new r("eva",-1,1),new r("iva",-1,1),new r("erebbe",-1,1),new r("irebbe",-1,1),new r("isce",-1,1),new r("ende",-1,1),new r("are",-1,1),new r("ere",-1,1),new r("ire",-1,1),new r("asse",-1,1),new r("ate",-1,1),new r("avate",16,1),new r("evate",16,1),new r("ivate",16,1),new r("ete",-1,1),new r("erete",20,1),new r("irete",20,1),new r("ite",-1,1),new r("ereste",-1,1),new r("ireste",-1,1),new r("ute",-1,1),new r("erai",-1,1),new r("irai",-1,1),new r("isci",-1,1),new r("endi",-1,1),new r("erei",-1,1),new r("irei",-1,1),new r("assi",-1,1),new r("ati",-1,1),new r("iti",-1,1),new r("eresti",-1,1),new r("iresti",-1,1),new r("uti",-1,1),new r("avi",-1,1),new r("evi",-1,1),new r("ivi",-1,1),new r("isco",-1,1),new r("ando",-1,1),new r("endo",-1,1),new r("Yamo",-1,1),new r("iamo",-1,1),new r("avamo",-1,1),new r("evamo",-1,1),new r("ivamo",-1,1),new r("eremo",-1,1),new r("iremo",-1,1),new r("assimo",-1,1),new r("ammo",-1,1),new r("emmo",-1,1),new r("eremmo",54,1),new r("iremmo",54,1),new r("immo",-1,1),new r("ano",-1,1),new r("iscano",58,1),new r("avano",58,1),new r("evano",58,1),new r("ivano",58,1),new r("eranno",-1,1),new r("iranno",-1,1),new r("ono",-1,1),new r("iscono",65,1),new r("arono",65,1),new r("erono",65,1),new r("irono",65,1),new r("erebbero",-1,1),new r("irebbero",-1,1),new r("assero",-1,1),new r("essero",-1,1),new r("issero",-1,1),new r("ato",-1,1),new r("ito",-1,1),new r("uto",-1,1),new r("avo",-1,1),new r("evo",-1,1),new r("ivo",-1,1),new r("ar",-1,1),new r("ir",-1,1),new r("erà",-1,1),new r("irà",-1,1),new r("erò",-1,1),new r("irò",-1,1)],L=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,128,128,8,2,1],y=[17,65,0,0,0,0,0,0,0,0,0,0,0,0,0,128,128,8,2],U=[17],x=new n;this.setCurrent=function(e){x.setCurrent(e)},this.getCurrent=function(){return x.getCurrent()},this.stem=function(){var e=x.cursor;return i(),x.cursor=e,u(),x.limit_backward=e,x.cursor=x.limit,f(),x.cursor=x.limit,v()||(x.cursor=x.limit,b()),x.cursor=x.limit,_(),x.cursor=x.limit_backward,c(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.it.stemmer,"stemmer-it"),e.it.stopWordFilter=e.generateStopWordFilter("a abbia abbiamo abbiano abbiate ad agl agli ai al all alla alle allo anche avemmo avendo avesse avessero avessi avessimo aveste avesti avete aveva avevamo avevano avevate avevi avevo avrai avranno avrebbe avrebbero avrei avremmo avremo avreste avresti avrete avrà avrò avuta avute avuti avuto c che chi ci coi col come con contro cui da dagl dagli dai dal dall dalla dalle dallo degl degli dei del dell della delle dello di dov dove e ebbe ebbero ebbi ed era erano eravamo eravate eri ero essendo faccia facciamo facciano facciate faccio facemmo facendo facesse facessero facessi facessimo faceste facesti faceva facevamo facevano facevate facevi facevo fai fanno farai faranno farebbe farebbero farei faremmo faremo fareste faresti farete farà farò fece fecero feci fosse fossero fossi fossimo foste fosti fu fui fummo furono gli ha hai hanno ho i il in io l la le lei li lo loro lui ma mi mia mie miei mio ne negl negli nei nel nell nella nelle nello noi non nostra nostre nostri nostro o per perché più quale quanta quante quanti quanto quella quelle quelli quello questa queste questi questo sarai saranno sarebbe sarebbero sarei saremmo saremo sareste saresti sarete sarà sarò se sei si sia siamo siano siate siete sono sta stai stando stanno starai staranno starebbe starebbero starei staremmo staremo stareste staresti starete starà starò stava stavamo stavano stavate stavi stavo stemmo stesse stessero stessi stessimo steste stesti stette stettero stetti stia stiamo stiano stiate sto su sua sue sugl sugli sui sul sull sulla sulle sullo suo suoi ti tra tu tua tue tuo tuoi tutti tutto un una uno vi voi vostra vostre vostri vostro è".split(" ")),e.Pipeline.registerFunction(e.it.stopWordFilter,"stopWordFilter-it")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.ja.min.js b/site/assets/javascripts/lunr/min/lunr.ja.min.js new file mode 100644 index 0000000000..5f254ebe91 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.ja.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.ja=function(){this.pipeline.reset(),this.pipeline.add(e.ja.trimmer,e.ja.stopWordFilter,e.ja.stemmer),r?this.tokenizer=e.ja.tokenizer:(e.tokenizer&&(e.tokenizer=e.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.ja.tokenizer))};var t=new e.TinySegmenter;e.ja.tokenizer=function(i){var n,o,s,p,a,u,m,l,c,f;if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(o=i.toString().toLowerCase().replace(/^\s+/,""),n=o.length-1;n>=0;n--)if(/\S/.test(o.charAt(n))){o=o.substring(0,n+1);break}for(a=[],s=o.length,c=0,l=0;c<=s;c++)if(u=o.charAt(c),m=c-l,u.match(/\s/)||c==s){if(m>0)for(p=t.segment(o.slice(l,c)).filter(function(e){return!!e}),f=l,n=0;n=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(e=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=e);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=e;else if(n(e))break}else if(n(e))break}function n(r){return C.cursor=r,r>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,d=_,t()||(_=C.cursor,_<3&&(_=3),t()||(d=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var r;;)if(C.bra=C.cursor,r=C.find_among(p,3))switch(C.ket=C.cursor,r){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return d<=C.cursor}function a(){var r=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-r,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var r;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.slice_del(),w=!0,a())))}function m(){var r;u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.eq_s_b(3,"gem")||(C.cursor=C.limit-r,C.slice_del(),a())))}function f(){var r,e,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,r=C.find_among_b(h,5))switch(C.bra=C.cursor,r){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(j,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(e=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-e,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,r=C.find_among_b(k,6))switch(C.bra=C.cursor,r){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(z,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var d,_,w,b=[new e("",-1,6),new e("á",0,1),new e("ä",0,1),new e("é",0,2),new e("ë",0,2),new e("í",0,3),new e("ï",0,3),new e("ó",0,4),new e("ö",0,4),new e("ú",0,5),new e("ü",0,5)],p=[new e("",-1,3),new e("I",0,2),new e("Y",0,1)],g=[new e("dd",-1,-1),new e("kk",-1,-1),new e("tt",-1,-1)],h=[new e("ene",-1,2),new e("se",-1,3),new e("en",-1,2),new e("heden",2,1),new e("s",-1,3)],k=[new e("end",-1,1),new e("ig",-1,2),new e("ing",-1,1),new e("lijk",-1,3),new e("baar",-1,4),new e("bar",-1,5)],v=[new e("aa",-1,-1),new e("ee",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(r){C.setCurrent(r)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var e=C.cursor;return r(),C.cursor=e,o(),C.limit_backward=e,C.cursor=C.limit,f(),C.cursor=C.limit_backward,s(),!0}};return function(r){return"function"==typeof r.update?r.update(function(r){return n.setCurrent(r),n.stem(),n.getCurrent()}):(n.setCurrent(r),n.stem(),n.getCurrent())}}(),r.Pipeline.registerFunction(r.nl.stemmer,"stemmer-nl"),r.nl.stopWordFilter=r.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),r.Pipeline.registerFunction(r.nl.stopWordFilter,"stopWordFilter-nl")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.no.min.js b/site/assets/javascripts/lunr/min/lunr.no.min.js new file mode 100644 index 0000000000..92bc7e4e89 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.no.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Norwegian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,r=w.cursor+3;if(a=w.limit,0<=r||r<=w.limit){for(s=r;;){if(e=w.cursor,w.in_grouping(d,97,248)){w.cursor=e;break}if(e>=w.limit)return;w.cursor=e+1}for(;!w.out_grouping(d,97,248);){if(w.cursor>=w.limit)return;w.cursor++}a=w.cursor,a=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(m,29),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:n=w.limit-w.cursor,w.in_grouping_b(c,98,122)?w.slice_del():(w.cursor=w.limit-n,w.eq_s_b(1,"k")&&w.out_grouping_b(d,97,248)&&w.slice_del());break;case 3:w.slice_from("er")}}function t(){var e,r=w.limit-w.cursor;w.cursor>=a&&(e=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,w.find_among_b(u,2)?(w.bra=w.cursor,w.limit_backward=e,w.cursor=w.limit-r,w.cursor>w.limit_backward&&(w.cursor--,w.bra=w.cursor,w.slice_del())):w.limit_backward=e)}function o(){var e,r;w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(l,11),e?(w.bra=w.cursor,w.limit_backward=r,1==e&&w.slice_del()):w.limit_backward=r)}var s,a,m=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],u=[new r("dt",-1,-1),new r("vt",-1,-1)],l=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],c=[119,125,149,1],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,i(),w.cursor=w.limit,t(),w.cursor=w.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.pt.min.js b/site/assets/javascripts/lunr/min/lunr.pt.min.js new file mode 100644 index 0000000000..6c16996d65 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.pt.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Portuguese` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.pt=function(){this.pipeline.reset(),this.pipeline.add(e.pt.trimmer,e.pt.stopWordFilter,e.pt.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.pt.stemmer))},e.pt.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.pt.trimmer=e.trimmerSupport.generateTrimmer(e.pt.wordCharacters),e.Pipeline.registerFunction(e.pt.trimmer,"trimmer-pt"),e.pt.stemmer=function(){var r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,n=new function(){function e(){for(var e;;){if(z.bra=z.cursor,e=z.find_among(k,3))switch(z.ket=z.cursor,e){case 1:z.slice_from("a~");continue;case 2:z.slice_from("o~");continue;case 3:if(z.cursor>=z.limit)break;z.cursor++;continue}break}}function n(){if(z.out_grouping(y,97,250)){for(;!z.in_grouping(y,97,250);){if(z.cursor>=z.limit)return!0;z.cursor++}return!1}return!0}function i(){if(z.in_grouping(y,97,250))for(;!z.out_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}return g=z.cursor,!0}function o(){var e,r,s=z.cursor;if(z.in_grouping(y,97,250))if(e=z.cursor,n()){if(z.cursor=e,i())return}else g=z.cursor;if(z.cursor=s,z.out_grouping(y,97,250)){if(r=z.cursor,n()){if(z.cursor=r,!z.in_grouping(y,97,250)||z.cursor>=z.limit)return;z.cursor++}g=z.cursor}}function t(){for(;!z.in_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}for(;!z.out_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}return!0}function a(){var e=z.cursor;g=z.limit,b=g,h=g,o(),z.cursor=e,t()&&(b=z.cursor,t()&&(h=z.cursor))}function u(){for(var e;;){if(z.bra=z.cursor,e=z.find_among(q,3))switch(z.ket=z.cursor,e){case 1:z.slice_from("ã");continue;case 2:z.slice_from("õ");continue;case 3:if(z.cursor>=z.limit)break;z.cursor++;continue}break}}function w(){return g<=z.cursor}function m(){return b<=z.cursor}function c(){return h<=z.cursor}function l(){var e;if(z.ket=z.cursor,!(e=z.find_among_b(F,45)))return!1;switch(z.bra=z.cursor,e){case 1:if(!c())return!1;z.slice_del();break;case 2:if(!c())return!1;z.slice_from("log");break;case 3:if(!c())return!1;z.slice_from("u");break;case 4:if(!c())return!1;z.slice_from("ente");break;case 5:if(!m())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(j,4),e&&(z.bra=z.cursor,c()&&(z.slice_del(),1==e&&(z.ket=z.cursor,z.eq_s_b(2,"at")&&(z.bra=z.cursor,c()&&z.slice_del()))));break;case 6:if(!c())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(C,3),e&&(z.bra=z.cursor,1==e&&c()&&z.slice_del());break;case 7:if(!c())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(P,3),e&&(z.bra=z.cursor,1==e&&c()&&z.slice_del());break;case 8:if(!c())return!1;z.slice_del(),z.ket=z.cursor,z.eq_s_b(2,"at")&&(z.bra=z.cursor,c()&&z.slice_del());break;case 9:if(!w()||!z.eq_s_b(1,"e"))return!1;z.slice_from("ir")}return!0}function f(){var e,r;if(z.cursor>=g){if(r=z.limit_backward,z.limit_backward=g,z.ket=z.cursor,e=z.find_among_b(S,120))return z.bra=z.cursor,1==e&&z.slice_del(),z.limit_backward=r,!0;z.limit_backward=r}return!1}function d(){var e;z.ket=z.cursor,(e=z.find_among_b(W,7))&&(z.bra=z.cursor,1==e&&w()&&z.slice_del())}function v(e,r){if(z.eq_s_b(1,e)){z.bra=z.cursor;var s=z.limit-z.cursor;if(z.eq_s_b(1,r))return z.cursor=z.limit-s,w()&&z.slice_del(),!1}return!0}function p(){var e;if(z.ket=z.cursor,e=z.find_among_b(L,4))switch(z.bra=z.cursor,e){case 1:w()&&(z.slice_del(),z.ket=z.cursor,z.limit-z.cursor,v("u","g")&&v("i","c"));break;case 2:z.slice_from("c")}}function _(){if(!l()&&(z.cursor=z.limit,!f()))return z.cursor=z.limit,void d();z.cursor=z.limit,z.ket=z.cursor,z.eq_s_b(1,"i")&&(z.bra=z.cursor,z.eq_s_b(1,"c")&&(z.cursor=z.limit,w()&&z.slice_del()))}var h,b,g,k=[new r("",-1,3),new r("ã",0,1),new r("õ",0,2)],q=[new r("",-1,3),new r("a~",0,1),new r("o~",0,2)],j=[new r("ic",-1,-1),new r("ad",-1,-1),new r("os",-1,-1),new r("iv",-1,1)],C=[new r("ante",-1,1),new r("avel",-1,1),new r("ível",-1,1)],P=[new r("ic",-1,1),new r("abil",-1,1),new r("iv",-1,1)],F=[new r("ica",-1,1),new r("ância",-1,1),new r("ência",-1,4),new r("ira",-1,9),new r("adora",-1,1),new r("osa",-1,1),new r("ista",-1,1),new r("iva",-1,8),new r("eza",-1,1),new r("logía",-1,2),new r("idade",-1,7),new r("ante",-1,1),new r("mente",-1,6),new r("amente",12,5),new r("ável",-1,1),new r("ível",-1,1),new r("ución",-1,3),new r("ico",-1,1),new r("ismo",-1,1),new r("oso",-1,1),new r("amento",-1,1),new r("imento",-1,1),new r("ivo",-1,8),new r("aça~o",-1,1),new r("ador",-1,1),new r("icas",-1,1),new r("ências",-1,4),new r("iras",-1,9),new r("adoras",-1,1),new r("osas",-1,1),new r("istas",-1,1),new r("ivas",-1,8),new r("ezas",-1,1),new r("logías",-1,2),new r("idades",-1,7),new r("uciones",-1,3),new r("adores",-1,1),new r("antes",-1,1),new r("aço~es",-1,1),new r("icos",-1,1),new r("ismos",-1,1),new r("osos",-1,1),new r("amentos",-1,1),new r("imentos",-1,1),new r("ivos",-1,8)],S=[new r("ada",-1,1),new r("ida",-1,1),new r("ia",-1,1),new r("aria",2,1),new r("eria",2,1),new r("iria",2,1),new r("ara",-1,1),new r("era",-1,1),new r("ira",-1,1),new r("ava",-1,1),new r("asse",-1,1),new r("esse",-1,1),new r("isse",-1,1),new r("aste",-1,1),new r("este",-1,1),new r("iste",-1,1),new r("ei",-1,1),new r("arei",16,1),new r("erei",16,1),new r("irei",16,1),new r("am",-1,1),new r("iam",20,1),new r("ariam",21,1),new r("eriam",21,1),new r("iriam",21,1),new r("aram",20,1),new r("eram",20,1),new r("iram",20,1),new r("avam",20,1),new r("em",-1,1),new r("arem",29,1),new r("erem",29,1),new r("irem",29,1),new r("assem",29,1),new r("essem",29,1),new r("issem",29,1),new r("ado",-1,1),new r("ido",-1,1),new r("ando",-1,1),new r("endo",-1,1),new r("indo",-1,1),new r("ara~o",-1,1),new r("era~o",-1,1),new r("ira~o",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("ir",-1,1),new r("as",-1,1),new r("adas",47,1),new r("idas",47,1),new r("ias",47,1),new r("arias",50,1),new r("erias",50,1),new r("irias",50,1),new r("aras",47,1),new r("eras",47,1),new r("iras",47,1),new r("avas",47,1),new r("es",-1,1),new r("ardes",58,1),new r("erdes",58,1),new r("irdes",58,1),new r("ares",58,1),new r("eres",58,1),new r("ires",58,1),new r("asses",58,1),new r("esses",58,1),new r("isses",58,1),new r("astes",58,1),new r("estes",58,1),new r("istes",58,1),new r("is",-1,1),new r("ais",71,1),new r("eis",71,1),new r("areis",73,1),new r("ereis",73,1),new r("ireis",73,1),new r("áreis",73,1),new r("éreis",73,1),new r("íreis",73,1),new r("ásseis",73,1),new r("ésseis",73,1),new r("ísseis",73,1),new r("áveis",73,1),new r("íeis",73,1),new r("aríeis",84,1),new r("eríeis",84,1),new r("iríeis",84,1),new r("ados",-1,1),new r("idos",-1,1),new r("amos",-1,1),new r("áramos",90,1),new r("éramos",90,1),new r("íramos",90,1),new r("ávamos",90,1),new r("íamos",90,1),new r("aríamos",95,1),new r("eríamos",95,1),new r("iríamos",95,1),new r("emos",-1,1),new r("aremos",99,1),new r("eremos",99,1),new r("iremos",99,1),new r("ássemos",99,1),new r("êssemos",99,1),new r("íssemos",99,1),new r("imos",-1,1),new r("armos",-1,1),new r("ermos",-1,1),new r("irmos",-1,1),new r("ámos",-1,1),new r("arás",-1,1),new r("erás",-1,1),new r("irás",-1,1),new r("eu",-1,1),new r("iu",-1,1),new r("ou",-1,1),new r("ará",-1,1),new r("erá",-1,1),new r("irá",-1,1)],W=[new r("a",-1,1),new r("i",-1,1),new r("o",-1,1),new r("os",-1,1),new r("á",-1,1),new r("í",-1,1),new r("ó",-1,1)],L=[new r("e",-1,1),new r("ç",-1,2),new r("é",-1,1),new r("ê",-1,1)],y=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,3,19,12,2],z=new s;this.setCurrent=function(e){z.setCurrent(e)},this.getCurrent=function(){return z.getCurrent()},this.stem=function(){var r=z.cursor;return e(),z.cursor=r,a(),z.limit_backward=r,z.cursor=z.limit,_(),z.cursor=z.limit,p(),z.cursor=z.limit_backward,u(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.pt.stemmer,"stemmer-pt"),e.pt.stopWordFilter=e.generateStopWordFilter("a ao aos aquela aquelas aquele aqueles aquilo as até com como da das de dela delas dele deles depois do dos e ela elas ele eles em entre era eram essa essas esse esses esta estamos estas estava estavam este esteja estejam estejamos estes esteve estive estivemos estiver estivera estiveram estiverem estivermos estivesse estivessem estivéramos estivéssemos estou está estávamos estão eu foi fomos for fora foram forem formos fosse fossem fui fôramos fôssemos haja hajam hajamos havemos hei houve houvemos houver houvera houveram houverei houverem houveremos houveria houveriam houvermos houverá houverão houveríamos houvesse houvessem houvéramos houvéssemos há hão isso isto já lhe lhes mais mas me mesmo meu meus minha minhas muito na nas nem no nos nossa nossas nosso nossos num numa não nós o os ou para pela pelas pelo pelos por qual quando que quem se seja sejam sejamos sem serei seremos seria seriam será serão seríamos seu seus somos sou sua suas são só também te tem temos tenha tenham tenhamos tenho terei teremos teria teriam terá terão teríamos teu teus teve tinha tinham tive tivemos tiver tivera tiveram tiverem tivermos tivesse tivessem tivéramos tivéssemos tu tua tuas tém tínhamos um uma você vocês vos à às éramos".split(" ")),e.Pipeline.registerFunction(e.pt.stopWordFilter,"stopWordFilter-pt")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.ro.min.js b/site/assets/javascripts/lunr/min/lunr.ro.min.js new file mode 100644 index 0000000000..7277140181 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.ro.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Romanian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ro=function(){this.pipeline.reset(),this.pipeline.add(e.ro.trimmer,e.ro.stopWordFilter,e.ro.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ro.stemmer))},e.ro.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.ro.trimmer=e.trimmerSupport.generateTrimmer(e.ro.wordCharacters),e.Pipeline.registerFunction(e.ro.trimmer,"trimmer-ro"),e.ro.stemmer=function(){var i=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,n=new function(){function e(e,i){L.eq_s(1,e)&&(L.ket=L.cursor,L.in_grouping(W,97,259)&&L.slice_from(i))}function n(){for(var i,r;;){if(i=L.cursor,L.in_grouping(W,97,259)&&(r=L.cursor,L.bra=r,e("u","U"),L.cursor=r,e("i","I")),L.cursor=i,L.cursor>=L.limit)break;L.cursor++}}function t(){if(L.out_grouping(W,97,259)){for(;!L.in_grouping(W,97,259);){if(L.cursor>=L.limit)return!0;L.cursor++}return!1}return!0}function a(){if(L.in_grouping(W,97,259))for(;!L.out_grouping(W,97,259);){if(L.cursor>=L.limit)return!0;L.cursor++}return!1}function o(){var e,i,r=L.cursor;if(L.in_grouping(W,97,259)){if(e=L.cursor,!t())return void(h=L.cursor);if(L.cursor=e,!a())return void(h=L.cursor)}L.cursor=r,L.out_grouping(W,97,259)&&(i=L.cursor,t()&&(L.cursor=i,L.in_grouping(W,97,259)&&L.cursor=L.limit)return!1;L.cursor++}for(;!L.out_grouping(W,97,259);){if(L.cursor>=L.limit)return!1;L.cursor++}return!0}function c(){var e=L.cursor;h=L.limit,k=h,g=h,o(),L.cursor=e,u()&&(k=L.cursor,u()&&(g=L.cursor))}function s(){for(var e;;){if(L.bra=L.cursor,e=L.find_among(z,3))switch(L.ket=L.cursor,e){case 1:L.slice_from("i");continue;case 2:L.slice_from("u");continue;case 3:if(L.cursor>=L.limit)break;L.cursor++;continue}break}}function w(){return h<=L.cursor}function m(){return k<=L.cursor}function l(){return g<=L.cursor}function f(){var e,i;if(L.ket=L.cursor,(e=L.find_among_b(C,16))&&(L.bra=L.cursor,m()))switch(e){case 1:L.slice_del();break;case 2:L.slice_from("a");break;case 3:L.slice_from("e");break;case 4:L.slice_from("i");break;case 5:i=L.limit-L.cursor,L.eq_s_b(2,"ab")||(L.cursor=L.limit-i,L.slice_from("i"));break;case 6:L.slice_from("at");break;case 7:L.slice_from("aţi")}}function p(){var e,i=L.limit-L.cursor;if(L.ket=L.cursor,(e=L.find_among_b(P,46))&&(L.bra=L.cursor,m())){switch(e){case 1:L.slice_from("abil");break;case 2:L.slice_from("ibil");break;case 3:L.slice_from("iv");break;case 4:L.slice_from("ic");break;case 5:L.slice_from("at");break;case 6:L.slice_from("it")}return _=!0,L.cursor=L.limit-i,!0}return!1}function d(){var e,i;for(_=!1;;)if(i=L.limit-L.cursor,!p()){L.cursor=L.limit-i;break}if(L.ket=L.cursor,(e=L.find_among_b(F,62))&&(L.bra=L.cursor,l())){switch(e){case 1:L.slice_del();break;case 2:L.eq_s_b(1,"ţ")&&(L.bra=L.cursor,L.slice_from("t"));break;case 3:L.slice_from("ist")}_=!0}}function b(){var e,i,r;if(L.cursor>=h){if(i=L.limit_backward,L.limit_backward=h,L.ket=L.cursor,e=L.find_among_b(q,94))switch(L.bra=L.cursor,e){case 1:if(r=L.limit-L.cursor,!L.out_grouping_b(W,97,259)&&(L.cursor=L.limit-r,!L.eq_s_b(1,"u")))break;case 2:L.slice_del()}L.limit_backward=i}}function v(){var e;L.ket=L.cursor,(e=L.find_among_b(S,5))&&(L.bra=L.cursor,w()&&1==e&&L.slice_del())}var _,g,k,h,z=[new i("",-1,3),new i("I",0,1),new i("U",0,2)],C=[new i("ea",-1,3),new i("aţia",-1,7),new i("aua",-1,2),new i("iua",-1,4),new i("aţie",-1,7),new i("ele",-1,3),new i("ile",-1,5),new i("iile",6,4),new i("iei",-1,4),new i("atei",-1,6),new i("ii",-1,4),new i("ului",-1,1),new i("ul",-1,1),new i("elor",-1,3),new i("ilor",-1,4),new i("iilor",14,4)],P=[new i("icala",-1,4),new i("iciva",-1,4),new i("ativa",-1,5),new i("itiva",-1,6),new i("icale",-1,4),new i("aţiune",-1,5),new i("iţiune",-1,6),new i("atoare",-1,5),new i("itoare",-1,6),new i("ătoare",-1,5),new i("icitate",-1,4),new i("abilitate",-1,1),new i("ibilitate",-1,2),new i("ivitate",-1,3),new i("icive",-1,4),new i("ative",-1,5),new i("itive",-1,6),new i("icali",-1,4),new i("atori",-1,5),new i("icatori",18,4),new i("itori",-1,6),new i("ători",-1,5),new i("icitati",-1,4),new i("abilitati",-1,1),new i("ivitati",-1,3),new i("icivi",-1,4),new i("ativi",-1,5),new i("itivi",-1,6),new i("icităi",-1,4),new i("abilităi",-1,1),new i("ivităi",-1,3),new i("icităţi",-1,4),new i("abilităţi",-1,1),new i("ivităţi",-1,3),new i("ical",-1,4),new i("ator",-1,5),new i("icator",35,4),new i("itor",-1,6),new i("ător",-1,5),new i("iciv",-1,4),new i("ativ",-1,5),new i("itiv",-1,6),new i("icală",-1,4),new i("icivă",-1,4),new i("ativă",-1,5),new i("itivă",-1,6)],F=[new i("ica",-1,1),new i("abila",-1,1),new i("ibila",-1,1),new i("oasa",-1,1),new i("ata",-1,1),new i("ita",-1,1),new i("anta",-1,1),new i("ista",-1,3),new i("uta",-1,1),new i("iva",-1,1),new i("ic",-1,1),new i("ice",-1,1),new i("abile",-1,1),new i("ibile",-1,1),new i("isme",-1,3),new i("iune",-1,2),new i("oase",-1,1),new i("ate",-1,1),new i("itate",17,1),new i("ite",-1,1),new i("ante",-1,1),new i("iste",-1,3),new i("ute",-1,1),new i("ive",-1,1),new i("ici",-1,1),new i("abili",-1,1),new i("ibili",-1,1),new i("iuni",-1,2),new i("atori",-1,1),new i("osi",-1,1),new i("ati",-1,1),new i("itati",30,1),new i("iti",-1,1),new i("anti",-1,1),new i("isti",-1,3),new i("uti",-1,1),new i("işti",-1,3),new i("ivi",-1,1),new i("ităi",-1,1),new i("oşi",-1,1),new i("ităţi",-1,1),new i("abil",-1,1),new i("ibil",-1,1),new i("ism",-1,3),new i("ator",-1,1),new i("os",-1,1),new i("at",-1,1),new i("it",-1,1),new i("ant",-1,1),new i("ist",-1,3),new i("ut",-1,1),new i("iv",-1,1),new i("ică",-1,1),new i("abilă",-1,1),new i("ibilă",-1,1),new i("oasă",-1,1),new i("ată",-1,1),new i("ită",-1,1),new i("antă",-1,1),new i("istă",-1,3),new i("ută",-1,1),new i("ivă",-1,1)],q=[new i("ea",-1,1),new i("ia",-1,1),new i("esc",-1,1),new i("ăsc",-1,1),new i("ind",-1,1),new i("ând",-1,1),new i("are",-1,1),new i("ere",-1,1),new i("ire",-1,1),new i("âre",-1,1),new i("se",-1,2),new i("ase",10,1),new i("sese",10,2),new i("ise",10,1),new i("use",10,1),new i("âse",10,1),new i("eşte",-1,1),new i("ăşte",-1,1),new i("eze",-1,1),new i("ai",-1,1),new i("eai",19,1),new i("iai",19,1),new i("sei",-1,2),new i("eşti",-1,1),new i("ăşti",-1,1),new i("ui",-1,1),new i("ezi",-1,1),new i("âi",-1,1),new i("aşi",-1,1),new i("seşi",-1,2),new i("aseşi",29,1),new i("seseşi",29,2),new i("iseşi",29,1),new i("useşi",29,1),new i("âseşi",29,1),new i("işi",-1,1),new i("uşi",-1,1),new i("âşi",-1,1),new i("aţi",-1,2),new i("eaţi",38,1),new i("iaţi",38,1),new i("eţi",-1,2),new i("iţi",-1,2),new i("âţi",-1,2),new i("arăţi",-1,1),new i("serăţi",-1,2),new i("aserăţi",45,1),new i("seserăţi",45,2),new i("iserăţi",45,1),new i("userăţi",45,1),new i("âserăţi",45,1),new i("irăţi",-1,1),new i("urăţi",-1,1),new i("ârăţi",-1,1),new i("am",-1,1),new i("eam",54,1),new i("iam",54,1),new i("em",-1,2),new i("asem",57,1),new i("sesem",57,2),new i("isem",57,1),new i("usem",57,1),new i("âsem",57,1),new i("im",-1,2),new i("âm",-1,2),new i("ăm",-1,2),new i("arăm",65,1),new i("serăm",65,2),new i("aserăm",67,1),new i("seserăm",67,2),new i("iserăm",67,1),new i("userăm",67,1),new i("âserăm",67,1),new i("irăm",65,1),new i("urăm",65,1),new i("ârăm",65,1),new i("au",-1,1),new i("eau",76,1),new i("iau",76,1),new i("indu",-1,1),new i("ându",-1,1),new i("ez",-1,1),new i("ească",-1,1),new i("ară",-1,1),new i("seră",-1,2),new i("aseră",84,1),new i("seseră",84,2),new i("iseră",84,1),new i("useră",84,1),new i("âseră",84,1),new i("iră",-1,1),new i("ură",-1,1),new i("âră",-1,1),new i("ează",-1,1)],S=[new i("a",-1,1),new i("e",-1,1),new i("ie",1,1),new i("i",-1,1),new i("ă",-1,1)],W=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,2,32,0,0,4],L=new r;this.setCurrent=function(e){L.setCurrent(e)},this.getCurrent=function(){return L.getCurrent()},this.stem=function(){var e=L.cursor;return n(),L.cursor=e,c(),L.limit_backward=e,L.cursor=L.limit,f(),L.cursor=L.limit,d(),L.cursor=L.limit,_||(L.cursor=L.limit,b(),L.cursor=L.limit),v(),L.cursor=L.limit_backward,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.ro.stemmer,"stemmer-ro"),e.ro.stopWordFilter=e.generateStopWordFilter("acea aceasta această aceea acei aceia acel acela acele acelea acest acesta aceste acestea aceşti aceştia acolo acord acum ai aia aibă aici al ale alea altceva altcineva am ar are asemenea asta astea astăzi asupra au avea avem aveţi azi aş aşadar aţi bine bucur bună ca care caut ce cel ceva chiar cinci cine cineva contra cu cum cumva curând curînd când cât câte câtva câţi cînd cît cîte cîtva cîţi că căci cărei căror cărui către da dacă dar datorită dată dau de deci deja deoarece departe deşi din dinaintea dintr- dintre doi doilea două drept după dă ea ei el ele eram este eu eşti face fata fi fie fiecare fii fim fiu fiţi frumos fără graţie halbă iar ieri la le li lor lui lângă lîngă mai mea mei mele mereu meu mi mie mine mult multă mulţi mulţumesc mâine mîine mă ne nevoie nici nicăieri nimeni nimeri nimic nişte noastre noastră noi noroc nostru nouă noştri nu opt ori oricare orice oricine oricum oricând oricât oricînd oricît oriunde patra patru patrulea pe pentru peste pic poate pot prea prima primul prin puţin puţina puţină până pînă rog sa sale sau se spate spre sub sunt suntem sunteţi sută sînt sîntem sînteţi să săi său ta tale te timp tine toate toată tot totuşi toţi trei treia treilea tu tăi tău un una unde undeva unei uneia unele uneori unii unor unora unu unui unuia unul vi voastre voastră voi vostru vouă voştri vreme vreo vreun vă zece zero zi zice îi îl îmi împotriva în înainte înaintea încotro încât încît între întrucât întrucît îţi ăla ălea ăsta ăstea ăştia şapte şase şi ştiu ţi ţie".split(" ")),e.Pipeline.registerFunction(e.ro.stopWordFilter,"stopWordFilter-ro")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.ru.min.js b/site/assets/javascripts/lunr/min/lunr.ru.min.js new file mode 100644 index 0000000000..186cc485c2 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.ru.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Russian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ru=function(){this.pipeline.reset(),this.pipeline.add(e.ru.trimmer,e.ru.stopWordFilter,e.ru.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ru.stemmer))},e.ru.wordCharacters="Ѐ-҄҇-ԯᴫᵸⷠ-ⷿꙀ-ꚟ︮︯",e.ru.trimmer=e.trimmerSupport.generateTrimmer(e.ru.wordCharacters),e.Pipeline.registerFunction(e.ru.trimmer,"trimmer-ru"),e.ru.stemmer=function(){var n=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,t=new function(){function e(){for(;!W.in_grouping(S,1072,1103);){if(W.cursor>=W.limit)return!1;W.cursor++}return!0}function t(){for(;!W.out_grouping(S,1072,1103);){if(W.cursor>=W.limit)return!1;W.cursor++}return!0}function w(){b=W.limit,_=b,e()&&(b=W.cursor,t()&&e()&&t()&&(_=W.cursor))}function i(){return _<=W.cursor}function u(e,n){var r,t;if(W.ket=W.cursor,r=W.find_among_b(e,n)){switch(W.bra=W.cursor,r){case 1:if(t=W.limit-W.cursor,!W.eq_s_b(1,"а")&&(W.cursor=W.limit-t,!W.eq_s_b(1,"я")))return!1;case 2:W.slice_del()}return!0}return!1}function o(){return u(h,9)}function s(e,n){var r;return W.ket=W.cursor,!!(r=W.find_among_b(e,n))&&(W.bra=W.cursor,1==r&&W.slice_del(),!0)}function c(){return s(g,26)}function m(){return!!c()&&(u(C,8),!0)}function f(){return s(k,2)}function l(){return u(P,46)}function a(){s(v,36)}function p(){var e;W.ket=W.cursor,(e=W.find_among_b(F,2))&&(W.bra=W.cursor,i()&&1==e&&W.slice_del())}function d(){var e;if(W.ket=W.cursor,e=W.find_among_b(q,4))switch(W.bra=W.cursor,e){case 1:if(W.slice_del(),W.ket=W.cursor,!W.eq_s_b(1,"н"))break;W.bra=W.cursor;case 2:if(!W.eq_s_b(1,"н"))break;case 3:W.slice_del()}}var _,b,h=[new n("в",-1,1),new n("ив",0,2),new n("ыв",0,2),new n("вши",-1,1),new n("ивши",3,2),new n("ывши",3,2),new n("вшись",-1,1),new n("ившись",6,2),new n("ывшись",6,2)],g=[new n("ее",-1,1),new n("ие",-1,1),new n("ое",-1,1),new n("ые",-1,1),new n("ими",-1,1),new n("ыми",-1,1),new n("ей",-1,1),new n("ий",-1,1),new n("ой",-1,1),new n("ый",-1,1),new n("ем",-1,1),new n("им",-1,1),new n("ом",-1,1),new n("ым",-1,1),new n("его",-1,1),new n("ого",-1,1),new n("ему",-1,1),new n("ому",-1,1),new n("их",-1,1),new n("ых",-1,1),new n("ею",-1,1),new n("ою",-1,1),new n("ую",-1,1),new n("юю",-1,1),new n("ая",-1,1),new n("яя",-1,1)],C=[new n("ем",-1,1),new n("нн",-1,1),new n("вш",-1,1),new n("ивш",2,2),new n("ывш",2,2),new n("щ",-1,1),new n("ющ",5,1),new n("ующ",6,2)],k=[new n("сь",-1,1),new n("ся",-1,1)],P=[new n("ла",-1,1),new n("ила",0,2),new n("ыла",0,2),new n("на",-1,1),new n("ена",3,2),new n("ете",-1,1),new n("ите",-1,2),new n("йте",-1,1),new n("ейте",7,2),new n("уйте",7,2),new n("ли",-1,1),new n("или",10,2),new n("ыли",10,2),new n("й",-1,1),new n("ей",13,2),new n("уй",13,2),new n("л",-1,1),new n("ил",16,2),new n("ыл",16,2),new n("ем",-1,1),new n("им",-1,2),new n("ым",-1,2),new n("н",-1,1),new n("ен",22,2),new n("ло",-1,1),new n("ило",24,2),new n("ыло",24,2),new n("но",-1,1),new n("ено",27,2),new n("нно",27,1),new n("ет",-1,1),new n("ует",30,2),new n("ит",-1,2),new n("ыт",-1,2),new n("ют",-1,1),new n("уют",34,2),new n("ят",-1,2),new n("ны",-1,1),new n("ены",37,2),new n("ть",-1,1),new n("ить",39,2),new n("ыть",39,2),new n("ешь",-1,1),new n("ишь",-1,2),new n("ю",-1,2),new n("ую",44,2)],v=[new n("а",-1,1),new n("ев",-1,1),new n("ов",-1,1),new n("е",-1,1),new n("ие",3,1),new n("ье",3,1),new n("и",-1,1),new n("еи",6,1),new n("ии",6,1),new n("ами",6,1),new n("ями",6,1),new n("иями",10,1),new n("й",-1,1),new n("ей",12,1),new n("ией",13,1),new n("ий",12,1),new n("ой",12,1),new n("ам",-1,1),new n("ем",-1,1),new n("ием",18,1),new n("ом",-1,1),new n("ям",-1,1),new n("иям",21,1),new n("о",-1,1),new n("у",-1,1),new n("ах",-1,1),new n("ях",-1,1),new n("иях",26,1),new n("ы",-1,1),new n("ь",-1,1),new n("ю",-1,1),new n("ию",30,1),new n("ью",30,1),new n("я",-1,1),new n("ия",33,1),new n("ья",33,1)],F=[new n("ост",-1,1),new n("ость",-1,1)],q=[new n("ейше",-1,1),new n("н",-1,2),new n("ейш",-1,1),new n("ь",-1,3)],S=[33,65,8,232],W=new r;this.setCurrent=function(e){W.setCurrent(e)},this.getCurrent=function(){return W.getCurrent()},this.stem=function(){return w(),W.cursor=W.limit,!(W.cursor=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursors||e>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor>1),f=0,l=o0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o=0;m--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n-_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n-_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.sv.min.js b/site/assets/javascripts/lunr/min/lunr.sv.min.js new file mode 100644 index 0000000000..3e5eb64000 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.sv.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Swedish` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){function e(){var e,r=w.cursor+3;if(o=w.limit,0<=r||r<=w.limit){for(a=r;;){if(e=w.cursor,w.in_grouping(l,97,246)){w.cursor=e;break}if(w.cursor=e,w.cursor>=w.limit)return;w.cursor++}for(;!w.out_grouping(l,97,246);){if(w.cursor>=w.limit)return;w.cursor++}o=w.cursor,o=o&&(w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(u,37),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.in_grouping_b(d,98,121)&&w.slice_del()}}function i(){var e=w.limit_backward;w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.find_among_b(c,7)&&(w.cursor=w.limit,w.ket=w.cursor,w.cursor>w.limit_backward&&(w.bra=--w.cursor,w.slice_del())),w.limit_backward=e)}function s(){var e,r;if(w.cursor>=o){if(r=w.limit_backward,w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(m,5))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.slice_from("lös");break;case 3:w.slice_from("full")}w.limit_backward=r}}var a,o,u=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],c=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],l=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],d=[119,127,149],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,t(),w.cursor=w.limit,i(),w.cursor=w.limit,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}}(),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.th.min.js b/site/assets/javascripts/lunr/min/lunr.th.min.js new file mode 100644 index 0000000000..dee3aac6e5 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.th.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.th=function(){this.pipeline.reset(),this.pipeline.add(e.th.trimmer),r?this.tokenizer=e.th.tokenizer:(e.tokenizer&&(e.tokenizer=e.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.th.tokenizer))},e.th.wordCharacters="[฀-๿]",e.th.trimmer=e.trimmerSupport.generateTrimmer(e.th.wordCharacters),e.Pipeline.registerFunction(e.th.trimmer,"trimmer-th");var t=e.wordcut;t.init(),e.th.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t):t});var n=i.toString().replace(/^\s+/,"");return t.cut(n).split("|")}}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.tr.min.js b/site/assets/javascripts/lunr/min/lunr.tr.min.js new file mode 100644 index 0000000000..563f6ec1f5 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.tr.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Turkish` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(r,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(r.lunr)}(this,function(){return function(r){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");r.tr=function(){this.pipeline.reset(),this.pipeline.add(r.tr.trimmer,r.tr.stopWordFilter,r.tr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(r.tr.stemmer))},r.tr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",r.tr.trimmer=r.trimmerSupport.generateTrimmer(r.tr.wordCharacters),r.Pipeline.registerFunction(r.tr.trimmer,"trimmer-tr"),r.tr.stemmer=function(){var i=r.stemmerSupport.Among,e=r.stemmerSupport.SnowballProgram,n=new function(){function r(r,i,e){for(;;){var n=Dr.limit-Dr.cursor;if(Dr.in_grouping_b(r,i,e)){Dr.cursor=Dr.limit-n;break}if(Dr.cursor=Dr.limit-n,Dr.cursor<=Dr.limit_backward)return!1;Dr.cursor--}return!0}function n(){var i,e;i=Dr.limit-Dr.cursor,r(Wr,97,305);for(var n=0;nDr.limit_backward&&(Dr.cursor--,e=Dr.limit-Dr.cursor,i()))?(Dr.cursor=Dr.limit-e,!0):(Dr.cursor=Dr.limit-n,r()?(Dr.cursor=Dr.limit-n,!1):(Dr.cursor=Dr.limit-n,!(Dr.cursor<=Dr.limit_backward)&&(Dr.cursor--,!!i()&&(Dr.cursor=Dr.limit-n,!0))))}function u(r){return t(r,function(){return Dr.in_grouping_b(Wr,97,305)})}function o(){return u(function(){return Dr.eq_s_b(1,"n")})}function s(){return u(function(){return Dr.eq_s_b(1,"s")})}function c(){return u(function(){return Dr.eq_s_b(1,"y")})}function l(){return t(function(){return Dr.in_grouping_b(Lr,105,305)},function(){return Dr.out_grouping_b(Wr,97,305)})}function a(){return Dr.find_among_b(ur,10)&&l()}function m(){return n()&&Dr.in_grouping_b(Lr,105,305)&&s()}function d(){return Dr.find_among_b(or,2)}function f(){return n()&&Dr.in_grouping_b(Lr,105,305)&&c()}function b(){return n()&&Dr.find_among_b(sr,4)}function w(){return n()&&Dr.find_among_b(cr,4)&&o()}function _(){return n()&&Dr.find_among_b(lr,2)&&c()}function k(){return n()&&Dr.find_among_b(ar,2)}function p(){return n()&&Dr.find_among_b(mr,4)}function g(){return n()&&Dr.find_among_b(dr,2)}function y(){return n()&&Dr.find_among_b(fr,4)}function z(){return n()&&Dr.find_among_b(br,2)}function v(){return n()&&Dr.find_among_b(wr,2)&&c()}function h(){return Dr.eq_s_b(2,"ki")}function q(){return n()&&Dr.find_among_b(_r,2)&&o()}function C(){return n()&&Dr.find_among_b(kr,4)&&c()}function P(){return n()&&Dr.find_among_b(pr,4)}function F(){return n()&&Dr.find_among_b(gr,4)&&c()}function S(){return Dr.find_among_b(yr,4)}function W(){return n()&&Dr.find_among_b(zr,2)}function L(){return n()&&Dr.find_among_b(vr,4)}function x(){return n()&&Dr.find_among_b(hr,8)}function A(){return Dr.find_among_b(qr,2)}function E(){return n()&&Dr.find_among_b(Cr,32)&&c()}function j(){return Dr.find_among_b(Pr,8)&&c()}function T(){return n()&&Dr.find_among_b(Fr,4)&&c()}function Z(){return Dr.eq_s_b(3,"ken")&&c()}function B(){var r=Dr.limit-Dr.cursor;return!(T()||(Dr.cursor=Dr.limit-r,E()||(Dr.cursor=Dr.limit-r,j()||(Dr.cursor=Dr.limit-r,Z()))))}function D(){if(A()){var r=Dr.limit-Dr.cursor;if(S()||(Dr.cursor=Dr.limit-r,W()||(Dr.cursor=Dr.limit-r,C()||(Dr.cursor=Dr.limit-r,P()||(Dr.cursor=Dr.limit-r,F()||(Dr.cursor=Dr.limit-r))))),T())return!1}return!0}function G(){if(W()){Dr.bra=Dr.cursor,Dr.slice_del();var r=Dr.limit-Dr.cursor;return Dr.ket=Dr.cursor,x()||(Dr.cursor=Dr.limit-r,E()||(Dr.cursor=Dr.limit-r,j()||(Dr.cursor=Dr.limit-r,T()||(Dr.cursor=Dr.limit-r)))),nr=!1,!1}return!0}function H(){if(!L())return!0;var r=Dr.limit-Dr.cursor;return!E()&&(Dr.cursor=Dr.limit-r,!j())}function I(){var r,i=Dr.limit-Dr.cursor;return!(S()||(Dr.cursor=Dr.limit-i,F()||(Dr.cursor=Dr.limit-i,P()||(Dr.cursor=Dr.limit-i,C()))))||(Dr.bra=Dr.cursor,Dr.slice_del(),r=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,T()||(Dr.cursor=Dr.limit-r),!1)}function J(){var r,i=Dr.limit-Dr.cursor;if(Dr.ket=Dr.cursor,nr=!0,B()&&(Dr.cursor=Dr.limit-i,D()&&(Dr.cursor=Dr.limit-i,G()&&(Dr.cursor=Dr.limit-i,H()&&(Dr.cursor=Dr.limit-i,I()))))){if(Dr.cursor=Dr.limit-i,!x())return;Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,r=Dr.limit-Dr.cursor,S()||(Dr.cursor=Dr.limit-r,W()||(Dr.cursor=Dr.limit-r,C()||(Dr.cursor=Dr.limit-r,P()||(Dr.cursor=Dr.limit-r,F()||(Dr.cursor=Dr.limit-r))))),T()||(Dr.cursor=Dr.limit-r)}Dr.bra=Dr.cursor,Dr.slice_del()}function K(){var r,i,e,n;if(Dr.ket=Dr.cursor,h()){if(r=Dr.limit-Dr.cursor,p())return Dr.bra=Dr.cursor,Dr.slice_del(),i=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,W()?(Dr.bra=Dr.cursor,Dr.slice_del(),K()):(Dr.cursor=Dr.limit-i,a()&&(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K()))),!0;if(Dr.cursor=Dr.limit-r,w()){if(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,e=Dr.limit-Dr.cursor,d())Dr.bra=Dr.cursor,Dr.slice_del();else{if(Dr.cursor=Dr.limit-e,Dr.ket=Dr.cursor,!a()&&(Dr.cursor=Dr.limit-e,!m()&&(Dr.cursor=Dr.limit-e,!K())))return!0;Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K())}return!0}if(Dr.cursor=Dr.limit-r,g()){if(n=Dr.limit-Dr.cursor,d())Dr.bra=Dr.cursor,Dr.slice_del();else if(Dr.cursor=Dr.limit-n,m())Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K());else if(Dr.cursor=Dr.limit-n,!K())return!1;return!0}}return!1}function M(r){if(Dr.ket=Dr.cursor,!g()&&(Dr.cursor=Dr.limit-r,!k()))return!1;var i=Dr.limit-Dr.cursor;if(d())Dr.bra=Dr.cursor,Dr.slice_del();else if(Dr.cursor=Dr.limit-i,m())Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K());else if(Dr.cursor=Dr.limit-i,!K())return!1;return!0}function N(r){if(Dr.ket=Dr.cursor,!z()&&(Dr.cursor=Dr.limit-r,!b()))return!1;var i=Dr.limit-Dr.cursor;return!(!m()&&(Dr.cursor=Dr.limit-i,!d()))&&(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K()),!0)}function O(){var r,i=Dr.limit-Dr.cursor;return Dr.ket=Dr.cursor,!(!w()&&(Dr.cursor=Dr.limit-i,!v()))&&(Dr.bra=Dr.cursor,Dr.slice_del(),r=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,!(!W()||(Dr.bra=Dr.cursor,Dr.slice_del(),!K()))||(Dr.cursor=Dr.limit-r,Dr.ket=Dr.cursor,!(a()||(Dr.cursor=Dr.limit-r,m()||(Dr.cursor=Dr.limit-r,K())))||(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K()),!0)))}function Q(){var r,i,e=Dr.limit-Dr.cursor;if(Dr.ket=Dr.cursor,!p()&&(Dr.cursor=Dr.limit-e,!f()&&(Dr.cursor=Dr.limit-e,!_())))return!1;if(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,r=Dr.limit-Dr.cursor,a())Dr.bra=Dr.cursor,Dr.slice_del(),i=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,W()||(Dr.cursor=Dr.limit-i);else if(Dr.cursor=Dr.limit-r,!W())return!0;return Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,K(),!0}function R(){var r,i,e=Dr.limit-Dr.cursor;if(Dr.ket=Dr.cursor,W())return Dr.bra=Dr.cursor,Dr.slice_del(),void K();if(Dr.cursor=Dr.limit-e,Dr.ket=Dr.cursor,q())if(Dr.bra=Dr.cursor,Dr.slice_del(),r=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,d())Dr.bra=Dr.cursor,Dr.slice_del();else{if(Dr.cursor=Dr.limit-r,Dr.ket=Dr.cursor,!a()&&(Dr.cursor=Dr.limit-r,!m())){if(Dr.cursor=Dr.limit-r,Dr.ket=Dr.cursor,!W())return;if(Dr.bra=Dr.cursor,Dr.slice_del(),!K())return}Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K())}else if(Dr.cursor=Dr.limit-e,!M(e)&&(Dr.cursor=Dr.limit-e,!N(e))){if(Dr.cursor=Dr.limit-e,Dr.ket=Dr.cursor,y())return Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,i=Dr.limit-Dr.cursor,void(a()?(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K())):(Dr.cursor=Dr.limit-i,W()?(Dr.bra=Dr.cursor,Dr.slice_del(),K()):(Dr.cursor=Dr.limit-i,K())));if(Dr.cursor=Dr.limit-e,!O()){if(Dr.cursor=Dr.limit-e,d())return Dr.bra=Dr.cursor,void Dr.slice_del();Dr.cursor=Dr.limit-e,K()||(Dr.cursor=Dr.limit-e,Q()||(Dr.cursor=Dr.limit-e,Dr.ket=Dr.cursor,(a()||(Dr.cursor=Dr.limit-e,m()))&&(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K()))))}}}function U(){var r;if(Dr.ket=Dr.cursor,r=Dr.find_among_b(Sr,4))switch(Dr.bra=Dr.cursor,r){case 1:Dr.slice_from("p");break;case 2:Dr.slice_from("ç");break;case 3:Dr.slice_from("t");break;case 4:Dr.slice_from("k")}}function V(){for(;;){var r=Dr.limit-Dr.cursor;if(Dr.in_grouping_b(Wr,97,305)){Dr.cursor=Dr.limit-r;break}if(Dr.cursor=Dr.limit-r,Dr.cursor<=Dr.limit_backward)return!1;Dr.cursor--}return!0}function X(r,i,e){if(Dr.cursor=Dr.limit-r,V()){var n=Dr.limit-Dr.cursor;if(!Dr.eq_s_b(1,i)&&(Dr.cursor=Dr.limit-n,!Dr.eq_s_b(1,e)))return!0;Dr.cursor=Dr.limit-r;var t=Dr.cursor;return Dr.insert(Dr.cursor,Dr.cursor,e),Dr.cursor=t,!1}return!0}function Y(){var r=Dr.limit-Dr.cursor;(Dr.eq_s_b(1,"d")||(Dr.cursor=Dr.limit-r,Dr.eq_s_b(1,"g")))&&X(r,"a","ı")&&X(r,"e","i")&&X(r,"o","u")&&X(r,"ö","ü")}function $(){for(var r,i=Dr.cursor,e=2;;){for(r=Dr.cursor;!Dr.in_grouping(Wr,97,305);){if(Dr.cursor>=Dr.limit)return Dr.cursor=r,!(e>0)&&(Dr.cursor=i,!0);Dr.cursor++}e--}}function rr(r,i,e){for(;!Dr.eq_s(i,e);){if(Dr.cursor>=Dr.limit)return!0;Dr.cursor++}return(tr=i)!=Dr.limit||(Dr.cursor=r,!1)}function ir(){var r=Dr.cursor;return!rr(r,2,"ad")||(Dr.cursor=r,!rr(r,5,"soyad"))}function er(){var r=Dr.cursor;return!ir()&&(Dr.limit_backward=r,Dr.cursor=Dr.limit,Y(),Dr.cursor=Dr.limit,U(),!0)}var nr,tr,ur=[new i("m",-1,-1),new i("n",-1,-1),new i("miz",-1,-1),new i("niz",-1,-1),new i("muz",-1,-1),new i("nuz",-1,-1),new i("müz",-1,-1),new i("nüz",-1,-1),new i("mız",-1,-1),new i("nız",-1,-1)],or=[new i("leri",-1,-1),new i("ları",-1,-1)],sr=[new i("ni",-1,-1),new i("nu",-1,-1),new i("nü",-1,-1),new i("nı",-1,-1)],cr=[new i("in",-1,-1),new i("un",-1,-1),new i("ün",-1,-1),new i("ın",-1,-1)],lr=[new i("a",-1,-1),new i("e",-1,-1)],ar=[new i("na",-1,-1),new i("ne",-1,-1)],mr=[new i("da",-1,-1),new i("ta",-1,-1),new i("de",-1,-1),new i("te",-1,-1)],dr=[new i("nda",-1,-1),new i("nde",-1,-1)],fr=[new i("dan",-1,-1),new i("tan",-1,-1),new i("den",-1,-1),new i("ten",-1,-1)],br=[new i("ndan",-1,-1),new i("nden",-1,-1)],wr=[new i("la",-1,-1),new i("le",-1,-1)],_r=[new i("ca",-1,-1),new i("ce",-1,-1)],kr=[new i("im",-1,-1),new i("um",-1,-1),new i("üm",-1,-1),new i("ım",-1,-1)],pr=[new i("sin",-1,-1),new i("sun",-1,-1),new i("sün",-1,-1),new i("sın",-1,-1)],gr=[new i("iz",-1,-1),new i("uz",-1,-1),new i("üz",-1,-1),new i("ız",-1,-1)],yr=[new i("siniz",-1,-1),new i("sunuz",-1,-1),new i("sünüz",-1,-1),new i("sınız",-1,-1)],zr=[new i("lar",-1,-1),new i("ler",-1,-1)],vr=[new i("niz",-1,-1),new i("nuz",-1,-1),new i("nüz",-1,-1),new i("nız",-1,-1)],hr=[new i("dir",-1,-1),new i("tir",-1,-1),new i("dur",-1,-1),new i("tur",-1,-1),new i("dür",-1,-1),new i("tür",-1,-1),new i("dır",-1,-1),new i("tır",-1,-1)],qr=[new i("casına",-1,-1),new i("cesine",-1,-1)],Cr=[new i("di",-1,-1),new i("ti",-1,-1),new i("dik",-1,-1),new i("tik",-1,-1),new i("duk",-1,-1),new i("tuk",-1,-1),new i("dük",-1,-1),new i("tük",-1,-1),new i("dık",-1,-1),new i("tık",-1,-1),new i("dim",-1,-1),new i("tim",-1,-1),new i("dum",-1,-1),new i("tum",-1,-1),new i("düm",-1,-1),new i("tüm",-1,-1),new i("dım",-1,-1),new i("tım",-1,-1),new i("din",-1,-1),new i("tin",-1,-1),new i("dun",-1,-1),new i("tun",-1,-1),new i("dün",-1,-1),new i("tün",-1,-1),new i("dın",-1,-1),new i("tın",-1,-1),new i("du",-1,-1),new i("tu",-1,-1),new i("dü",-1,-1),new i("tü",-1,-1),new i("dı",-1,-1),new i("tı",-1,-1)],Pr=[new i("sa",-1,-1),new i("se",-1,-1),new i("sak",-1,-1),new i("sek",-1,-1),new i("sam",-1,-1),new i("sem",-1,-1),new i("san",-1,-1),new i("sen",-1,-1)],Fr=[new i("miş",-1,-1),new i("muş",-1,-1),new i("müş",-1,-1),new i("mış",-1,-1)],Sr=[new i("b",-1,1),new i("c",-1,2),new i("d",-1,3),new i("ğ",-1,4)],Wr=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,8,0,0,0,0,0,0,1],Lr=[1,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,1],xr=[1,64,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],Ar=[17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130],Er=[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],jr=[17],Tr=[65],Zr=[65],Br=[["a",xr,97,305],["e",Ar,101,252],["ı",Er,97,305],["i",jr,101,105],["o",Tr,111,117],["ö",Zr,246,252],["u",Tr,111,117]],Dr=new e;this.setCurrent=function(r){Dr.setCurrent(r)},this.getCurrent=function(){return Dr.getCurrent()},this.stem=function(){return!!($()&&(Dr.limit_backward=Dr.cursor,Dr.cursor=Dr.limit,J(),Dr.cursor=Dr.limit,nr&&(R(),Dr.cursor=Dr.limit_backward,er())))}};return function(r){return"function"==typeof r.update?r.update(function(r){return n.setCurrent(r),n.stem(),n.getCurrent()}):(n.setCurrent(r),n.stem(),n.getCurrent())}}(),r.Pipeline.registerFunction(r.tr.stemmer,"stemmer-tr"),r.tr.stopWordFilter=r.generateStopWordFilter("acaba altmış altı ama ancak arada aslında ayrıca bana bazı belki ben benden beni benim beri beş bile bin bir biri birkaç birkez birçok birşey birşeyi biz bizden bize bizi bizim bu buna bunda bundan bunlar bunları bunların bunu bunun burada böyle böylece da daha dahi de defa değil diye diğer doksan dokuz dolayı dolayısıyla dört edecek eden ederek edilecek ediliyor edilmesi ediyor elli en etmesi etti ettiği ettiğini eğer gibi göre halen hangi hatta hem henüz hep hepsi her herhangi herkesin hiç hiçbir iki ile ilgili ise itibaren itibariyle için işte kadar karşın katrilyon kendi kendilerine kendini kendisi kendisine kendisini kez ki kim kimden kime kimi kimse kırk milyar milyon mu mü mı nasıl ne neden nedenle nerde nerede nereye niye niçin o olan olarak oldu olduklarını olduğu olduğunu olmadı olmadığı olmak olması olmayan olmaz olsa olsun olup olur olursa oluyor on ona ondan onlar onlardan onları onların onu onun otuz oysa pek rağmen sadece sanki sekiz seksen sen senden seni senin siz sizden sizi sizin tarafından trilyon tüm var vardı ve veya ya yani yapacak yapmak yaptı yaptıkları yaptığı yaptığını yapılan yapılması yapıyor yedi yerine yetmiş yine yirmi yoksa yüz zaten çok çünkü öyle üzere üç şey şeyden şeyi şeyler şu şuna şunda şundan şunları şunu şöyle".split(" ")),r.Pipeline.registerFunction(r.tr.stopWordFilter,"stopWordFilter-tr")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.vi.min.js b/site/assets/javascripts/lunr/min/lunr.vi.min.js new file mode 100644 index 0000000000..22aed28c49 --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.vi.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.vi=function(){this.pipeline.reset(),this.pipeline.add(e.vi.stopWordFilter,e.vi.trimmer)},e.vi.wordCharacters="[A-Za-ẓ̀͐́͑̉̃̓ÂâÊêÔôĂ-ăĐ-đƠ-ơƯ-ư]",e.vi.trimmer=e.trimmerSupport.generateTrimmer(e.vi.wordCharacters),e.Pipeline.registerFunction(e.vi.trimmer,"trimmer-vi"),e.vi.stopWordFilter=e.generateStopWordFilter("là cái nhưng mà".split(" "))}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/min/lunr.zh.min.js b/site/assets/javascripts/lunr/min/lunr.zh.min.js new file mode 100644 index 0000000000..7727bbe24d --- /dev/null +++ b/site/assets/javascripts/lunr/min/lunr.zh.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r(require("nodejieba")):r()(e.lunr)}(this,function(e){return function(r,t){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==r.version[0];r.zh=function(){this.pipeline.reset(),this.pipeline.add(r.zh.trimmer,r.zh.stopWordFilter,r.zh.stemmer),i?this.tokenizer=r.zh.tokenizer:(r.tokenizer&&(r.tokenizer=r.zh.tokenizer),this.tokenizerFn&&(this.tokenizerFn=r.zh.tokenizer))},r.zh.tokenizer=function(n){if(!arguments.length||null==n||void 0==n)return[];if(Array.isArray(n))return n.map(function(e){return i?new r.Token(e.toLowerCase()):e.toLowerCase()});t&&e.load(t);var o=n.toString().trim().toLowerCase(),s=[];e.cut(o,!0).forEach(function(e){s=s.concat(e.split(" "))}),s=s.filter(function(e){return!!e});var u=0;return s.map(function(e,t){if(i){var n=o.indexOf(e,u),s={};return s.position=[n,e.length],s.index=t,u=n,new r.Token(e,s)}return e})},r.zh.wordCharacters="\\w一-龥",r.zh.trimmer=r.trimmerSupport.generateTrimmer(r.zh.wordCharacters),r.Pipeline.registerFunction(r.zh.trimmer,"trimmer-zh"),r.zh.stemmer=function(){return function(e){return e}}(),r.Pipeline.registerFunction(r.zh.stemmer,"stemmer-zh"),r.zh.stopWordFilter=r.generateStopWordFilter("的 一 不 在 人 有 是 为 以 于 上 他 而 后 之 来 及 了 因 下 可 到 由 这 与 也 此 但 并 个 其 已 无 小 我 们 起 最 再 今 去 好 只 又 或 很 亦 某 把 那 你 乃 它 吧 被 比 别 趁 当 从 到 得 打 凡 儿 尔 该 各 给 跟 和 何 还 即 几 既 看 据 距 靠 啦 了 另 么 每 们 嘛 拿 哪 那 您 凭 且 却 让 仍 啥 如 若 使 谁 虽 随 同 所 她 哇 嗡 往 哪 些 向 沿 哟 用 于 咱 则 怎 曾 至 致 着 诸 自".split(" ")),r.Pipeline.registerFunction(r.zh.stopWordFilter,"stopWordFilter-zh")}}); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/tinyseg.js b/site/assets/javascripts/lunr/tinyseg.js new file mode 100644 index 0000000000..167fa6dd69 --- /dev/null +++ b/site/assets/javascripts/lunr/tinyseg.js @@ -0,0 +1,206 @@ +/** + * export the module via AMD, CommonJS or as a browser global + * Export code from https://github.com/umdjs/umd/blob/master/returnExports.js + */ +;(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(factory) + } else if (typeof exports === 'object') { + /** + * Node. Does not work with strict CommonJS, but + * only CommonJS-like environments that support module.exports, + * like Node. + */ + module.exports = factory() + } else { + // Browser globals (root is window) + factory()(root.lunr); + } +}(this, function () { + /** + * Just return a value to define the module export. + * This example returns an object, but the module + * can return a function as the exported value. + */ + + return function(lunr) { + // TinySegmenter 0.1 -- Super compact Japanese tokenizer in Javascript + // (c) 2008 Taku Kudo + // TinySegmenter is freely distributable under the terms of a new BSD licence. + // For details, see http://chasen.org/~taku/software/TinySegmenter/LICENCE.txt + + function TinySegmenter() { + var patterns = { + "[一二三四五六七八九十百千万億兆]":"M", + "[一-龠々〆ヵヶ]":"H", + "[ぁ-ん]":"I", + "[ァ-ヴーア-ン゙ー]":"K", + "[a-zA-Za-zA-Z]":"A", + "[0-90-9]":"N" + } + this.chartype_ = []; + for (var i in patterns) { + var regexp = new RegExp(i); + this.chartype_.push([regexp, patterns[i]]); + } + + this.BIAS__ = -332 + this.BC1__ = {"HH":6,"II":2461,"KH":406,"OH":-1378}; + this.BC2__ = {"AA":-3267,"AI":2744,"AN":-878,"HH":-4070,"HM":-1711,"HN":4012,"HO":3761,"IA":1327,"IH":-1184,"II":-1332,"IK":1721,"IO":5492,"KI":3831,"KK":-8741,"MH":-3132,"MK":3334,"OO":-2920}; + this.BC3__ = {"HH":996,"HI":626,"HK":-721,"HN":-1307,"HO":-836,"IH":-301,"KK":2762,"MK":1079,"MM":4034,"OA":-1652,"OH":266}; + this.BP1__ = {"BB":295,"OB":304,"OO":-125,"UB":352}; + this.BP2__ = {"BO":60,"OO":-1762}; + this.BQ1__ = {"BHH":1150,"BHM":1521,"BII":-1158,"BIM":886,"BMH":1208,"BNH":449,"BOH":-91,"BOO":-2597,"OHI":451,"OIH":-296,"OKA":1851,"OKH":-1020,"OKK":904,"OOO":2965}; + this.BQ2__ = {"BHH":118,"BHI":-1159,"BHM":466,"BIH":-919,"BKK":-1720,"BKO":864,"OHH":-1139,"OHM":-181,"OIH":153,"UHI":-1146}; + this.BQ3__ = {"BHH":-792,"BHI":2664,"BII":-299,"BKI":419,"BMH":937,"BMM":8335,"BNN":998,"BOH":775,"OHH":2174,"OHM":439,"OII":280,"OKH":1798,"OKI":-793,"OKO":-2242,"OMH":-2402,"OOO":11699}; + this.BQ4__ = {"BHH":-3895,"BIH":3761,"BII":-4654,"BIK":1348,"BKK":-1806,"BMI":-3385,"BOO":-12396,"OAH":926,"OHH":266,"OHK":-2036,"ONN":-973}; + this.BW1__ = {",と":660,",同":727,"B1あ":1404,"B1同":542,"、と":660,"、同":727,"」と":1682,"あっ":1505,"いう":1743,"いっ":-2055,"いる":672,"うし":-4817,"うん":665,"から":3472,"がら":600,"こう":-790,"こと":2083,"こん":-1262,"さら":-4143,"さん":4573,"した":2641,"して":1104,"すで":-3399,"そこ":1977,"それ":-871,"たち":1122,"ため":601,"った":3463,"つい":-802,"てい":805,"てき":1249,"でき":1127,"です":3445,"では":844,"とい":-4915,"とみ":1922,"どこ":3887,"ない":5713,"なっ":3015,"など":7379,"なん":-1113,"にし":2468,"には":1498,"にも":1671,"に対":-912,"の一":-501,"の中":741,"ませ":2448,"まで":1711,"まま":2600,"まる":-2155,"やむ":-1947,"よっ":-2565,"れた":2369,"れで":-913,"をし":1860,"を見":731,"亡く":-1886,"京都":2558,"取り":-2784,"大き":-2604,"大阪":1497,"平方":-2314,"引き":-1336,"日本":-195,"本当":-2423,"毎日":-2113,"目指":-724,"B1あ":1404,"B1同":542,"」と":1682}; + this.BW2__ = {"..":-11822,"11":-669,"――":-5730,"−−":-13175,"いう":-1609,"うか":2490,"かし":-1350,"かも":-602,"から":-7194,"かれ":4612,"がい":853,"がら":-3198,"きた":1941,"くな":-1597,"こと":-8392,"この":-4193,"させ":4533,"され":13168,"さん":-3977,"しい":-1819,"しか":-545,"した":5078,"して":972,"しな":939,"その":-3744,"たい":-1253,"たた":-662,"ただ":-3857,"たち":-786,"たと":1224,"たは":-939,"った":4589,"って":1647,"っと":-2094,"てい":6144,"てき":3640,"てく":2551,"ては":-3110,"ても":-3065,"でい":2666,"でき":-1528,"でし":-3828,"です":-4761,"でも":-4203,"とい":1890,"とこ":-1746,"とと":-2279,"との":720,"とみ":5168,"とも":-3941,"ない":-2488,"なが":-1313,"など":-6509,"なの":2614,"なん":3099,"にお":-1615,"にし":2748,"にな":2454,"によ":-7236,"に対":-14943,"に従":-4688,"に関":-11388,"のか":2093,"ので":-7059,"のに":-6041,"のの":-6125,"はい":1073,"はが":-1033,"はず":-2532,"ばれ":1813,"まし":-1316,"まで":-6621,"まれ":5409,"めて":-3153,"もい":2230,"もの":-10713,"らか":-944,"らし":-1611,"らに":-1897,"りし":651,"りま":1620,"れた":4270,"れて":849,"れば":4114,"ろう":6067,"われ":7901,"を通":-11877,"んだ":728,"んな":-4115,"一人":602,"一方":-1375,"一日":970,"一部":-1051,"上が":-4479,"会社":-1116,"出て":2163,"分の":-7758,"同党":970,"同日":-913,"大阪":-2471,"委員":-1250,"少な":-1050,"年度":-8669,"年間":-1626,"府県":-2363,"手権":-1982,"新聞":-4066,"日新":-722,"日本":-7068,"日米":3372,"曜日":-601,"朝鮮":-2355,"本人":-2697,"東京":-1543,"然と":-1384,"社会":-1276,"立て":-990,"第に":-1612,"米国":-4268,"11":-669}; + this.BW3__ = {"あた":-2194,"あり":719,"ある":3846,"い.":-1185,"い。":-1185,"いい":5308,"いえ":2079,"いく":3029,"いた":2056,"いっ":1883,"いる":5600,"いわ":1527,"うち":1117,"うと":4798,"えと":1454,"か.":2857,"か。":2857,"かけ":-743,"かっ":-4098,"かに":-669,"から":6520,"かり":-2670,"が,":1816,"が、":1816,"がき":-4855,"がけ":-1127,"がっ":-913,"がら":-4977,"がり":-2064,"きた":1645,"けど":1374,"こと":7397,"この":1542,"ころ":-2757,"さい":-714,"さを":976,"し,":1557,"し、":1557,"しい":-3714,"した":3562,"して":1449,"しな":2608,"しま":1200,"す.":-1310,"す。":-1310,"する":6521,"ず,":3426,"ず、":3426,"ずに":841,"そう":428,"た.":8875,"た。":8875,"たい":-594,"たの":812,"たり":-1183,"たる":-853,"だ.":4098,"だ。":4098,"だっ":1004,"った":-4748,"って":300,"てい":6240,"てお":855,"ても":302,"です":1437,"でに":-1482,"では":2295,"とう":-1387,"とし":2266,"との":541,"とも":-3543,"どう":4664,"ない":1796,"なく":-903,"など":2135,"に,":-1021,"に、":-1021,"にし":1771,"にな":1906,"には":2644,"の,":-724,"の、":-724,"の子":-1000,"は,":1337,"は、":1337,"べき":2181,"まし":1113,"ます":6943,"まっ":-1549,"まで":6154,"まれ":-793,"らし":1479,"られ":6820,"るる":3818,"れ,":854,"れ、":854,"れた":1850,"れて":1375,"れば":-3246,"れる":1091,"われ":-605,"んだ":606,"んで":798,"カ月":990,"会議":860,"入り":1232,"大会":2217,"始め":1681,"市":965,"新聞":-5055,"日,":974,"日、":974,"社会":2024,"カ月":990}; + this.TC1__ = {"AAA":1093,"HHH":1029,"HHM":580,"HII":998,"HOH":-390,"HOM":-331,"IHI":1169,"IOH":-142,"IOI":-1015,"IOM":467,"MMH":187,"OOI":-1832}; + this.TC2__ = {"HHO":2088,"HII":-1023,"HMM":-1154,"IHI":-1965,"KKH":703,"OII":-2649}; + this.TC3__ = {"AAA":-294,"HHH":346,"HHI":-341,"HII":-1088,"HIK":731,"HOH":-1486,"IHH":128,"IHI":-3041,"IHO":-1935,"IIH":-825,"IIM":-1035,"IOI":-542,"KHH":-1216,"KKA":491,"KKH":-1217,"KOK":-1009,"MHH":-2694,"MHM":-457,"MHO":123,"MMH":-471,"NNH":-1689,"NNO":662,"OHO":-3393}; + this.TC4__ = {"HHH":-203,"HHI":1344,"HHK":365,"HHM":-122,"HHN":182,"HHO":669,"HIH":804,"HII":679,"HOH":446,"IHH":695,"IHO":-2324,"IIH":321,"III":1497,"IIO":656,"IOO":54,"KAK":4845,"KKA":3386,"KKK":3065,"MHH":-405,"MHI":201,"MMH":-241,"MMM":661,"MOM":841}; + this.TQ1__ = {"BHHH":-227,"BHHI":316,"BHIH":-132,"BIHH":60,"BIII":1595,"BNHH":-744,"BOHH":225,"BOOO":-908,"OAKK":482,"OHHH":281,"OHIH":249,"OIHI":200,"OIIH":-68}; + this.TQ2__ = {"BIHH":-1401,"BIII":-1033,"BKAK":-543,"BOOO":-5591}; + this.TQ3__ = {"BHHH":478,"BHHM":-1073,"BHIH":222,"BHII":-504,"BIIH":-116,"BIII":-105,"BMHI":-863,"BMHM":-464,"BOMH":620,"OHHH":346,"OHHI":1729,"OHII":997,"OHMH":481,"OIHH":623,"OIIH":1344,"OKAK":2792,"OKHH":587,"OKKA":679,"OOHH":110,"OOII":-685}; + this.TQ4__ = {"BHHH":-721,"BHHM":-3604,"BHII":-966,"BIIH":-607,"BIII":-2181,"OAAA":-2763,"OAKK":180,"OHHH":-294,"OHHI":2446,"OHHO":480,"OHIH":-1573,"OIHH":1935,"OIHI":-493,"OIIH":626,"OIII":-4007,"OKAK":-8156}; + this.TW1__ = {"につい":-4681,"東京都":2026}; + this.TW2__ = {"ある程":-2049,"いった":-1256,"ころが":-2434,"しょう":3873,"その後":-4430,"だって":-1049,"ていた":1833,"として":-4657,"ともに":-4517,"もので":1882,"一気に":-792,"初めて":-1512,"同時に":-8097,"大きな":-1255,"対して":-2721,"社会党":-3216}; + this.TW3__ = {"いただ":-1734,"してい":1314,"として":-4314,"につい":-5483,"にとっ":-5989,"に当た":-6247,"ので,":-727,"ので、":-727,"のもの":-600,"れから":-3752,"十二月":-2287}; + this.TW4__ = {"いう.":8576,"いう。":8576,"からな":-2348,"してい":2958,"たが,":1516,"たが、":1516,"ている":1538,"という":1349,"ました":5543,"ません":1097,"ようと":-4258,"よると":5865}; + this.UC1__ = {"A":484,"K":93,"M":645,"O":-505}; + this.UC2__ = {"A":819,"H":1059,"I":409,"M":3987,"N":5775,"O":646}; + this.UC3__ = {"A":-1370,"I":2311}; + this.UC4__ = {"A":-2643,"H":1809,"I":-1032,"K":-3450,"M":3565,"N":3876,"O":6646}; + this.UC5__ = {"H":313,"I":-1238,"K":-799,"M":539,"O":-831}; + this.UC6__ = {"H":-506,"I":-253,"K":87,"M":247,"O":-387}; + this.UP1__ = {"O":-214}; + this.UP2__ = {"B":69,"O":935}; + this.UP3__ = {"B":189}; + this.UQ1__ = {"BH":21,"BI":-12,"BK":-99,"BN":142,"BO":-56,"OH":-95,"OI":477,"OK":410,"OO":-2422}; + this.UQ2__ = {"BH":216,"BI":113,"OK":1759}; + this.UQ3__ = {"BA":-479,"BH":42,"BI":1913,"BK":-7198,"BM":3160,"BN":6427,"BO":14761,"OI":-827,"ON":-3212}; + this.UW1__ = {",":156,"、":156,"「":-463,"あ":-941,"う":-127,"が":-553,"き":121,"こ":505,"で":-201,"と":-547,"ど":-123,"に":-789,"の":-185,"は":-847,"も":-466,"や":-470,"よ":182,"ら":-292,"り":208,"れ":169,"を":-446,"ん":-137,"・":-135,"主":-402,"京":-268,"区":-912,"午":871,"国":-460,"大":561,"委":729,"市":-411,"日":-141,"理":361,"生":-408,"県":-386,"都":-718,"「":-463,"・":-135}; + this.UW2__ = {",":-829,"、":-829,"〇":892,"「":-645,"」":3145,"あ":-538,"い":505,"う":134,"お":-502,"か":1454,"が":-856,"く":-412,"こ":1141,"さ":878,"ざ":540,"し":1529,"す":-675,"せ":300,"そ":-1011,"た":188,"だ":1837,"つ":-949,"て":-291,"で":-268,"と":-981,"ど":1273,"な":1063,"に":-1764,"の":130,"は":-409,"ひ":-1273,"べ":1261,"ま":600,"も":-1263,"や":-402,"よ":1639,"り":-579,"る":-694,"れ":571,"を":-2516,"ん":2095,"ア":-587,"カ":306,"キ":568,"ッ":831,"三":-758,"不":-2150,"世":-302,"中":-968,"主":-861,"事":492,"人":-123,"会":978,"保":362,"入":548,"初":-3025,"副":-1566,"北":-3414,"区":-422,"大":-1769,"天":-865,"太":-483,"子":-1519,"学":760,"実":1023,"小":-2009,"市":-813,"年":-1060,"強":1067,"手":-1519,"揺":-1033,"政":1522,"文":-1355,"新":-1682,"日":-1815,"明":-1462,"最":-630,"朝":-1843,"本":-1650,"東":-931,"果":-665,"次":-2378,"民":-180,"気":-1740,"理":752,"発":529,"目":-1584,"相":-242,"県":-1165,"立":-763,"第":810,"米":509,"自":-1353,"行":838,"西":-744,"見":-3874,"調":1010,"議":1198,"込":3041,"開":1758,"間":-1257,"「":-645,"」":3145,"ッ":831,"ア":-587,"カ":306,"キ":568}; + this.UW3__ = {",":4889,"1":-800,"−":-1723,"、":4889,"々":-2311,"〇":5827,"」":2670,"〓":-3573,"あ":-2696,"い":1006,"う":2342,"え":1983,"お":-4864,"か":-1163,"が":3271,"く":1004,"け":388,"げ":401,"こ":-3552,"ご":-3116,"さ":-1058,"し":-395,"す":584,"せ":3685,"そ":-5228,"た":842,"ち":-521,"っ":-1444,"つ":-1081,"て":6167,"で":2318,"と":1691,"ど":-899,"な":-2788,"に":2745,"の":4056,"は":4555,"ひ":-2171,"ふ":-1798,"へ":1199,"ほ":-5516,"ま":-4384,"み":-120,"め":1205,"も":2323,"や":-788,"よ":-202,"ら":727,"り":649,"る":5905,"れ":2773,"わ":-1207,"を":6620,"ん":-518,"ア":551,"グ":1319,"ス":874,"ッ":-1350,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278,"・":-3794,"一":-1619,"下":-1759,"世":-2087,"両":3815,"中":653,"主":-758,"予":-1193,"二":974,"人":2742,"今":792,"他":1889,"以":-1368,"低":811,"何":4265,"作":-361,"保":-2439,"元":4858,"党":3593,"全":1574,"公":-3030,"六":755,"共":-1880,"円":5807,"再":3095,"分":457,"初":2475,"別":1129,"前":2286,"副":4437,"力":365,"動":-949,"務":-1872,"化":1327,"北":-1038,"区":4646,"千":-2309,"午":-783,"協":-1006,"口":483,"右":1233,"各":3588,"合":-241,"同":3906,"和":-837,"員":4513,"国":642,"型":1389,"場":1219,"外":-241,"妻":2016,"学":-1356,"安":-423,"実":-1008,"家":1078,"小":-513,"少":-3102,"州":1155,"市":3197,"平":-1804,"年":2416,"広":-1030,"府":1605,"度":1452,"建":-2352,"当":-3885,"得":1905,"思":-1291,"性":1822,"戸":-488,"指":-3973,"政":-2013,"教":-1479,"数":3222,"文":-1489,"新":1764,"日":2099,"旧":5792,"昨":-661,"時":-1248,"曜":-951,"最":-937,"月":4125,"期":360,"李":3094,"村":364,"東":-805,"核":5156,"森":2438,"業":484,"氏":2613,"民":-1694,"決":-1073,"法":1868,"海":-495,"無":979,"物":461,"特":-3850,"生":-273,"用":914,"町":1215,"的":7313,"直":-1835,"省":792,"県":6293,"知":-1528,"私":4231,"税":401,"立":-960,"第":1201,"米":7767,"系":3066,"約":3663,"級":1384,"統":-4229,"総":1163,"線":1255,"者":6457,"能":725,"自":-2869,"英":785,"見":1044,"調":-562,"財":-733,"費":1777,"車":1835,"軍":1375,"込":-1504,"通":-1136,"選":-681,"郎":1026,"郡":4404,"部":1200,"金":2163,"長":421,"開":-1432,"間":1302,"関":-1282,"雨":2009,"電":-1045,"非":2066,"駅":1620,"1":-800,"」":2670,"・":-3794,"ッ":-1350,"ア":551,"グ":1319,"ス":874,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278}; + this.UW4__ = {",":3930,".":3508,"―":-4841,"、":3930,"。":3508,"〇":4999,"「":1895,"」":3798,"〓":-5156,"あ":4752,"い":-3435,"う":-640,"え":-2514,"お":2405,"か":530,"が":6006,"き":-4482,"ぎ":-3821,"く":-3788,"け":-4376,"げ":-4734,"こ":2255,"ご":1979,"さ":2864,"し":-843,"じ":-2506,"す":-731,"ず":1251,"せ":181,"そ":4091,"た":5034,"だ":5408,"ち":-3654,"っ":-5882,"つ":-1659,"て":3994,"で":7410,"と":4547,"な":5433,"に":6499,"ぬ":1853,"ね":1413,"の":7396,"は":8578,"ば":1940,"ひ":4249,"び":-4134,"ふ":1345,"へ":6665,"べ":-744,"ほ":1464,"ま":1051,"み":-2082,"む":-882,"め":-5046,"も":4169,"ゃ":-2666,"や":2795,"ょ":-1544,"よ":3351,"ら":-2922,"り":-9726,"る":-14896,"れ":-2613,"ろ":-4570,"わ":-1783,"を":13150,"ん":-2352,"カ":2145,"コ":1789,"セ":1287,"ッ":-724,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637,"・":-4371,"ー":-11870,"一":-2069,"中":2210,"予":782,"事":-190,"井":-1768,"人":1036,"以":544,"会":950,"体":-1286,"作":530,"側":4292,"先":601,"党":-2006,"共":-1212,"内":584,"円":788,"初":1347,"前":1623,"副":3879,"力":-302,"動":-740,"務":-2715,"化":776,"区":4517,"協":1013,"参":1555,"合":-1834,"和":-681,"員":-910,"器":-851,"回":1500,"国":-619,"園":-1200,"地":866,"場":-1410,"塁":-2094,"士":-1413,"多":1067,"大":571,"子":-4802,"学":-1397,"定":-1057,"寺":-809,"小":1910,"屋":-1328,"山":-1500,"島":-2056,"川":-2667,"市":2771,"年":374,"庁":-4556,"後":456,"性":553,"感":916,"所":-1566,"支":856,"改":787,"政":2182,"教":704,"文":522,"方":-856,"日":1798,"時":1829,"最":845,"月":-9066,"木":-485,"来":-442,"校":-360,"業":-1043,"氏":5388,"民":-2716,"気":-910,"沢":-939,"済":-543,"物":-735,"率":672,"球":-1267,"生":-1286,"産":-1101,"田":-2900,"町":1826,"的":2586,"目":922,"省":-3485,"県":2997,"空":-867,"立":-2112,"第":788,"米":2937,"系":786,"約":2171,"経":1146,"統":-1169,"総":940,"線":-994,"署":749,"者":2145,"能":-730,"般":-852,"行":-792,"規":792,"警":-1184,"議":-244,"谷":-1000,"賞":730,"車":-1481,"軍":1158,"輪":-1433,"込":-3370,"近":929,"道":-1291,"選":2596,"郎":-4866,"都":1192,"野":-1100,"銀":-2213,"長":357,"間":-2344,"院":-2297,"際":-2604,"電":-878,"領":-1659,"題":-792,"館":-1984,"首":1749,"高":2120,"「":1895,"」":3798,"・":-4371,"ッ":-724,"ー":-11870,"カ":2145,"コ":1789,"セ":1287,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637}; + this.UW5__ = {",":465,".":-299,"1":-514,"E2":-32768,"]":-2762,"、":465,"。":-299,"「":363,"あ":1655,"い":331,"う":-503,"え":1199,"お":527,"か":647,"が":-421,"き":1624,"ぎ":1971,"く":312,"げ":-983,"さ":-1537,"し":-1371,"す":-852,"だ":-1186,"ち":1093,"っ":52,"つ":921,"て":-18,"で":-850,"と":-127,"ど":1682,"な":-787,"に":-1224,"の":-635,"は":-578,"べ":1001,"み":502,"め":865,"ゃ":3350,"ょ":854,"り":-208,"る":429,"れ":504,"わ":419,"を":-1264,"ん":327,"イ":241,"ル":451,"ン":-343,"中":-871,"京":722,"会":-1153,"党":-654,"務":3519,"区":-901,"告":848,"員":2104,"大":-1296,"学":-548,"定":1785,"嵐":-1304,"市":-2991,"席":921,"年":1763,"思":872,"所":-814,"挙":1618,"新":-1682,"日":218,"月":-4353,"査":932,"格":1356,"機":-1508,"氏":-1347,"田":240,"町":-3912,"的":-3149,"相":1319,"省":-1052,"県":-4003,"研":-997,"社":-278,"空":-813,"統":1955,"者":-2233,"表":663,"語":-1073,"議":1219,"選":-1018,"郎":-368,"長":786,"間":1191,"題":2368,"館":-689,"1":-514,"E2":-32768,"「":363,"イ":241,"ル":451,"ン":-343}; + this.UW6__ = {",":227,".":808,"1":-270,"E1":306,"、":227,"。":808,"あ":-307,"う":189,"か":241,"が":-73,"く":-121,"こ":-200,"じ":1782,"す":383,"た":-428,"っ":573,"て":-1014,"で":101,"と":-105,"な":-253,"に":-149,"の":-417,"は":-236,"も":-206,"り":187,"る":-135,"を":195,"ル":-673,"ン":-496,"一":-277,"中":201,"件":-800,"会":624,"前":302,"区":1792,"員":-1212,"委":798,"学":-960,"市":887,"広":-695,"後":535,"業":-697,"相":753,"社":-507,"福":974,"空":-822,"者":1811,"連":463,"郎":1082,"1":-270,"E1":306,"ル":-673,"ン":-496}; + + return this; + } + TinySegmenter.prototype.ctype_ = function(str) { + for (var i in this.chartype_) { + if (str.match(this.chartype_[i][0])) { + return this.chartype_[i][1]; + } + } + return "O"; + } + + TinySegmenter.prototype.ts_ = function(v) { + if (v) { return v; } + return 0; + } + + TinySegmenter.prototype.segment = function(input) { + if (input == null || input == undefined || input == "") { + return []; + } + var result = []; + var seg = ["B3","B2","B1"]; + var ctype = ["O","O","O"]; + var o = input.split(""); + for (i = 0; i < o.length; ++i) { + seg.push(o[i]); + ctype.push(this.ctype_(o[i])) + } + seg.push("E1"); + seg.push("E2"); + seg.push("E3"); + ctype.push("O"); + ctype.push("O"); + ctype.push("O"); + var word = seg[3]; + var p1 = "U"; + var p2 = "U"; + var p3 = "U"; + for (var i = 4; i < seg.length - 3; ++i) { + var score = this.BIAS__; + var w1 = seg[i-3]; + var w2 = seg[i-2]; + var w3 = seg[i-1]; + var w4 = seg[i]; + var w5 = seg[i+1]; + var w6 = seg[i+2]; + var c1 = ctype[i-3]; + var c2 = ctype[i-2]; + var c3 = ctype[i-1]; + var c4 = ctype[i]; + var c5 = ctype[i+1]; + var c6 = ctype[i+2]; + score += this.ts_(this.UP1__[p1]); + score += this.ts_(this.UP2__[p2]); + score += this.ts_(this.UP3__[p3]); + score += this.ts_(this.BP1__[p1 + p2]); + score += this.ts_(this.BP2__[p2 + p3]); + score += this.ts_(this.UW1__[w1]); + score += this.ts_(this.UW2__[w2]); + score += this.ts_(this.UW3__[w3]); + score += this.ts_(this.UW4__[w4]); + score += this.ts_(this.UW5__[w5]); + score += this.ts_(this.UW6__[w6]); + score += this.ts_(this.BW1__[w2 + w3]); + score += this.ts_(this.BW2__[w3 + w4]); + score += this.ts_(this.BW3__[w4 + w5]); + score += this.ts_(this.TW1__[w1 + w2 + w3]); + score += this.ts_(this.TW2__[w2 + w3 + w4]); + score += this.ts_(this.TW3__[w3 + w4 + w5]); + score += this.ts_(this.TW4__[w4 + w5 + w6]); + score += this.ts_(this.UC1__[c1]); + score += this.ts_(this.UC2__[c2]); + score += this.ts_(this.UC3__[c3]); + score += this.ts_(this.UC4__[c4]); + score += this.ts_(this.UC5__[c5]); + score += this.ts_(this.UC6__[c6]); + score += this.ts_(this.BC1__[c2 + c3]); + score += this.ts_(this.BC2__[c3 + c4]); + score += this.ts_(this.BC3__[c4 + c5]); + score += this.ts_(this.TC1__[c1 + c2 + c3]); + score += this.ts_(this.TC2__[c2 + c3 + c4]); + score += this.ts_(this.TC3__[c3 + c4 + c5]); + score += this.ts_(this.TC4__[c4 + c5 + c6]); + // score += this.ts_(this.TC5__[c4 + c5 + c6]); + score += this.ts_(this.UQ1__[p1 + c1]); + score += this.ts_(this.UQ2__[p2 + c2]); + score += this.ts_(this.UQ3__[p3 + c3]); + score += this.ts_(this.BQ1__[p2 + c2 + c3]); + score += this.ts_(this.BQ2__[p2 + c3 + c4]); + score += this.ts_(this.BQ3__[p3 + c2 + c3]); + score += this.ts_(this.BQ4__[p3 + c3 + c4]); + score += this.ts_(this.TQ1__[p2 + c1 + c2 + c3]); + score += this.ts_(this.TQ2__[p2 + c2 + c3 + c4]); + score += this.ts_(this.TQ3__[p3 + c1 + c2 + c3]); + score += this.ts_(this.TQ4__[p3 + c2 + c3 + c4]); + var p = "O"; + if (score > 0) { + result.push(word); + word = ""; + p = "B"; + } + p1 = p2; + p2 = p3; + p3 = p; + word += seg[i]; + } + result.push(word); + + return result; + } + + lunr.TinySegmenter = TinySegmenter; + }; + +})); \ No newline at end of file diff --git a/site/assets/javascripts/lunr/wordcut.js b/site/assets/javascripts/lunr/wordcut.js new file mode 100644 index 0000000000..146f4b44bc --- /dev/null +++ b/site/assets/javascripts/lunr/wordcut.js @@ -0,0 +1,6708 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}(g.lunr || (g.lunr = {})).wordcut = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 1; + }) + this.addWords(words, false) + } + if(finalize){ + this.finalizeDict(); + } + }, + + dictSeek: function (l, r, ch, strOffset, pos) { + var ans = null; + while (l <= r) { + var m = Math.floor((l + r) / 2), + dict_item = this.dict[m], + len = dict_item.length; + if (len <= strOffset) { + l = m + 1; + } else { + var ch_ = dict_item[strOffset]; + if (ch_ < ch) { + l = m + 1; + } else if (ch_ > ch) { + r = m - 1; + } else { + ans = m; + if (pos == LEFT) { + r = m - 1; + } else { + l = m + 1; + } + } + } + } + return ans; + }, + + isFinal: function (acceptor) { + return this.dict[acceptor.l].length == acceptor.strOffset; + }, + + createAcceptor: function () { + return { + l: 0, + r: this.dict.length - 1, + strOffset: 0, + isFinal: false, + dict: this, + transit: function (ch) { + return this.dict.transit(this, ch); + }, + isError: false, + tag: "DICT", + w: 1, + type: "DICT" + }; + }, + + transit: function (acceptor, ch) { + var l = this.dictSeek(acceptor.l, + acceptor.r, + ch, + acceptor.strOffset, + LEFT); + if (l !== null) { + var r = this.dictSeek(l, + acceptor.r, + ch, + acceptor.strOffset, + RIGHT); + acceptor.l = l; + acceptor.r = r; + acceptor.strOffset++; + acceptor.isFinal = this.isFinal(acceptor); + } else { + acceptor.isError = true; + } + return acceptor; + }, + + sortuniq: function(a){ + return a.sort().filter(function(item, pos, arr){ + return !pos || item != arr[pos - 1]; + }) + }, + + flatten: function(a){ + //[[1,2],[3]] -> [1,2,3] + return [].concat.apply([], a); + } +}; +module.exports = WordcutDict; + +}).call(this,"/dist/tmp") +},{"glob":16,"path":22}],3:[function(require,module,exports){ +var WordRule = { + createAcceptor: function(tag) { + if (tag["WORD_RULE"]) + return null; + + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + var lch = ch.toLowerCase(); + if (lch >= "a" && lch <= "z") { + this.isFinal = true; + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "WORD_RULE", + type: "WORD_RULE", + w: 1}; + } +}; + +var NumberRule = { + createAcceptor: function(tag) { + if (tag["NUMBER_RULE"]) + return null; + + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + if (ch >= "0" && ch <= "9") { + this.isFinal = true; + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "NUMBER_RULE", + type: "NUMBER_RULE", + w: 1}; + } +}; + +var SpaceRule = { + tag: "SPACE_RULE", + createAcceptor: function(tag) { + + if (tag["SPACE_RULE"]) + return null; + + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + if (ch == " " || ch == "\t" || ch == "\r" || ch == "\n" || + ch == "\u00A0" || ch=="\u2003"//nbsp and emsp + ) { + this.isFinal = true; + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: SpaceRule.tag, + w: 1, + type: "SPACE_RULE"}; + } +} + +var SingleSymbolRule = { + tag: "SINSYM", + createAcceptor: function(tag) { + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + if (this.strOffset == 0 && ch.match(/^[\@\(\)\/\,\-\."`]$/)) { + this.isFinal = true; + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "SINSYM", + w: 1, + type: "SINSYM"}; + } +} + + +var LatinRules = [WordRule, SpaceRule, SingleSymbolRule, NumberRule]; + +module.exports = LatinRules; + +},{}],4:[function(require,module,exports){ +var _ = require("underscore") + , WordcutCore = require("./wordcut_core"); +var PathInfoBuilder = { + + /* + buildByPartAcceptors: function(path, acceptors, i) { + var + var genInfos = partAcceptors.reduce(function(genInfos, acceptor) { + + }, []); + + return genInfos; + } + */ + + buildByAcceptors: function(path, finalAcceptors, i) { + var self = this; + var infos = finalAcceptors.map(function(acceptor) { + var p = i - acceptor.strOffset + 1 + , _info = path[p]; + + var info = {p: p, + mw: _info.mw + (acceptor.mw === undefined ? 0 : acceptor.mw), + w: acceptor.w + _info.w, + unk: (acceptor.unk ? acceptor.unk : 0) + _info.unk, + type: acceptor.type}; + + if (acceptor.type == "PART") { + for(var j = p + 1; j <= i; j++) { + path[j].merge = p; + } + info.merge = p; + } + + return info; + }); + return infos.filter(function(info) { return info; }); + }, + + fallback: function(path, leftBoundary, text, i) { + var _info = path[leftBoundary]; + if (text[i].match(/[\u0E48-\u0E4E]/)) { + if (leftBoundary != 0) + leftBoundary = path[leftBoundary].p; + return {p: leftBoundary, + mw: 0, + w: 1 + _info.w, + unk: 1 + _info.unk, + type: "UNK"}; +/* } else if(leftBoundary > 0 && path[leftBoundary].type !== "UNK") { + leftBoundary = path[leftBoundary].p; + return {p: leftBoundary, + w: 1 + _info.w, + unk: 1 + _info.unk, + type: "UNK"}; */ + } else { + return {p: leftBoundary, + mw: _info.mw, + w: 1 + _info.w, + unk: 1 + _info.unk, + type: "UNK"}; + } + }, + + build: function(path, finalAcceptors, i, leftBoundary, text) { + var basicPathInfos = this.buildByAcceptors(path, finalAcceptors, i); + if (basicPathInfos.length > 0) { + return basicPathInfos; + } else { + return [this.fallback(path, leftBoundary, text, i)]; + } + } +}; + +module.exports = function() { + return _.clone(PathInfoBuilder); +} + +},{"./wordcut_core":8,"underscore":25}],5:[function(require,module,exports){ +var _ = require("underscore"); + + +var PathSelector = { + selectPath: function(paths) { + var path = paths.reduce(function(selectedPath, path) { + if (selectedPath == null) { + return path; + } else { + if (path.unk < selectedPath.unk) + return path; + if (path.unk == selectedPath.unk) { + if (path.mw < selectedPath.mw) + return path + if (path.mw == selectedPath.mw) { + if (path.w < selectedPath.w) + return path; + } + } + return selectedPath; + } + }, null); + return path; + }, + + createPath: function() { + return [{p:null, w:0, unk:0, type: "INIT", mw:0}]; + } +}; + +module.exports = function() { + return _.clone(PathSelector); +}; + +},{"underscore":25}],6:[function(require,module,exports){ +function isMatch(pat, offset, ch) { + if (pat.length <= offset) + return false; + var _ch = pat[offset]; + return _ch == ch || + (_ch.match(/[กข]/) && ch.match(/[ก-ฮ]/)) || + (_ch.match(/[มบ]/) && ch.match(/[ก-ฮ]/)) || + (_ch.match(/\u0E49/) && ch.match(/[\u0E48-\u0E4B]/)); +} + +var Rule0 = { + pat: "เหก็ม", + createAcceptor: function(tag) { + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + if (isMatch(Rule0.pat, this.strOffset,ch)) { + this.isFinal = (this.strOffset + 1 == Rule0.pat.length); + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "THAI_RULE", + type: "THAI_RULE", + w: 1}; + } +}; + +var PartRule = { + createAcceptor: function(tag) { + return {strOffset: 0, + patterns: [ + "แก", "เก", "ก้", "กก์", "กา", "กี", "กิ", "กืก" + ], + isFinal: false, + transit: function(ch) { + var offset = this.strOffset; + this.patterns = this.patterns.filter(function(pat) { + return isMatch(pat, offset, ch); + }); + + if (this.patterns.length > 0) { + var len = 1 + offset; + this.isFinal = this.patterns.some(function(pat) { + return pat.length == len; + }); + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "PART", + type: "PART", + unk: 1, + w: 1}; + } +}; + +var ThaiRules = [Rule0, PartRule]; + +module.exports = ThaiRules; + +},{}],7:[function(require,module,exports){ +var sys = require("sys") + , WordcutDict = require("./dict") + , WordcutCore = require("./wordcut_core") + , PathInfoBuilder = require("./path_info_builder") + , PathSelector = require("./path_selector") + , Acceptors = require("./acceptors") + , latinRules = require("./latin_rules") + , thaiRules = require("./thai_rules") + , _ = require("underscore"); + + +var Wordcut = Object.create(WordcutCore); +Wordcut.defaultPathInfoBuilder = PathInfoBuilder; +Wordcut.defaultPathSelector = PathSelector; +Wordcut.defaultAcceptors = Acceptors; +Wordcut.defaultLatinRules = latinRules; +Wordcut.defaultThaiRules = thaiRules; +Wordcut.defaultDict = WordcutDict; + + +Wordcut.initNoDict = function(dict_path) { + var self = this; + self.pathInfoBuilder = new self.defaultPathInfoBuilder; + self.pathSelector = new self.defaultPathSelector; + self.acceptors = new self.defaultAcceptors; + self.defaultLatinRules.forEach(function(rule) { + self.acceptors.creators.push(rule); + }); + self.defaultThaiRules.forEach(function(rule) { + self.acceptors.creators.push(rule); + }); +}; + +Wordcut.init = function(dict_path, withDefault, additionalWords) { + withDefault = withDefault || false; + this.initNoDict(); + var dict = _.clone(this.defaultDict); + dict.init(dict_path, withDefault, additionalWords); + this.acceptors.creators.push(dict); +}; + +module.exports = Wordcut; + +},{"./acceptors":1,"./dict":2,"./latin_rules":3,"./path_info_builder":4,"./path_selector":5,"./thai_rules":6,"./wordcut_core":8,"sys":28,"underscore":25}],8:[function(require,module,exports){ +var WordcutCore = { + + buildPath: function(text) { + var self = this + , path = self.pathSelector.createPath() + , leftBoundary = 0; + self.acceptors.reset(); + for (var i = 0; i < text.length; i++) { + var ch = text[i]; + self.acceptors.transit(ch); + + var possiblePathInfos = self + .pathInfoBuilder + .build(path, + self.acceptors.getFinalAcceptors(), + i, + leftBoundary, + text); + var selectedPath = self.pathSelector.selectPath(possiblePathInfos) + + path.push(selectedPath); + if (selectedPath.type !== "UNK") { + leftBoundary = i; + } + } + return path; + }, + + pathToRanges: function(path) { + var e = path.length - 1 + , ranges = []; + + while (e > 0) { + var info = path[e] + , s = info.p; + + if (info.merge !== undefined && ranges.length > 0) { + var r = ranges[ranges.length - 1]; + r.s = info.merge; + s = r.s; + } else { + ranges.push({s:s, e:e}); + } + e = s; + } + return ranges.reverse(); + }, + + rangesToText: function(text, ranges, delimiter) { + return ranges.map(function(r) { + return text.substring(r.s, r.e); + }).join(delimiter); + }, + + cut: function(text, delimiter) { + var path = this.buildPath(text) + , ranges = this.pathToRanges(path); + return this + .rangesToText(text, ranges, + (delimiter === undefined ? "|" : delimiter)); + }, + + cutIntoRanges: function(text, noText) { + var path = this.buildPath(text) + , ranges = this.pathToRanges(path); + + if (!noText) { + ranges.forEach(function(r) { + r.text = text.substring(r.s, r.e); + }); + } + return ranges; + }, + + cutIntoArray: function(text) { + var path = this.buildPath(text) + , ranges = this.pathToRanges(path); + + return ranges.map(function(r) { + return text.substring(r.s, r.e) + }); + } +}; + +module.exports = WordcutCore; + +},{}],9:[function(require,module,exports){ +// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 +// +// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! +// +// Originally from narwhal.js (http://narwhaljs.org) +// Copyright (c) 2009 Thomas Robinson <280north.com> +// +// 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 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. + +// when used in node, this will actually load the util module we depend on +// versus loading the builtin util module as happens otherwise +// this is a bug in node module loading as far as I am concerned +var util = require('util/'); + +var pSlice = Array.prototype.slice; +var hasOwn = Object.prototype.hasOwnProperty; + +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = module.exports = ok; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({ message: message, +// actual: actual, +// expected: expected }) + +assert.AssertionError = function AssertionError(options) { + this.name = 'AssertionError'; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + if (options.message) { + this.message = options.message; + this.generatedMessage = false; + } else { + this.message = getMessage(this); + this.generatedMessage = true; + } + var stackStartFunction = options.stackStartFunction || fail; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } + else { + // non v8 browsers so we can have a stacktrace + var err = new Error(); + if (err.stack) { + var out = err.stack; + + // try to strip useless frames + var fn_name = stackStartFunction.name; + var idx = out.indexOf('\n' + fn_name); + if (idx >= 0) { + // once we have located the function frame + // we need to strip out everything before it (and its line) + var next_line = out.indexOf('\n', idx + 1); + out = out.substring(next_line + 1); + } + + this.stack = out; + } + } +}; + +// assert.AssertionError instanceof Error +util.inherits(assert.AssertionError, Error); + +function replacer(key, value) { + if (util.isUndefined(value)) { + return '' + value; + } + if (util.isNumber(value) && !isFinite(value)) { + return value.toString(); + } + if (util.isFunction(value) || util.isRegExp(value)) { + return value.toString(); + } + return value; +} + +function truncate(s, n) { + if (util.isString(s)) { + return s.length < n ? s : s.slice(0, n); + } else { + return s; + } +} + +function getMessage(self) { + return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + + self.operator + ' ' + + truncate(JSON.stringify(self.expected, replacer), 128); +} + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, !!guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +function ok(value, message) { + if (!value) fail(value, true, message, '==', assert.ok); +} +assert.ok = ok; + +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, '==', assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, '!=', assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected)) { + fail(actual, expected, message, 'deepEqual', assert.deepEqual); + } +}; + +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + + } else if (util.isBuffer(actual) && util.isBuffer(expected)) { + if (actual.length != expected.length) return false; + + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) return false; + } + + return true; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (util.isDate(actual) && util.isDate(expected)) { + return actual.getTime() === expected.getTime(); + + // 7.3 If the expected value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object with the same source and + // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). + } else if (util.isRegExp(actual) && util.isRegExp(expected)) { + return actual.source === expected.source && + actual.global === expected.global && + actual.multiline === expected.multiline && + actual.lastIndex === expected.lastIndex && + actual.ignoreCase === expected.ignoreCase; + + // 7.4. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if (!util.isObject(actual) && !util.isObject(expected)) { + return actual == expected; + + // 7.5 For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } +} + +function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv(a, b) { + if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) + return false; + // an identical 'prototype' property. + if (a.prototype !== b.prototype) return false; + // if one is a primitive, the other must be same + if (util.isPrimitive(a) || util.isPrimitive(b)) { + return a === b; + } + var aIsArgs = isArguments(a), + bIsArgs = isArguments(b); + if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) + return false; + if (aIsArgs) { + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b); + } + var ka = objectKeys(a), + kb = objectKeys(b), + key, i; + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key])) return false; + } + return true; +} + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + } +}; + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, '===', assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as +// determined by !==. assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, '!==', assert.notStrictEqual); + } +}; + +function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } + + if (Object.prototype.toString.call(expected) == '[object RegExp]') { + return expected.test(actual); + } else if (actual instanceof expected) { + return true; + } else if (expected.call({}, actual) === true) { + return true; + } + + return false; +} + +function _throws(shouldThrow, block, expected, message) { + var actual; + + if (util.isString(expected)) { + message = expected; + expected = null; + } + + try { + block(); + } catch (e) { + actual = e; + } + + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + + (message ? ' ' + message : '.'); + + if (shouldThrow && !actual) { + fail(actual, expected, 'Missing expected exception' + message); + } + + if (!shouldThrow && expectedException(actual, expected)) { + fail(actual, expected, 'Got unwanted exception' + message); + } + + if ((shouldThrow && actual && expected && + !expectedException(actual, expected)) || (!shouldThrow && actual)) { + throw actual; + } +} + +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [true].concat(pSlice.call(arguments))); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/message) { + _throws.apply(this, [false].concat(pSlice.call(arguments))); +}; + +assert.ifError = function(err) { if (err) {throw err;}}; + +var objectKeys = Object.keys || function (obj) { + var keys = []; + for (var key in obj) { + if (hasOwn.call(obj, key)) keys.push(key); + } + return keys; +}; + +},{"util/":28}],10:[function(require,module,exports){ +'use strict'; +module.exports = balanced; +function balanced(a, b, str) { + if (a instanceof RegExp) a = maybeMatch(a, str); + if (b instanceof RegExp) b = maybeMatch(b, str); + + var r = range(a, b, str); + + return r && { + start: r[0], + end: r[1], + pre: str.slice(0, r[0]), + body: str.slice(r[0] + a.length, r[1]), + post: str.slice(r[1] + b.length) + }; +} + +function maybeMatch(reg, str) { + var m = str.match(reg); + return m ? m[0] : null; +} + +balanced.range = range; +function range(a, b, str) { + var begs, beg, left, right, result; + var ai = str.indexOf(a); + var bi = str.indexOf(b, ai + 1); + var i = ai; + + if (ai >= 0 && bi > 0) { + begs = []; + left = str.length; + + while (i >= 0 && !result) { + if (i == ai) { + begs.push(i); + ai = str.indexOf(a, i + 1); + } else if (begs.length == 1) { + result = [ begs.pop(), bi ]; + } else { + beg = begs.pop(); + if (beg < left) { + left = beg; + right = bi; + } + + bi = str.indexOf(b, i + 1); + } + + i = ai < bi && ai >= 0 ? ai : bi; + } + + if (begs.length) { + result = [ left, right ]; + } + } + + return result; +} + +},{}],11:[function(require,module,exports){ +var concatMap = require('concat-map'); +var balanced = require('balanced-match'); + +module.exports = expandTop; + +var escSlash = '\0SLASH'+Math.random()+'\0'; +var escOpen = '\0OPEN'+Math.random()+'\0'; +var escClose = '\0CLOSE'+Math.random()+'\0'; +var escComma = '\0COMMA'+Math.random()+'\0'; +var escPeriod = '\0PERIOD'+Math.random()+'\0'; + +function numeric(str) { + return parseInt(str, 10) == str + ? parseInt(str, 10) + : str.charCodeAt(0); +} + +function escapeBraces(str) { + return str.split('\\\\').join(escSlash) + .split('\\{').join(escOpen) + .split('\\}').join(escClose) + .split('\\,').join(escComma) + .split('\\.').join(escPeriod); +} + +function unescapeBraces(str) { + return str.split(escSlash).join('\\') + .split(escOpen).join('{') + .split(escClose).join('}') + .split(escComma).join(',') + .split(escPeriod).join('.'); +} + + +// Basically just str.split(","), but handling cases +// where we have nested braced sections, which should be +// treated as individual members, like {a,{b,c},d} +function parseCommaParts(str) { + if (!str) + return ['']; + + var parts = []; + var m = balanced('{', '}', str); + + if (!m) + return str.split(','); + + var pre = m.pre; + var body = m.body; + var post = m.post; + var p = pre.split(','); + + p[p.length-1] += '{' + body + '}'; + var postParts = parseCommaParts(post); + if (post.length) { + p[p.length-1] += postParts.shift(); + p.push.apply(p, postParts); + } + + parts.push.apply(parts, p); + + return parts; +} + +function expandTop(str) { + if (!str) + return []; + + // I don't know why Bash 4.3 does this, but it does. + // Anything starting with {} will have the first two bytes preserved + // but *only* at the top level, so {},a}b will not expand to anything, + // but a{},b}c will be expanded to [a}c,abc]. + // One could argue that this is a bug in Bash, but since the goal of + // this module is to match Bash's rules, we escape a leading {} + if (str.substr(0, 2) === '{}') { + str = '\\{\\}' + str.substr(2); + } + + return expand(escapeBraces(str), true).map(unescapeBraces); +} + +function identity(e) { + return e; +} + +function embrace(str) { + return '{' + str + '}'; +} +function isPadded(el) { + return /^-?0\d/.test(el); +} + +function lte(i, y) { + return i <= y; +} +function gte(i, y) { + return i >= y; +} + +function expand(str, isTop) { + var expansions = []; + + var m = balanced('{', '}', str); + if (!m || /\$$/.test(m.pre)) return [str]; + + var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); + var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); + var isSequence = isNumericSequence || isAlphaSequence; + var isOptions = m.body.indexOf(',') >= 0; + if (!isSequence && !isOptions) { + // {a},b} + if (m.post.match(/,.*\}/)) { + str = m.pre + '{' + m.body + escClose + m.post; + return expand(str); + } + return [str]; + } + + var n; + if (isSequence) { + n = m.body.split(/\.\./); + } else { + n = parseCommaParts(m.body); + if (n.length === 1) { + // x{{a,b}}y ==> x{a}y x{b}y + n = expand(n[0], false).map(embrace); + if (n.length === 1) { + var post = m.post.length + ? expand(m.post, false) + : ['']; + return post.map(function(p) { + return m.pre + n[0] + p; + }); + } + } + } + + // at this point, n is the parts, and we know it's not a comma set + // with a single entry. + + // no need to expand pre, since it is guaranteed to be free of brace-sets + var pre = m.pre; + var post = m.post.length + ? expand(m.post, false) + : ['']; + + var N; + + if (isSequence) { + var x = numeric(n[0]); + var y = numeric(n[1]); + var width = Math.max(n[0].length, n[1].length) + var incr = n.length == 3 + ? Math.abs(numeric(n[2])) + : 1; + var test = lte; + var reverse = y < x; + if (reverse) { + incr *= -1; + test = gte; + } + var pad = n.some(isPadded); + + N = []; + + for (var i = x; test(i, y); i += incr) { + var c; + if (isAlphaSequence) { + c = String.fromCharCode(i); + if (c === '\\') + c = ''; + } else { + c = String(i); + if (pad) { + var need = width - c.length; + if (need > 0) { + var z = new Array(need + 1).join('0'); + if (i < 0) + c = '-' + z + c.slice(1); + else + c = z + c; + } + } + } + N.push(c); + } + } else { + N = concatMap(n, function(el) { return expand(el, false) }); + } + + for (var j = 0; j < N.length; j++) { + for (var k = 0; k < post.length; k++) { + var expansion = pre + N[j] + post[k]; + if (!isTop || isSequence || expansion) + expansions.push(expansion); + } + } + + return expansions; +} + + +},{"balanced-match":10,"concat-map":13}],12:[function(require,module,exports){ + +},{}],13:[function(require,module,exports){ +module.exports = function (xs, fn) { + var res = []; + for (var i = 0; i < xs.length; i++) { + var x = fn(xs[i], i); + if (isArray(x)) res.push.apply(res, x); + else res.push(x); + } + return res; +}; + +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; + +},{}],14:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +function EventEmitter() { + this._events = this._events || {}; + this._maxListeners = this._maxListeners || undefined; +} +module.exports = EventEmitter; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +EventEmitter.defaultMaxListeners = 10; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function(n) { + if (!isNumber(n) || n < 0 || isNaN(n)) + throw TypeError('n must be a positive number'); + this._maxListeners = n; + return this; +}; + +EventEmitter.prototype.emit = function(type) { + var er, handler, len, args, i, listeners; + + if (!this._events) + this._events = {}; + + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events.error || + (isObject(this._events.error) && !this._events.error.length)) { + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } + throw TypeError('Uncaught, unspecified "error" event.'); + } + } + + handler = this._events[type]; + + if (isUndefined(handler)) + return false; + + if (isFunction(handler)) { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + handler.apply(this, args); + } + } else if (isObject(handler)) { + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + + listeners = handler.slice(); + len = listeners.length; + for (i = 0; i < len; i++) + listeners[i].apply(this, args); + } + + return true; +}; + +EventEmitter.prototype.addListener = function(type, listener) { + var m; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events) + this._events = {}; + + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (this._events.newListener) + this.emit('newListener', type, + isFunction(listener.listener) ? + listener.listener : listener); + + if (!this._events[type]) + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + else if (isObject(this._events[type])) + // If we've already got an array, just append. + this._events[type].push(listener); + else + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + + // Check for listener leak + if (isObject(this._events[type]) && !this._events[type].warned) { + var m; + if (!isUndefined(this._maxListeners)) { + m = this._maxListeners; + } else { + m = EventEmitter.defaultMaxListeners; + } + + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); + } + } + } + + return this; +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.once = function(type, listener) { + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + var fired = false; + + function g() { + this.removeListener(type, g); + + if (!fired) { + fired = true; + listener.apply(this, arguments); + } + } + + g.listener = listener; + this.on(type, g); + + return this; +}; + +// emits a 'removeListener' event iff the listener was removed +EventEmitter.prototype.removeListener = function(type, listener) { + var list, position, length, i; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events || !this._events[type]) + return this; + + list = this._events[type]; + length = list.length; + position = -1; + + if (list === listener || + (isFunction(list.listener) && list.listener === listener)) { + delete this._events[type]; + if (this._events.removeListener) + this.emit('removeListener', type, listener); + + } else if (isObject(list)) { + for (i = length; i-- > 0;) { + if (list[i] === listener || + (list[i].listener && list[i].listener === listener)) { + position = i; + break; + } + } + + if (position < 0) + return this; + + if (list.length === 1) { + list.length = 0; + delete this._events[type]; + } else { + list.splice(position, 1); + } + + if (this._events.removeListener) + this.emit('removeListener', type, listener); + } + + return this; +}; + +EventEmitter.prototype.removeAllListeners = function(type) { + var key, listeners; + + if (!this._events) + return this; + + // not listening for removeListener, no need to emit + if (!this._events.removeListener) { + if (arguments.length === 0) + this._events = {}; + else if (this._events[type]) + delete this._events[type]; + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + for (key in this._events) { + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = {}; + return this; + } + + listeners = this._events[type]; + + if (isFunction(listeners)) { + this.removeListener(type, listeners); + } else { + // LIFO order + while (listeners.length) + this.removeListener(type, listeners[listeners.length - 1]); + } + delete this._events[type]; + + return this; +}; + +EventEmitter.prototype.listeners = function(type) { + var ret; + if (!this._events || !this._events[type]) + ret = []; + else if (isFunction(this._events[type])) + ret = [this._events[type]]; + else + ret = this._events[type].slice(); + return ret; +}; + +EventEmitter.listenerCount = function(emitter, type) { + var ret; + if (!emitter._events || !emitter._events[type]) + ret = 0; + else if (isFunction(emitter._events[type])) + ret = 1; + else + ret = emitter._events[type].length; + return ret; +}; + +function isFunction(arg) { + return typeof arg === 'function'; +} + +function isNumber(arg) { + return typeof arg === 'number'; +} + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} + +function isUndefined(arg) { + return arg === void 0; +} + +},{}],15:[function(require,module,exports){ +(function (process){ +exports.alphasort = alphasort +exports.alphasorti = alphasorti +exports.setopts = setopts +exports.ownProp = ownProp +exports.makeAbs = makeAbs +exports.finish = finish +exports.mark = mark +exports.isIgnored = isIgnored +exports.childrenIgnored = childrenIgnored + +function ownProp (obj, field) { + return Object.prototype.hasOwnProperty.call(obj, field) +} + +var path = require("path") +var minimatch = require("minimatch") +var isAbsolute = require("path-is-absolute") +var Minimatch = minimatch.Minimatch + +function alphasorti (a, b) { + return a.toLowerCase().localeCompare(b.toLowerCase()) +} + +function alphasort (a, b) { + return a.localeCompare(b) +} + +function setupIgnores (self, options) { + self.ignore = options.ignore || [] + + if (!Array.isArray(self.ignore)) + self.ignore = [self.ignore] + + if (self.ignore.length) { + self.ignore = self.ignore.map(ignoreMap) + } +} + +function ignoreMap (pattern) { + var gmatcher = null + if (pattern.slice(-3) === '/**') { + var gpattern = pattern.replace(/(\/\*\*)+$/, '') + gmatcher = new Minimatch(gpattern) + } + + return { + matcher: new Minimatch(pattern), + gmatcher: gmatcher + } +} + +function setopts (self, pattern, options) { + if (!options) + options = {} + + // base-matching: just use globstar for that. + if (options.matchBase && -1 === pattern.indexOf("/")) { + if (options.noglobstar) { + throw new Error("base matching requires globstar") + } + pattern = "**/" + pattern + } + + self.silent = !!options.silent + self.pattern = pattern + self.strict = options.strict !== false + self.realpath = !!options.realpath + self.realpathCache = options.realpathCache || Object.create(null) + self.follow = !!options.follow + self.dot = !!options.dot + self.mark = !!options.mark + self.nodir = !!options.nodir + if (self.nodir) + self.mark = true + self.sync = !!options.sync + self.nounique = !!options.nounique + self.nonull = !!options.nonull + self.nosort = !!options.nosort + self.nocase = !!options.nocase + self.stat = !!options.stat + self.noprocess = !!options.noprocess + + self.maxLength = options.maxLength || Infinity + self.cache = options.cache || Object.create(null) + self.statCache = options.statCache || Object.create(null) + self.symlinks = options.symlinks || Object.create(null) + + setupIgnores(self, options) + + self.changedCwd = false + var cwd = process.cwd() + if (!ownProp(options, "cwd")) + self.cwd = cwd + else { + self.cwd = options.cwd + self.changedCwd = path.resolve(options.cwd) !== cwd + } + + self.root = options.root || path.resolve(self.cwd, "/") + self.root = path.resolve(self.root) + if (process.platform === "win32") + self.root = self.root.replace(/\\/g, "/") + + self.nomount = !!options.nomount + + // disable comments and negation unless the user explicitly + // passes in false as the option. + options.nonegate = options.nonegate === false ? false : true + options.nocomment = options.nocomment === false ? false : true + deprecationWarning(options) + + self.minimatch = new Minimatch(pattern, options) + self.options = self.minimatch.options +} + +// TODO(isaacs): remove entirely in v6 +// exported to reset in tests +exports.deprecationWarned +function deprecationWarning(options) { + if (!options.nonegate || !options.nocomment) { + if (process.noDeprecation !== true && !exports.deprecationWarned) { + var msg = 'glob WARNING: comments and negation will be disabled in v6' + if (process.throwDeprecation) + throw new Error(msg) + else if (process.traceDeprecation) + console.trace(msg) + else + console.error(msg) + + exports.deprecationWarned = true + } + } +} + +function finish (self) { + var nou = self.nounique + var all = nou ? [] : Object.create(null) + + for (var i = 0, l = self.matches.length; i < l; i ++) { + var matches = self.matches[i] + if (!matches || Object.keys(matches).length === 0) { + if (self.nonull) { + // do like the shell, and spit out the literal glob + var literal = self.minimatch.globSet[i] + if (nou) + all.push(literal) + else + all[literal] = true + } + } else { + // had matches + var m = Object.keys(matches) + if (nou) + all.push.apply(all, m) + else + m.forEach(function (m) { + all[m] = true + }) + } + } + + if (!nou) + all = Object.keys(all) + + if (!self.nosort) + all = all.sort(self.nocase ? alphasorti : alphasort) + + // at *some* point we statted all of these + if (self.mark) { + for (var i = 0; i < all.length; i++) { + all[i] = self._mark(all[i]) + } + if (self.nodir) { + all = all.filter(function (e) { + return !(/\/$/.test(e)) + }) + } + } + + if (self.ignore.length) + all = all.filter(function(m) { + return !isIgnored(self, m) + }) + + self.found = all +} + +function mark (self, p) { + var abs = makeAbs(self, p) + var c = self.cache[abs] + var m = p + if (c) { + var isDir = c === 'DIR' || Array.isArray(c) + var slash = p.slice(-1) === '/' + + if (isDir && !slash) + m += '/' + else if (!isDir && slash) + m = m.slice(0, -1) + + if (m !== p) { + var mabs = makeAbs(self, m) + self.statCache[mabs] = self.statCache[abs] + self.cache[mabs] = self.cache[abs] + } + } + + return m +} + +// lotta situps... +function makeAbs (self, f) { + var abs = f + if (f.charAt(0) === '/') { + abs = path.join(self.root, f) + } else if (isAbsolute(f) || f === '') { + abs = f + } else if (self.changedCwd) { + abs = path.resolve(self.cwd, f) + } else { + abs = path.resolve(f) + } + return abs +} + + +// Return true, if pattern ends with globstar '**', for the accompanying parent directory. +// Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents +function isIgnored (self, path) { + if (!self.ignore.length) + return false + + return self.ignore.some(function(item) { + return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) + }) +} + +function childrenIgnored (self, path) { + if (!self.ignore.length) + return false + + return self.ignore.some(function(item) { + return !!(item.gmatcher && item.gmatcher.match(path)) + }) +} + +}).call(this,require('_process')) +},{"_process":24,"minimatch":20,"path":22,"path-is-absolute":23}],16:[function(require,module,exports){ +(function (process){ +// Approach: +// +// 1. Get the minimatch set +// 2. For each pattern in the set, PROCESS(pattern, false) +// 3. Store matches per-set, then uniq them +// +// PROCESS(pattern, inGlobStar) +// Get the first [n] items from pattern that are all strings +// Join these together. This is PREFIX. +// If there is no more remaining, then stat(PREFIX) and +// add to matches if it succeeds. END. +// +// If inGlobStar and PREFIX is symlink and points to dir +// set ENTRIES = [] +// else readdir(PREFIX) as ENTRIES +// If fail, END +// +// with ENTRIES +// If pattern[n] is GLOBSTAR +// // handle the case where the globstar match is empty +// // by pruning it out, and testing the resulting pattern +// PROCESS(pattern[0..n] + pattern[n+1 .. $], false) +// // handle other cases. +// for ENTRY in ENTRIES (not dotfiles) +// // attach globstar + tail onto the entry +// // Mark that this entry is a globstar match +// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true) +// +// else // not globstar +// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot) +// Test ENTRY against pattern[n] +// If fails, continue +// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $]) +// +// Caveat: +// Cache all stats and readdirs results to minimize syscall. Since all +// we ever care about is existence and directory-ness, we can just keep +// `true` for files, and [children,...] for directories, or `false` for +// things that don't exist. + +module.exports = glob + +var fs = require('fs') +var minimatch = require('minimatch') +var Minimatch = minimatch.Minimatch +var inherits = require('inherits') +var EE = require('events').EventEmitter +var path = require('path') +var assert = require('assert') +var isAbsolute = require('path-is-absolute') +var globSync = require('./sync.js') +var common = require('./common.js') +var alphasort = common.alphasort +var alphasorti = common.alphasorti +var setopts = common.setopts +var ownProp = common.ownProp +var inflight = require('inflight') +var util = require('util') +var childrenIgnored = common.childrenIgnored +var isIgnored = common.isIgnored + +var once = require('once') + +function glob (pattern, options, cb) { + if (typeof options === 'function') cb = options, options = {} + if (!options) options = {} + + if (options.sync) { + if (cb) + throw new TypeError('callback provided to sync glob') + return globSync(pattern, options) + } + + return new Glob(pattern, options, cb) +} + +glob.sync = globSync +var GlobSync = glob.GlobSync = globSync.GlobSync + +// old api surface +glob.glob = glob + +glob.hasMagic = function (pattern, options_) { + var options = util._extend({}, options_) + options.noprocess = true + + var g = new Glob(pattern, options) + var set = g.minimatch.set + if (set.length > 1) + return true + + for (var j = 0; j < set[0].length; j++) { + if (typeof set[0][j] !== 'string') + return true + } + + return false +} + +glob.Glob = Glob +inherits(Glob, EE) +function Glob (pattern, options, cb) { + if (typeof options === 'function') { + cb = options + options = null + } + + if (options && options.sync) { + if (cb) + throw new TypeError('callback provided to sync glob') + return new GlobSync(pattern, options) + } + + if (!(this instanceof Glob)) + return new Glob(pattern, options, cb) + + setopts(this, pattern, options) + this._didRealPath = false + + // process each pattern in the minimatch set + var n = this.minimatch.set.length + + // The matches are stored as {: true,...} so that + // duplicates are automagically pruned. + // Later, we do an Object.keys() on these. + // Keep them as a list so we can fill in when nonull is set. + this.matches = new Array(n) + + if (typeof cb === 'function') { + cb = once(cb) + this.on('error', cb) + this.on('end', function (matches) { + cb(null, matches) + }) + } + + var self = this + var n = this.minimatch.set.length + this._processing = 0 + this.matches = new Array(n) + + this._emitQueue = [] + this._processQueue = [] + this.paused = false + + if (this.noprocess) + return this + + if (n === 0) + return done() + + for (var i = 0; i < n; i ++) { + this._process(this.minimatch.set[i], i, false, done) + } + + function done () { + --self._processing + if (self._processing <= 0) + self._finish() + } +} + +Glob.prototype._finish = function () { + assert(this instanceof Glob) + if (this.aborted) + return + + if (this.realpath && !this._didRealpath) + return this._realpath() + + common.finish(this) + this.emit('end', this.found) +} + +Glob.prototype._realpath = function () { + if (this._didRealpath) + return + + this._didRealpath = true + + var n = this.matches.length + if (n === 0) + return this._finish() + + var self = this + for (var i = 0; i < this.matches.length; i++) + this._realpathSet(i, next) + + function next () { + if (--n === 0) + self._finish() + } +} + +Glob.prototype._realpathSet = function (index, cb) { + var matchset = this.matches[index] + if (!matchset) + return cb() + + var found = Object.keys(matchset) + var self = this + var n = found.length + + if (n === 0) + return cb() + + var set = this.matches[index] = Object.create(null) + found.forEach(function (p, i) { + // If there's a problem with the stat, then it means that + // one or more of the links in the realpath couldn't be + // resolved. just return the abs value in that case. + p = self._makeAbs(p) + fs.realpath(p, self.realpathCache, function (er, real) { + if (!er) + set[real] = true + else if (er.syscall === 'stat') + set[p] = true + else + self.emit('error', er) // srsly wtf right here + + if (--n === 0) { + self.matches[index] = set + cb() + } + }) + }) +} + +Glob.prototype._mark = function (p) { + return common.mark(this, p) +} + +Glob.prototype._makeAbs = function (f) { + return common.makeAbs(this, f) +} + +Glob.prototype.abort = function () { + this.aborted = true + this.emit('abort') +} + +Glob.prototype.pause = function () { + if (!this.paused) { + this.paused = true + this.emit('pause') + } +} + +Glob.prototype.resume = function () { + if (this.paused) { + this.emit('resume') + this.paused = false + if (this._emitQueue.length) { + var eq = this._emitQueue.slice(0) + this._emitQueue.length = 0 + for (var i = 0; i < eq.length; i ++) { + var e = eq[i] + this._emitMatch(e[0], e[1]) + } + } + if (this._processQueue.length) { + var pq = this._processQueue.slice(0) + this._processQueue.length = 0 + for (var i = 0; i < pq.length; i ++) { + var p = pq[i] + this._processing-- + this._process(p[0], p[1], p[2], p[3]) + } + } + } +} + +Glob.prototype._process = function (pattern, index, inGlobStar, cb) { + assert(this instanceof Glob) + assert(typeof cb === 'function') + + if (this.aborted) + return + + this._processing++ + if (this.paused) { + this._processQueue.push([pattern, index, inGlobStar, cb]) + return + } + + //console.error('PROCESS %d', this._processing, pattern) + + // Get the first [n] parts of pattern that are all strings. + var n = 0 + while (typeof pattern[n] === 'string') { + n ++ + } + // now n is the index of the first one that is *not* a string. + + // see if there's anything else + var prefix + switch (n) { + // if not, then this is rather simple + case pattern.length: + this._processSimple(pattern.join('/'), index, cb) + return + + case 0: + // pattern *starts* with some non-trivial item. + // going to readdir(cwd), but not include the prefix in matches. + prefix = null + break + + default: + // pattern has some string bits in the front. + // whatever it starts with, whether that's 'absolute' like /foo/bar, + // or 'relative' like '../baz' + prefix = pattern.slice(0, n).join('/') + break + } + + var remain = pattern.slice(n) + + // get the list of entries. + var read + if (prefix === null) + read = '.' + else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { + if (!prefix || !isAbsolute(prefix)) + prefix = '/' + prefix + read = prefix + } else + read = prefix + + var abs = this._makeAbs(read) + + //if ignored, skip _processing + if (childrenIgnored(this, read)) + return cb() + + var isGlobStar = remain[0] === minimatch.GLOBSTAR + if (isGlobStar) + this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb) + else + this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb) +} + +Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) { + var self = this + this._readdir(abs, inGlobStar, function (er, entries) { + return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb) + }) +} + +Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + + // if the abs isn't a dir, then nothing can match! + if (!entries) + return cb() + + // It will only match dot entries if it starts with a dot, or if + // dot is set. Stuff like @(.foo|.bar) isn't allowed. + var pn = remain[0] + var negate = !!this.minimatch.negate + var rawGlob = pn._glob + var dotOk = this.dot || rawGlob.charAt(0) === '.' + + var matchedEntries = [] + for (var i = 0; i < entries.length; i++) { + var e = entries[i] + if (e.charAt(0) !== '.' || dotOk) { + var m + if (negate && !prefix) { + m = !e.match(pn) + } else { + m = e.match(pn) + } + if (m) + matchedEntries.push(e) + } + } + + //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries) + + var len = matchedEntries.length + // If there are no matched entries, then nothing matches. + if (len === 0) + return cb() + + // if this is the last remaining pattern bit, then no need for + // an additional stat *unless* the user has specified mark or + // stat explicitly. We know they exist, since readdir returned + // them. + + if (remain.length === 1 && !this.mark && !this.stat) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + if (prefix) { + if (prefix !== '/') + e = prefix + '/' + e + else + e = prefix + e + } + + if (e.charAt(0) === '/' && !this.nomount) { + e = path.join(this.root, e) + } + this._emitMatch(index, e) + } + // This was the last one, and no stats were needed + return cb() + } + + // now test all matched entries as stand-ins for that part + // of the pattern. + remain.shift() + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + var newPattern + if (prefix) { + if (prefix !== '/') + e = prefix + '/' + e + else + e = prefix + e + } + this._process([e].concat(remain), index, inGlobStar, cb) + } + cb() +} + +Glob.prototype._emitMatch = function (index, e) { + if (this.aborted) + return + + if (this.matches[index][e]) + return + + if (isIgnored(this, e)) + return + + if (this.paused) { + this._emitQueue.push([index, e]) + return + } + + var abs = this._makeAbs(e) + + if (this.nodir) { + var c = this.cache[abs] + if (c === 'DIR' || Array.isArray(c)) + return + } + + if (this.mark) + e = this._mark(e) + + this.matches[index][e] = true + + var st = this.statCache[abs] + if (st) + this.emit('stat', e, st) + + this.emit('match', e) +} + +Glob.prototype._readdirInGlobStar = function (abs, cb) { + if (this.aborted) + return + + // follow all symlinked directories forever + // just proceed as if this is a non-globstar situation + if (this.follow) + return this._readdir(abs, false, cb) + + var lstatkey = 'lstat\0' + abs + var self = this + var lstatcb = inflight(lstatkey, lstatcb_) + + if (lstatcb) + fs.lstat(abs, lstatcb) + + function lstatcb_ (er, lstat) { + if (er) + return cb() + + var isSym = lstat.isSymbolicLink() + self.symlinks[abs] = isSym + + // If it's not a symlink or a dir, then it's definitely a regular file. + // don't bother doing a readdir in that case. + if (!isSym && !lstat.isDirectory()) { + self.cache[abs] = 'FILE' + cb() + } else + self._readdir(abs, false, cb) + } +} + +Glob.prototype._readdir = function (abs, inGlobStar, cb) { + if (this.aborted) + return + + cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb) + if (!cb) + return + + //console.error('RD %j %j', +inGlobStar, abs) + if (inGlobStar && !ownProp(this.symlinks, abs)) + return this._readdirInGlobStar(abs, cb) + + if (ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (!c || c === 'FILE') + return cb() + + if (Array.isArray(c)) + return cb(null, c) + } + + var self = this + fs.readdir(abs, readdirCb(this, abs, cb)) +} + +function readdirCb (self, abs, cb) { + return function (er, entries) { + if (er) + self._readdirError(abs, er, cb) + else + self._readdirEntries(abs, entries, cb) + } +} + +Glob.prototype._readdirEntries = function (abs, entries, cb) { + if (this.aborted) + return + + // if we haven't asked to stat everything, then just + // assume that everything in there exists, so we can avoid + // having to stat it a second time. + if (!this.mark && !this.stat) { + for (var i = 0; i < entries.length; i ++) { + var e = entries[i] + if (abs === '/') + e = abs + e + else + e = abs + '/' + e + this.cache[e] = true + } + } + + this.cache[abs] = entries + return cb(null, entries) +} + +Glob.prototype._readdirError = function (f, er, cb) { + if (this.aborted) + return + + // handle errors, and cache the information + switch (er.code) { + case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 + case 'ENOTDIR': // totally normal. means it *does* exist. + this.cache[this._makeAbs(f)] = 'FILE' + break + + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + break + + default: // some unusual error. Treat as failure. + this.cache[this._makeAbs(f)] = false + if (this.strict) { + this.emit('error', er) + // If the error is handled, then we abort + // if not, we threw out of here + this.abort() + } + if (!this.silent) + console.error('glob error', er) + break + } + + return cb() +} + +Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) { + var self = this + this._readdir(abs, inGlobStar, function (er, entries) { + self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb) + }) +} + + +Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + //console.error('pgs2', prefix, remain[0], entries) + + // no entries means not a dir, so it can never have matches + // foo.txt/** doesn't match foo.txt + if (!entries) + return cb() + + // test without the globstar, and with every child both below + // and replacing the globstar. + var remainWithoutGlobStar = remain.slice(1) + var gspref = prefix ? [ prefix ] : [] + var noGlobStar = gspref.concat(remainWithoutGlobStar) + + // the noGlobStar pattern exits the inGlobStar state + this._process(noGlobStar, index, false, cb) + + var isSym = this.symlinks[abs] + var len = entries.length + + // If it's a symlink, and we're in a globstar, then stop + if (isSym && inGlobStar) + return cb() + + for (var i = 0; i < len; i++) { + var e = entries[i] + if (e.charAt(0) === '.' && !this.dot) + continue + + // these two cases enter the inGlobStar state + var instead = gspref.concat(entries[i], remainWithoutGlobStar) + this._process(instead, index, true, cb) + + var below = gspref.concat(entries[i], remain) + this._process(below, index, true, cb) + } + + cb() +} + +Glob.prototype._processSimple = function (prefix, index, cb) { + // XXX review this. Shouldn't it be doing the mounting etc + // before doing stat? kinda weird? + var self = this + this._stat(prefix, function (er, exists) { + self._processSimple2(prefix, index, er, exists, cb) + }) +} +Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) { + + //console.error('ps2', prefix, exists) + + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + // If it doesn't exist, then just mark the lack of results + if (!exists) + return cb() + + if (prefix && isAbsolute(prefix) && !this.nomount) { + var trail = /[\/\\]$/.test(prefix) + if (prefix.charAt(0) === '/') { + prefix = path.join(this.root, prefix) + } else { + prefix = path.resolve(this.root, prefix) + if (trail) + prefix += '/' + } + } + + if (process.platform === 'win32') + prefix = prefix.replace(/\\/g, '/') + + // Mark this as a match + this._emitMatch(index, prefix) + cb() +} + +// Returns either 'DIR', 'FILE', or false +Glob.prototype._stat = function (f, cb) { + var abs = this._makeAbs(f) + var needDir = f.slice(-1) === '/' + + if (f.length > this.maxLength) + return cb() + + if (!this.stat && ownProp(this.cache, abs)) { + var c = this.cache[abs] + + if (Array.isArray(c)) + c = 'DIR' + + // It exists, but maybe not how we need it + if (!needDir || c === 'DIR') + return cb(null, c) + + if (needDir && c === 'FILE') + return cb() + + // otherwise we have to stat, because maybe c=true + // if we know it exists, but not what it is. + } + + var exists + var stat = this.statCache[abs] + if (stat !== undefined) { + if (stat === false) + return cb(null, stat) + else { + var type = stat.isDirectory() ? 'DIR' : 'FILE' + if (needDir && type === 'FILE') + return cb() + else + return cb(null, type, stat) + } + } + + var self = this + var statcb = inflight('stat\0' + abs, lstatcb_) + if (statcb) + fs.lstat(abs, statcb) + + function lstatcb_ (er, lstat) { + if (lstat && lstat.isSymbolicLink()) { + // If it's a symlink, then treat it as the target, unless + // the target does not exist, then treat it as a file. + return fs.stat(abs, function (er, stat) { + if (er) + self._stat2(f, abs, null, lstat, cb) + else + self._stat2(f, abs, er, stat, cb) + }) + } else { + self._stat2(f, abs, er, lstat, cb) + } + } +} + +Glob.prototype._stat2 = function (f, abs, er, stat, cb) { + if (er) { + this.statCache[abs] = false + return cb() + } + + var needDir = f.slice(-1) === '/' + this.statCache[abs] = stat + + if (abs.slice(-1) === '/' && !stat.isDirectory()) + return cb(null, false, stat) + + var c = stat.isDirectory() ? 'DIR' : 'FILE' + this.cache[abs] = this.cache[abs] || c + + if (needDir && c !== 'DIR') + return cb() + + return cb(null, c, stat) +} + +}).call(this,require('_process')) +},{"./common.js":15,"./sync.js":17,"_process":24,"assert":9,"events":14,"fs":12,"inflight":18,"inherits":19,"minimatch":20,"once":21,"path":22,"path-is-absolute":23,"util":28}],17:[function(require,module,exports){ +(function (process){ +module.exports = globSync +globSync.GlobSync = GlobSync + +var fs = require('fs') +var minimatch = require('minimatch') +var Minimatch = minimatch.Minimatch +var Glob = require('./glob.js').Glob +var util = require('util') +var path = require('path') +var assert = require('assert') +var isAbsolute = require('path-is-absolute') +var common = require('./common.js') +var alphasort = common.alphasort +var alphasorti = common.alphasorti +var setopts = common.setopts +var ownProp = common.ownProp +var childrenIgnored = common.childrenIgnored + +function globSync (pattern, options) { + if (typeof options === 'function' || arguments.length === 3) + throw new TypeError('callback provided to sync glob\n'+ + 'See: https://github.com/isaacs/node-glob/issues/167') + + return new GlobSync(pattern, options).found +} + +function GlobSync (pattern, options) { + if (!pattern) + throw new Error('must provide pattern') + + if (typeof options === 'function' || arguments.length === 3) + throw new TypeError('callback provided to sync glob\n'+ + 'See: https://github.com/isaacs/node-glob/issues/167') + + if (!(this instanceof GlobSync)) + return new GlobSync(pattern, options) + + setopts(this, pattern, options) + + if (this.noprocess) + return this + + var n = this.minimatch.set.length + this.matches = new Array(n) + for (var i = 0; i < n; i ++) { + this._process(this.minimatch.set[i], i, false) + } + this._finish() +} + +GlobSync.prototype._finish = function () { + assert(this instanceof GlobSync) + if (this.realpath) { + var self = this + this.matches.forEach(function (matchset, index) { + var set = self.matches[index] = Object.create(null) + for (var p in matchset) { + try { + p = self._makeAbs(p) + var real = fs.realpathSync(p, self.realpathCache) + set[real] = true + } catch (er) { + if (er.syscall === 'stat') + set[self._makeAbs(p)] = true + else + throw er + } + } + }) + } + common.finish(this) +} + + +GlobSync.prototype._process = function (pattern, index, inGlobStar) { + assert(this instanceof GlobSync) + + // Get the first [n] parts of pattern that are all strings. + var n = 0 + while (typeof pattern[n] === 'string') { + n ++ + } + // now n is the index of the first one that is *not* a string. + + // See if there's anything else + var prefix + switch (n) { + // if not, then this is rather simple + case pattern.length: + this._processSimple(pattern.join('/'), index) + return + + case 0: + // pattern *starts* with some non-trivial item. + // going to readdir(cwd), but not include the prefix in matches. + prefix = null + break + + default: + // pattern has some string bits in the front. + // whatever it starts with, whether that's 'absolute' like /foo/bar, + // or 'relative' like '../baz' + prefix = pattern.slice(0, n).join('/') + break + } + + var remain = pattern.slice(n) + + // get the list of entries. + var read + if (prefix === null) + read = '.' + else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { + if (!prefix || !isAbsolute(prefix)) + prefix = '/' + prefix + read = prefix + } else + read = prefix + + var abs = this._makeAbs(read) + + //if ignored, skip processing + if (childrenIgnored(this, read)) + return + + var isGlobStar = remain[0] === minimatch.GLOBSTAR + if (isGlobStar) + this._processGlobStar(prefix, read, abs, remain, index, inGlobStar) + else + this._processReaddir(prefix, read, abs, remain, index, inGlobStar) +} + + +GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) { + var entries = this._readdir(abs, inGlobStar) + + // if the abs isn't a dir, then nothing can match! + if (!entries) + return + + // It will only match dot entries if it starts with a dot, or if + // dot is set. Stuff like @(.foo|.bar) isn't allowed. + var pn = remain[0] + var negate = !!this.minimatch.negate + var rawGlob = pn._glob + var dotOk = this.dot || rawGlob.charAt(0) === '.' + + var matchedEntries = [] + for (var i = 0; i < entries.length; i++) { + var e = entries[i] + if (e.charAt(0) !== '.' || dotOk) { + var m + if (negate && !prefix) { + m = !e.match(pn) + } else { + m = e.match(pn) + } + if (m) + matchedEntries.push(e) + } + } + + var len = matchedEntries.length + // If there are no matched entries, then nothing matches. + if (len === 0) + return + + // if this is the last remaining pattern bit, then no need for + // an additional stat *unless* the user has specified mark or + // stat explicitly. We know they exist, since readdir returned + // them. + + if (remain.length === 1 && !this.mark && !this.stat) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + if (prefix) { + if (prefix.slice(-1) !== '/') + e = prefix + '/' + e + else + e = prefix + e + } + + if (e.charAt(0) === '/' && !this.nomount) { + e = path.join(this.root, e) + } + this.matches[index][e] = true + } + // This was the last one, and no stats were needed + return + } + + // now test all matched entries as stand-ins for that part + // of the pattern. + remain.shift() + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + var newPattern + if (prefix) + newPattern = [prefix, e] + else + newPattern = [e] + this._process(newPattern.concat(remain), index, inGlobStar) + } +} + + +GlobSync.prototype._emitMatch = function (index, e) { + var abs = this._makeAbs(e) + if (this.mark) + e = this._mark(e) + + if (this.matches[index][e]) + return + + if (this.nodir) { + var c = this.cache[this._makeAbs(e)] + if (c === 'DIR' || Array.isArray(c)) + return + } + + this.matches[index][e] = true + if (this.stat) + this._stat(e) +} + + +GlobSync.prototype._readdirInGlobStar = function (abs) { + // follow all symlinked directories forever + // just proceed as if this is a non-globstar situation + if (this.follow) + return this._readdir(abs, false) + + var entries + var lstat + var stat + try { + lstat = fs.lstatSync(abs) + } catch (er) { + // lstat failed, doesn't exist + return null + } + + var isSym = lstat.isSymbolicLink() + this.symlinks[abs] = isSym + + // If it's not a symlink or a dir, then it's definitely a regular file. + // don't bother doing a readdir in that case. + if (!isSym && !lstat.isDirectory()) + this.cache[abs] = 'FILE' + else + entries = this._readdir(abs, false) + + return entries +} + +GlobSync.prototype._readdir = function (abs, inGlobStar) { + var entries + + if (inGlobStar && !ownProp(this.symlinks, abs)) + return this._readdirInGlobStar(abs) + + if (ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (!c || c === 'FILE') + return null + + if (Array.isArray(c)) + return c + } + + try { + return this._readdirEntries(abs, fs.readdirSync(abs)) + } catch (er) { + this._readdirError(abs, er) + return null + } +} + +GlobSync.prototype._readdirEntries = function (abs, entries) { + // if we haven't asked to stat everything, then just + // assume that everything in there exists, so we can avoid + // having to stat it a second time. + if (!this.mark && !this.stat) { + for (var i = 0; i < entries.length; i ++) { + var e = entries[i] + if (abs === '/') + e = abs + e + else + e = abs + '/' + e + this.cache[e] = true + } + } + + this.cache[abs] = entries + + // mark and cache dir-ness + return entries +} + +GlobSync.prototype._readdirError = function (f, er) { + // handle errors, and cache the information + switch (er.code) { + case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 + case 'ENOTDIR': // totally normal. means it *does* exist. + this.cache[this._makeAbs(f)] = 'FILE' + break + + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + break + + default: // some unusual error. Treat as failure. + this.cache[this._makeAbs(f)] = false + if (this.strict) + throw er + if (!this.silent) + console.error('glob error', er) + break + } +} + +GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) { + + var entries = this._readdir(abs, inGlobStar) + + // no entries means not a dir, so it can never have matches + // foo.txt/** doesn't match foo.txt + if (!entries) + return + + // test without the globstar, and with every child both below + // and replacing the globstar. + var remainWithoutGlobStar = remain.slice(1) + var gspref = prefix ? [ prefix ] : [] + var noGlobStar = gspref.concat(remainWithoutGlobStar) + + // the noGlobStar pattern exits the inGlobStar state + this._process(noGlobStar, index, false) + + var len = entries.length + var isSym = this.symlinks[abs] + + // If it's a symlink, and we're in a globstar, then stop + if (isSym && inGlobStar) + return + + for (var i = 0; i < len; i++) { + var e = entries[i] + if (e.charAt(0) === '.' && !this.dot) + continue + + // these two cases enter the inGlobStar state + var instead = gspref.concat(entries[i], remainWithoutGlobStar) + this._process(instead, index, true) + + var below = gspref.concat(entries[i], remain) + this._process(below, index, true) + } +} + +GlobSync.prototype._processSimple = function (prefix, index) { + // XXX review this. Shouldn't it be doing the mounting etc + // before doing stat? kinda weird? + var exists = this._stat(prefix) + + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + // If it doesn't exist, then just mark the lack of results + if (!exists) + return + + if (prefix && isAbsolute(prefix) && !this.nomount) { + var trail = /[\/\\]$/.test(prefix) + if (prefix.charAt(0) === '/') { + prefix = path.join(this.root, prefix) + } else { + prefix = path.resolve(this.root, prefix) + if (trail) + prefix += '/' + } + } + + if (process.platform === 'win32') + prefix = prefix.replace(/\\/g, '/') + + // Mark this as a match + this.matches[index][prefix] = true +} + +// Returns either 'DIR', 'FILE', or false +GlobSync.prototype._stat = function (f) { + var abs = this._makeAbs(f) + var needDir = f.slice(-1) === '/' + + if (f.length > this.maxLength) + return false + + if (!this.stat && ownProp(this.cache, abs)) { + var c = this.cache[abs] + + if (Array.isArray(c)) + c = 'DIR' + + // It exists, but maybe not how we need it + if (!needDir || c === 'DIR') + return c + + if (needDir && c === 'FILE') + return false + + // otherwise we have to stat, because maybe c=true + // if we know it exists, but not what it is. + } + + var exists + var stat = this.statCache[abs] + if (!stat) { + var lstat + try { + lstat = fs.lstatSync(abs) + } catch (er) { + return false + } + + if (lstat.isSymbolicLink()) { + try { + stat = fs.statSync(abs) + } catch (er) { + stat = lstat + } + } else { + stat = lstat + } + } + + this.statCache[abs] = stat + + var c = stat.isDirectory() ? 'DIR' : 'FILE' + this.cache[abs] = this.cache[abs] || c + + if (needDir && c !== 'DIR') + return false + + return c +} + +GlobSync.prototype._mark = function (p) { + return common.mark(this, p) +} + +GlobSync.prototype._makeAbs = function (f) { + return common.makeAbs(this, f) +} + +}).call(this,require('_process')) +},{"./common.js":15,"./glob.js":16,"_process":24,"assert":9,"fs":12,"minimatch":20,"path":22,"path-is-absolute":23,"util":28}],18:[function(require,module,exports){ +(function (process){ +var wrappy = require('wrappy') +var reqs = Object.create(null) +var once = require('once') + +module.exports = wrappy(inflight) + +function inflight (key, cb) { + if (reqs[key]) { + reqs[key].push(cb) + return null + } else { + reqs[key] = [cb] + return makeres(key) + } +} + +function makeres (key) { + return once(function RES () { + var cbs = reqs[key] + var len = cbs.length + var args = slice(arguments) + + // XXX It's somewhat ambiguous whether a new callback added in this + // pass should be queued for later execution if something in the + // list of callbacks throws, or if it should just be discarded. + // However, it's such an edge case that it hardly matters, and either + // choice is likely as surprising as the other. + // As it happens, we do go ahead and schedule it for later execution. + try { + for (var i = 0; i < len; i++) { + cbs[i].apply(null, args) + } + } finally { + if (cbs.length > len) { + // added more in the interim. + // de-zalgo, just in case, but don't call again. + cbs.splice(0, len) + process.nextTick(function () { + RES.apply(null, args) + }) + } else { + delete reqs[key] + } + } + }) +} + +function slice (args) { + var length = args.length + var array = [] + + for (var i = 0; i < length; i++) array[i] = args[i] + return array +} + +}).call(this,require('_process')) +},{"_process":24,"once":21,"wrappy":29}],19:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],20:[function(require,module,exports){ +module.exports = minimatch +minimatch.Minimatch = Minimatch + +var path = { sep: '/' } +try { + path = require('path') +} catch (er) {} + +var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} +var expand = require('brace-expansion') + +var plTypes = { + '!': { open: '(?:(?!(?:', close: '))[^/]*?)'}, + '?': { open: '(?:', close: ')?' }, + '+': { open: '(?:', close: ')+' }, + '*': { open: '(?:', close: ')*' }, + '@': { open: '(?:', close: ')' } +} + +// any single thing other than / +// don't need to escape / when using new RegExp() +var qmark = '[^/]' + +// * => any number of characters +var star = qmark + '*?' + +// ** when dots are allowed. Anything goes, except .. and . +// not (^ or / followed by one or two dots followed by $ or /), +// followed by anything, any number of times. +var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?' + +// not a ^ or / followed by a dot, +// followed by anything, any number of times. +var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?' + +// characters that need to be escaped in RegExp. +var reSpecials = charSet('().*{}+?[]^$\\!') + +// "abc" -> { a:true, b:true, c:true } +function charSet (s) { + return s.split('').reduce(function (set, c) { + set[c] = true + return set + }, {}) +} + +// normalizes slashes. +var slashSplit = /\/+/ + +minimatch.filter = filter +function filter (pattern, options) { + options = options || {} + return function (p, i, list) { + return minimatch(p, pattern, options) + } +} + +function ext (a, b) { + a = a || {} + b = b || {} + var t = {} + Object.keys(b).forEach(function (k) { + t[k] = b[k] + }) + Object.keys(a).forEach(function (k) { + t[k] = a[k] + }) + return t +} + +minimatch.defaults = function (def) { + if (!def || !Object.keys(def).length) return minimatch + + var orig = minimatch + + var m = function minimatch (p, pattern, options) { + return orig.minimatch(p, pattern, ext(def, options)) + } + + m.Minimatch = function Minimatch (pattern, options) { + return new orig.Minimatch(pattern, ext(def, options)) + } + + return m +} + +Minimatch.defaults = function (def) { + if (!def || !Object.keys(def).length) return Minimatch + return minimatch.defaults(def).Minimatch +} + +function minimatch (p, pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('glob pattern string required') + } + + if (!options) options = {} + + // shortcut: comments match nothing. + if (!options.nocomment && pattern.charAt(0) === '#') { + return false + } + + // "" only matches "" + if (pattern.trim() === '') return p === '' + + return new Minimatch(pattern, options).match(p) +} + +function Minimatch (pattern, options) { + if (!(this instanceof Minimatch)) { + return new Minimatch(pattern, options) + } + + if (typeof pattern !== 'string') { + throw new TypeError('glob pattern string required') + } + + if (!options) options = {} + pattern = pattern.trim() + + // windows support: need to use /, not \ + if (path.sep !== '/') { + pattern = pattern.split(path.sep).join('/') + } + + this.options = options + this.set = [] + this.pattern = pattern + this.regexp = null + this.negate = false + this.comment = false + this.empty = false + + // make the set of regexps etc. + this.make() +} + +Minimatch.prototype.debug = function () {} + +Minimatch.prototype.make = make +function make () { + // don't do it more than once. + if (this._made) return + + var pattern = this.pattern + var options = this.options + + // empty patterns and comments match nothing. + if (!options.nocomment && pattern.charAt(0) === '#') { + this.comment = true + return + } + if (!pattern) { + this.empty = true + return + } + + // step 1: figure out negation, etc. + this.parseNegate() + + // step 2: expand braces + var set = this.globSet = this.braceExpand() + + if (options.debug) this.debug = console.error + + this.debug(this.pattern, set) + + // step 3: now we have a set, so turn each one into a series of path-portion + // matching patterns. + // These will be regexps, except in the case of "**", which is + // set to the GLOBSTAR object for globstar behavior, + // and will not contain any / characters + set = this.globParts = set.map(function (s) { + return s.split(slashSplit) + }) + + this.debug(this.pattern, set) + + // glob --> regexps + set = set.map(function (s, si, set) { + return s.map(this.parse, this) + }, this) + + this.debug(this.pattern, set) + + // filter out everything that didn't compile properly. + set = set.filter(function (s) { + return s.indexOf(false) === -1 + }) + + this.debug(this.pattern, set) + + this.set = set +} + +Minimatch.prototype.parseNegate = parseNegate +function parseNegate () { + var pattern = this.pattern + var negate = false + var options = this.options + var negateOffset = 0 + + if (options.nonegate) return + + for (var i = 0, l = pattern.length + ; i < l && pattern.charAt(i) === '!' + ; i++) { + negate = !negate + negateOffset++ + } + + if (negateOffset) this.pattern = pattern.substr(negateOffset) + this.negate = negate +} + +// Brace expansion: +// a{b,c}d -> abd acd +// a{b,}c -> abc ac +// a{0..3}d -> a0d a1d a2d a3d +// a{b,c{d,e}f}g -> abg acdfg acefg +// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg +// +// Invalid sets are not expanded. +// a{2..}b -> a{2..}b +// a{b}c -> a{b}c +minimatch.braceExpand = function (pattern, options) { + return braceExpand(pattern, options) +} + +Minimatch.prototype.braceExpand = braceExpand + +function braceExpand (pattern, options) { + if (!options) { + if (this instanceof Minimatch) { + options = this.options + } else { + options = {} + } + } + + pattern = typeof pattern === 'undefined' + ? this.pattern : pattern + + if (typeof pattern === 'undefined') { + throw new TypeError('undefined pattern') + } + + if (options.nobrace || + !pattern.match(/\{.*\}/)) { + // shortcut. no need to expand. + return [pattern] + } + + return expand(pattern) +} + +// parse a component of the expanded set. +// At this point, no pattern may contain "/" in it +// so we're going to return a 2d array, where each entry is the full +// pattern, split on '/', and then turned into a regular expression. +// A regexp is made at the end which joins each array with an +// escaped /, and another full one which joins each regexp with |. +// +// Following the lead of Bash 4.1, note that "**" only has special meaning +// when it is the *only* thing in a path portion. Otherwise, any series +// of * is equivalent to a single *. Globstar behavior is enabled by +// default, and can be disabled by setting options.noglobstar. +Minimatch.prototype.parse = parse +var SUBPARSE = {} +function parse (pattern, isSub) { + if (pattern.length > 1024 * 64) { + throw new TypeError('pattern is too long') + } + + var options = this.options + + // shortcuts + if (!options.noglobstar && pattern === '**') return GLOBSTAR + if (pattern === '') return '' + + var re = '' + var hasMagic = !!options.nocase + var escaping = false + // ? => one single character + var patternListStack = [] + var negativeLists = [] + var stateChar + var inClass = false + var reClassStart = -1 + var classStart = -1 + // . and .. never match anything that doesn't start with ., + // even when options.dot is set. + var patternStart = pattern.charAt(0) === '.' ? '' // anything + // not (start or / followed by . or .. followed by / or end) + : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))' + : '(?!\\.)' + var self = this + + function clearStateChar () { + if (stateChar) { + // we had some state-tracking character + // that wasn't consumed by this pass. + switch (stateChar) { + case '*': + re += star + hasMagic = true + break + case '?': + re += qmark + hasMagic = true + break + default: + re += '\\' + stateChar + break + } + self.debug('clearStateChar %j %j', stateChar, re) + stateChar = false + } + } + + for (var i = 0, len = pattern.length, c + ; (i < len) && (c = pattern.charAt(i)) + ; i++) { + this.debug('%s\t%s %s %j', pattern, i, re, c) + + // skip over any that are escaped. + if (escaping && reSpecials[c]) { + re += '\\' + c + escaping = false + continue + } + + switch (c) { + case '/': + // completely not allowed, even escaped. + // Should already be path-split by now. + return false + + case '\\': + clearStateChar() + escaping = true + continue + + // the various stateChar values + // for the "extglob" stuff. + case '?': + case '*': + case '+': + case '@': + case '!': + this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c) + + // all of those are literals inside a class, except that + // the glob [!a] means [^a] in regexp + if (inClass) { + this.debug(' in class') + if (c === '!' && i === classStart + 1) c = '^' + re += c + continue + } + + // if we already have a stateChar, then it means + // that there was something like ** or +? in there. + // Handle the stateChar, then proceed with this one. + self.debug('call clearStateChar %j', stateChar) + clearStateChar() + stateChar = c + // if extglob is disabled, then +(asdf|foo) isn't a thing. + // just clear the statechar *now*, rather than even diving into + // the patternList stuff. + if (options.noext) clearStateChar() + continue + + case '(': + if (inClass) { + re += '(' + continue + } + + if (!stateChar) { + re += '\\(' + continue + } + + patternListStack.push({ + type: stateChar, + start: i - 1, + reStart: re.length, + open: plTypes[stateChar].open, + close: plTypes[stateChar].close + }) + // negation is (?:(?!js)[^/]*) + re += stateChar === '!' ? '(?:(?!(?:' : '(?:' + this.debug('plType %j %j', stateChar, re) + stateChar = false + continue + + case ')': + if (inClass || !patternListStack.length) { + re += '\\)' + continue + } + + clearStateChar() + hasMagic = true + var pl = patternListStack.pop() + // negation is (?:(?!js)[^/]*) + // The others are (?:) + re += pl.close + if (pl.type === '!') { + negativeLists.push(pl) + } + pl.reEnd = re.length + continue + + case '|': + if (inClass || !patternListStack.length || escaping) { + re += '\\|' + escaping = false + continue + } + + clearStateChar() + re += '|' + continue + + // these are mostly the same in regexp and glob + case '[': + // swallow any state-tracking char before the [ + clearStateChar() + + if (inClass) { + re += '\\' + c + continue + } + + inClass = true + classStart = i + reClassStart = re.length + re += c + continue + + case ']': + // a right bracket shall lose its special + // meaning and represent itself in + // a bracket expression if it occurs + // first in the list. -- POSIX.2 2.8.3.2 + if (i === classStart + 1 || !inClass) { + re += '\\' + c + escaping = false + continue + } + + // handle the case where we left a class open. + // "[z-a]" is valid, equivalent to "\[z-a\]" + if (inClass) { + // split where the last [ was, make sure we don't have + // an invalid re. if so, re-walk the contents of the + // would-be class to re-translate any characters that + // were passed through as-is + // TODO: It would probably be faster to determine this + // without a try/catch and a new RegExp, but it's tricky + // to do safely. For now, this is safe and works. + var cs = pattern.substring(classStart + 1, i) + try { + RegExp('[' + cs + ']') + } catch (er) { + // not a valid class! + var sp = this.parse(cs, SUBPARSE) + re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]' + hasMagic = hasMagic || sp[1] + inClass = false + continue + } + } + + // finish up the class. + hasMagic = true + inClass = false + re += c + continue + + default: + // swallow any state char that wasn't consumed + clearStateChar() + + if (escaping) { + // no need + escaping = false + } else if (reSpecials[c] + && !(c === '^' && inClass)) { + re += '\\' + } + + re += c + + } // switch + } // for + + // handle the case where we left a class open. + // "[abc" is valid, equivalent to "\[abc" + if (inClass) { + // split where the last [ was, and escape it + // this is a huge pita. We now have to re-walk + // the contents of the would-be class to re-translate + // any characters that were passed through as-is + cs = pattern.substr(classStart + 1) + sp = this.parse(cs, SUBPARSE) + re = re.substr(0, reClassStart) + '\\[' + sp[0] + hasMagic = hasMagic || sp[1] + } + + // handle the case where we had a +( thing at the *end* + // of the pattern. + // each pattern list stack adds 3 chars, and we need to go through + // and escape any | chars that were passed through as-is for the regexp. + // Go through and escape them, taking care not to double-escape any + // | chars that were already escaped. + for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) { + var tail = re.slice(pl.reStart + pl.open.length) + this.debug('setting tail', re, pl) + // maybe some even number of \, then maybe 1 \, followed by a | + tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) { + if (!$2) { + // the | isn't already escaped, so escape it. + $2 = '\\' + } + + // need to escape all those slashes *again*, without escaping the + // one that we need for escaping the | character. As it works out, + // escaping an even number of slashes can be done by simply repeating + // it exactly after itself. That's why this trick works. + // + // I am sorry that you have to see this. + return $1 + $1 + $2 + '|' + }) + + this.debug('tail=%j\n %s', tail, tail, pl, re) + var t = pl.type === '*' ? star + : pl.type === '?' ? qmark + : '\\' + pl.type + + hasMagic = true + re = re.slice(0, pl.reStart) + t + '\\(' + tail + } + + // handle trailing things that only matter at the very end. + clearStateChar() + if (escaping) { + // trailing \\ + re += '\\\\' + } + + // only need to apply the nodot start if the re starts with + // something that could conceivably capture a dot + var addPatternStart = false + switch (re.charAt(0)) { + case '.': + case '[': + case '(': addPatternStart = true + } + + // Hack to work around lack of negative lookbehind in JS + // A pattern like: *.!(x).!(y|z) needs to ensure that a name + // like 'a.xyz.yz' doesn't match. So, the first negative + // lookahead, has to look ALL the way ahead, to the end of + // the pattern. + for (var n = negativeLists.length - 1; n > -1; n--) { + var nl = negativeLists[n] + + var nlBefore = re.slice(0, nl.reStart) + var nlFirst = re.slice(nl.reStart, nl.reEnd - 8) + var nlLast = re.slice(nl.reEnd - 8, nl.reEnd) + var nlAfter = re.slice(nl.reEnd) + + nlLast += nlAfter + + // Handle nested stuff like *(*.js|!(*.json)), where open parens + // mean that we should *not* include the ) in the bit that is considered + // "after" the negated section. + var openParensBefore = nlBefore.split('(').length - 1 + var cleanAfter = nlAfter + for (i = 0; i < openParensBefore; i++) { + cleanAfter = cleanAfter.replace(/\)[+*?]?/, '') + } + nlAfter = cleanAfter + + var dollar = '' + if (nlAfter === '' && isSub !== SUBPARSE) { + dollar = '$' + } + var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast + re = newRe + } + + // if the re is not "" at this point, then we need to make sure + // it doesn't match against an empty path part. + // Otherwise a/* will match a/, which it should not. + if (re !== '' && hasMagic) { + re = '(?=.)' + re + } + + if (addPatternStart) { + re = patternStart + re + } + + // parsing just a piece of a larger pattern. + if (isSub === SUBPARSE) { + return [re, hasMagic] + } + + // skip the regexp for non-magical patterns + // unescape anything in it, though, so that it'll be + // an exact match against a file etc. + if (!hasMagic) { + return globUnescape(pattern) + } + + var flags = options.nocase ? 'i' : '' + try { + var regExp = new RegExp('^' + re + '$', flags) + } catch (er) { + // If it was an invalid regular expression, then it can't match + // anything. This trick looks for a character after the end of + // the string, which is of course impossible, except in multi-line + // mode, but it's not a /m regex. + return new RegExp('$.') + } + + regExp._glob = pattern + regExp._src = re + + return regExp +} + +minimatch.makeRe = function (pattern, options) { + return new Minimatch(pattern, options || {}).makeRe() +} + +Minimatch.prototype.makeRe = makeRe +function makeRe () { + if (this.regexp || this.regexp === false) return this.regexp + + // at this point, this.set is a 2d array of partial + // pattern strings, or "**". + // + // It's better to use .match(). This function shouldn't + // be used, really, but it's pretty convenient sometimes, + // when you just want to work with a regex. + var set = this.set + + if (!set.length) { + this.regexp = false + return this.regexp + } + var options = this.options + + var twoStar = options.noglobstar ? star + : options.dot ? twoStarDot + : twoStarNoDot + var flags = options.nocase ? 'i' : '' + + var re = set.map(function (pattern) { + return pattern.map(function (p) { + return (p === GLOBSTAR) ? twoStar + : (typeof p === 'string') ? regExpEscape(p) + : p._src + }).join('\\\/') + }).join('|') + + // must match entire pattern + // ending in a * or ** will make it less strict. + re = '^(?:' + re + ')$' + + // can match anything, as long as it's not this. + if (this.negate) re = '^(?!' + re + ').*$' + + try { + this.regexp = new RegExp(re, flags) + } catch (ex) { + this.regexp = false + } + return this.regexp +} + +minimatch.match = function (list, pattern, options) { + options = options || {} + var mm = new Minimatch(pattern, options) + list = list.filter(function (f) { + return mm.match(f) + }) + if (mm.options.nonull && !list.length) { + list.push(pattern) + } + return list +} + +Minimatch.prototype.match = match +function match (f, partial) { + this.debug('match', f, this.pattern) + // short-circuit in the case of busted things. + // comments, etc. + if (this.comment) return false + if (this.empty) return f === '' + + if (f === '/' && partial) return true + + var options = this.options + + // windows: need to use /, not \ + if (path.sep !== '/') { + f = f.split(path.sep).join('/') + } + + // treat the test path as a set of pathparts. + f = f.split(slashSplit) + this.debug(this.pattern, 'split', f) + + // just ONE of the pattern sets in this.set needs to match + // in order for it to be valid. If negating, then just one + // match means that we have failed. + // Either way, return on the first hit. + + var set = this.set + this.debug(this.pattern, 'set', set) + + // Find the basename of the path by looking for the last non-empty segment + var filename + var i + for (i = f.length - 1; i >= 0; i--) { + filename = f[i] + if (filename) break + } + + for (i = 0; i < set.length; i++) { + var pattern = set[i] + var file = f + if (options.matchBase && pattern.length === 1) { + file = [filename] + } + var hit = this.matchOne(file, pattern, partial) + if (hit) { + if (options.flipNegate) return true + return !this.negate + } + } + + // didn't get any hits. this is success if it's a negative + // pattern, failure otherwise. + if (options.flipNegate) return false + return this.negate +} + +// set partial to true to test if, for example, +// "/a/b" matches the start of "/*/b/*/d" +// Partial means, if you run out of file before you run +// out of pattern, then that's fine, as long as all +// the parts match. +Minimatch.prototype.matchOne = function (file, pattern, partial) { + var options = this.options + + this.debug('matchOne', + { 'this': this, file: file, pattern: pattern }) + + this.debug('matchOne', file.length, pattern.length) + + for (var fi = 0, + pi = 0, + fl = file.length, + pl = pattern.length + ; (fi < fl) && (pi < pl) + ; fi++, pi++) { + this.debug('matchOne loop') + var p = pattern[pi] + var f = file[fi] + + this.debug(pattern, p, f) + + // should be impossible. + // some invalid regexp stuff in the set. + if (p === false) return false + + if (p === GLOBSTAR) { + this.debug('GLOBSTAR', [pattern, p, f]) + + // "**" + // a/**/b/**/c would match the following: + // a/b/x/y/z/c + // a/x/y/z/b/c + // a/b/x/b/x/c + // a/b/c + // To do this, take the rest of the pattern after + // the **, and see if it would match the file remainder. + // If so, return success. + // If not, the ** "swallows" a segment, and try again. + // This is recursively awful. + // + // a/**/b/**/c matching a/b/x/y/z/c + // - a matches a + // - doublestar + // - matchOne(b/x/y/z/c, b/**/c) + // - b matches b + // - doublestar + // - matchOne(x/y/z/c, c) -> no + // - matchOne(y/z/c, c) -> no + // - matchOne(z/c, c) -> no + // - matchOne(c, c) yes, hit + var fr = fi + var pr = pi + 1 + if (pr === pl) { + this.debug('** at the end') + // a ** at the end will just swallow the rest. + // We have found a match. + // however, it will not swallow /.x, unless + // options.dot is set. + // . and .. are *never* matched by **, for explosively + // exponential reasons. + for (; fi < fl; fi++) { + if (file[fi] === '.' || file[fi] === '..' || + (!options.dot && file[fi].charAt(0) === '.')) return false + } + return true + } + + // ok, let's see if we can swallow whatever we can. + while (fr < fl) { + var swallowee = file[fr] + + this.debug('\nglobstar while', file, fr, pattern, pr, swallowee) + + // XXX remove this slice. Just pass the start index. + if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { + this.debug('globstar found match!', fr, fl, swallowee) + // found a match. + return true + } else { + // can't swallow "." or ".." ever. + // can only swallow ".foo" when explicitly asked. + if (swallowee === '.' || swallowee === '..' || + (!options.dot && swallowee.charAt(0) === '.')) { + this.debug('dot detected!', file, fr, pattern, pr) + break + } + + // ** swallows a segment, and continue. + this.debug('globstar swallow a segment, and continue') + fr++ + } + } + + // no match was found. + // However, in partial mode, we can't say this is necessarily over. + // If there's more *pattern* left, then + if (partial) { + // ran out of file + this.debug('\n>>> no match, partial?', file, fr, pattern, pr) + if (fr === fl) return true + } + return false + } + + // something other than ** + // non-magic patterns just have to match exactly + // patterns with magic have been turned into regexps. + var hit + if (typeof p === 'string') { + if (options.nocase) { + hit = f.toLowerCase() === p.toLowerCase() + } else { + hit = f === p + } + this.debug('string match', p, f, hit) + } else { + hit = f.match(p) + this.debug('pattern match', p, f, hit) + } + + if (!hit) return false + } + + // Note: ending in / means that we'll get a final "" + // at the end of the pattern. This can only match a + // corresponding "" at the end of the file. + // If the file ends in /, then it can only match a + // a pattern that ends in /, unless the pattern just + // doesn't have any more for it. But, a/b/ should *not* + // match "a/b/*", even though "" matches against the + // [^/]*? pattern, except in partial mode, where it might + // simply not be reached yet. + // However, a/b/ should still satisfy a/* + + // now either we fell off the end of the pattern, or we're done. + if (fi === fl && pi === pl) { + // ran out of pattern and filename at the same time. + // an exact hit! + return true + } else if (fi === fl) { + // ran out of file, but still had pattern left. + // this is ok if we're doing the match as part of + // a glob fs traversal. + return partial + } else if (pi === pl) { + // ran out of pattern, still have file left. + // this is only acceptable if we're on the very last + // empty segment of a file with a trailing slash. + // a/* should match a/b/ + var emptyFileEnd = (fi === fl - 1) && (file[fi] === '') + return emptyFileEnd + } + + // should be unreachable. + throw new Error('wtf?') +} + +// replace stuff like \* with * +function globUnescape (s) { + return s.replace(/\\(.)/g, '$1') +} + +function regExpEscape (s) { + return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') +} + +},{"brace-expansion":11,"path":22}],21:[function(require,module,exports){ +var wrappy = require('wrappy') +module.exports = wrappy(once) +module.exports.strict = wrappy(onceStrict) + +once.proto = once(function () { + Object.defineProperty(Function.prototype, 'once', { + value: function () { + return once(this) + }, + configurable: true + }) + + Object.defineProperty(Function.prototype, 'onceStrict', { + value: function () { + return onceStrict(this) + }, + configurable: true + }) +}) + +function once (fn) { + var f = function () { + if (f.called) return f.value + f.called = true + return f.value = fn.apply(this, arguments) + } + f.called = false + return f +} + +function onceStrict (fn) { + var f = function () { + if (f.called) + throw new Error(f.onceError) + f.called = true + return f.value = fn.apply(this, arguments) + } + var name = fn.name || 'Function wrapped with `once`' + f.onceError = name + " shouldn't be called more than once" + f.called = false + return f +} + +},{"wrappy":29}],22:[function(require,module,exports){ +(function (process){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +// resolves . and .. elements in a path array with directory names there +// must be no slashes, empty elements, or device names (c:\) in the array +// (so also no leading and trailing slashes - it does not distinguish +// relative and absolute paths) +function normalizeArray(parts, allowAboveRoot) { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up--; up) { + parts.unshift('..'); + } + } + + return parts; +} + +// Split a filename into [root, dir, basename, ext], unix version +// 'root' is just a slash, or nothing. +var splitPathRe = + /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; +var splitPath = function(filename) { + return splitPathRe.exec(filename).slice(1); +}; + +// path.resolve([from ...], to) +// posix version +exports.resolve = function() { + var resolvedPath = '', + resolvedAbsolute = false; + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? arguments[i] : process.cwd(); + + // Skip empty and invalid entries + if (typeof path !== 'string') { + throw new TypeError('Arguments to path.resolve must be strings'); + } else if (!path) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charAt(0) === '/'; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { + return !!p; + }), !resolvedAbsolute).join('/'); + + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; +}; + +// path.normalize(path) +// posix version +exports.normalize = function(path) { + var isAbsolute = exports.isAbsolute(path), + trailingSlash = substr(path, -1) === '/'; + + // Normalize the path + path = normalizeArray(filter(path.split('/'), function(p) { + return !!p; + }), !isAbsolute).join('/'); + + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + + return (isAbsolute ? '/' : '') + path; +}; + +// posix version +exports.isAbsolute = function(path) { + return path.charAt(0) === '/'; +}; + +// posix version +exports.join = function() { + var paths = Array.prototype.slice.call(arguments, 0); + return exports.normalize(filter(paths, function(p, index) { + if (typeof p !== 'string') { + throw new TypeError('Arguments to path.join must be strings'); + } + return p; + }).join('/')); +}; + + +// path.relative(from, to) +// posix version +exports.relative = function(from, to) { + from = exports.resolve(from).substr(1); + to = exports.resolve(to).substr(1); + + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + + return outputParts.join('/'); +}; + +exports.sep = '/'; +exports.delimiter = ':'; + +exports.dirname = function(path) { + var result = splitPath(path), + root = result[0], + dir = result[1]; + + if (!root && !dir) { + // No dirname whatsoever + return '.'; + } + + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.substr(0, dir.length - 1); + } + + return root + dir; +}; + + +exports.basename = function(path, ext) { + var f = splitPath(path)[2]; + // TODO: make this comparison case-insensitive on windows? + if (ext && f.substr(-1 * ext.length) === ext) { + f = f.substr(0, f.length - ext.length); + } + return f; +}; + + +exports.extname = function(path) { + return splitPath(path)[3]; +}; + +function filter (xs, f) { + if (xs.filter) return xs.filter(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + if (f(xs[i], i, xs)) res.push(xs[i]); + } + return res; +} + +// String.prototype.substr - negative index don't work in IE8 +var substr = 'ab'.substr(-1) === 'b' + ? function (str, start, len) { return str.substr(start, len) } + : function (str, start, len) { + if (start < 0) start = str.length + start; + return str.substr(start, len); + } +; + +}).call(this,require('_process')) +},{"_process":24}],23:[function(require,module,exports){ +(function (process){ +'use strict'; + +function posix(path) { + return path.charAt(0) === '/'; +} + +function win32(path) { + // https://github.com/nodejs/node/blob/b3fcc245fb25539909ef1d5eaa01dbf92e168633/lib/path.js#L56 + var splitDeviceRe = /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/; + var result = splitDeviceRe.exec(path); + var device = result[1] || ''; + var isUnc = Boolean(device && device.charAt(1) !== ':'); + + // UNC paths are always absolute + return Boolean(result[2] || isUnc); +} + +module.exports = process.platform === 'win32' ? win32 : posix; +module.exports.posix = posix; +module.exports.win32 = win32; + +}).call(this,require('_process')) +},{"_process":24}],24:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],25:[function(require,module,exports){ +// Underscore.js 1.8.3 +// http://underscorejs.org +// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Underscore may be freely distributed under the MIT license. + +(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `exports` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var + push = ArrayProto.push, + slice = ArrayProto.slice, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind, + nativeCreate = Object.create; + + // Naked function reference for surrogate-prototype-swapping. + var Ctor = function(){}; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { + if (obj instanceof _) return obj; + if (!(this instanceof _)) return new _(obj); + this._wrapped = obj; + }; + + // Export the Underscore object for **Node.js**, with + // backwards-compatibility for the old `require()` API. If we're in + // the browser, add `_` as a global object. + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else { + root._ = _; + } + + // Current version. + _.VERSION = '1.8.3'; + + // Internal function that returns an efficient (for current engines) version + // of the passed-in callback, to be repeatedly applied in other Underscore + // functions. + var optimizeCb = function(func, context, argCount) { + if (context === void 0) return func; + switch (argCount == null ? 3 : argCount) { + case 1: return function(value) { + return func.call(context, value); + }; + case 2: return function(value, other) { + return func.call(context, value, other); + }; + case 3: return function(value, index, collection) { + return func.call(context, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(context, accumulator, value, index, collection); + }; + } + return function() { + return func.apply(context, arguments); + }; + }; + + // A mostly-internal function to generate callbacks that can be applied + // to each element in a collection, returning the desired result — either + // identity, an arbitrary callback, a property matcher, or a property accessor. + var cb = function(value, context, argCount) { + if (value == null) return _.identity; + if (_.isFunction(value)) return optimizeCb(value, context, argCount); + if (_.isObject(value)) return _.matcher(value); + return _.property(value); + }; + _.iteratee = function(value, context) { + return cb(value, context, Infinity); + }; + + // An internal function for creating assigner functions. + var createAssigner = function(keysFunc, undefinedOnly) { + return function(obj) { + var length = arguments.length; + if (length < 2 || obj == null) return obj; + for (var index = 1; index < length; index++) { + var source = arguments[index], + keys = keysFunc(source), + l = keys.length; + for (var i = 0; i < l; i++) { + var key = keys[i]; + if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; + } + } + return obj; + }; + }; + + // An internal function for creating a new object that inherits from another. + var baseCreate = function(prototype) { + if (!_.isObject(prototype)) return {}; + if (nativeCreate) return nativeCreate(prototype); + Ctor.prototype = prototype; + var result = new Ctor; + Ctor.prototype = null; + return result; + }; + + var property = function(key) { + return function(obj) { + return obj == null ? void 0 : obj[key]; + }; + }; + + // Helper for collection methods to determine whether a collection + // should be iterated as an array or as an object + // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength + // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 + var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; + var getLength = property('length'); + var isArrayLike = function(collection) { + var length = getLength(collection); + return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; + }; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles raw objects in addition to array-likes. Treats all + // sparse array-likes as if they were dense. + _.each = _.forEach = function(obj, iteratee, context) { + iteratee = optimizeCb(iteratee, context); + var i, length; + if (isArrayLike(obj)) { + for (i = 0, length = obj.length; i < length; i++) { + iteratee(obj[i], i, obj); + } + } else { + var keys = _.keys(obj); + for (i = 0, length = keys.length; i < length; i++) { + iteratee(obj[keys[i]], keys[i], obj); + } + } + return obj; + }; + + // Return the results of applying the iteratee to each element. + _.map = _.collect = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length, + results = Array(length); + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + results[index] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + }; + + // Create a reducing function iterating left or right. + function createReduce(dir) { + // Optimized iterator function as using arguments.length + // in the main function will deoptimize the, see #1991. + function iterator(obj, iteratee, memo, keys, index, length) { + for (; index >= 0 && index < length; index += dir) { + var currentKey = keys ? keys[index] : index; + memo = iteratee(memo, obj[currentKey], currentKey, obj); + } + return memo; + } + + return function(obj, iteratee, memo, context) { + iteratee = optimizeCb(iteratee, context, 4); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length, + index = dir > 0 ? 0 : length - 1; + // Determine the initial value if none is provided. + if (arguments.length < 3) { + memo = obj[keys ? keys[index] : index]; + index += dir; + } + return iterator(obj, iteratee, memo, keys, index, length); + }; + } + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. + _.reduce = _.foldl = _.inject = createReduce(1); + + // The right-associative version of reduce, also known as `foldr`. + _.reduceRight = _.foldr = createReduce(-1); + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, predicate, context) { + var key; + if (isArrayLike(obj)) { + key = _.findIndex(obj, predicate, context); + } else { + key = _.findKey(obj, predicate, context); + } + if (key !== void 0 && key !== -1) return obj[key]; + }; + + // Return all the elements that pass a truth test. + // Aliased as `select`. + _.filter = _.select = function(obj, predicate, context) { + var results = []; + predicate = cb(predicate, context); + _.each(obj, function(value, index, list) { + if (predicate(value, index, list)) results.push(value); + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, predicate, context) { + return _.filter(obj, _.negate(cb(predicate)), context); + }; + + // Determine whether all of the elements match a truth test. + // Aliased as `all`. + _.every = _.all = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + if (!predicate(obj[currentKey], currentKey, obj)) return false; + } + return true; + }; + + // Determine if at least one element in the object matches a truth test. + // Aliased as `any`. + _.some = _.any = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + if (predicate(obj[currentKey], currentKey, obj)) return true; + } + return false; + }; + + // Determine if the array or object contains a given item (using `===`). + // Aliased as `includes` and `include`. + _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) { + if (!isArrayLike(obj)) obj = _.values(obj); + if (typeof fromIndex != 'number' || guard) fromIndex = 0; + return _.indexOf(obj, item, fromIndex) >= 0; + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + var isFunc = _.isFunction(method); + return _.map(obj, function(value) { + var func = isFunc ? method : value[method]; + return func == null ? func : func.apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, _.property(key)); + }; + + // Convenience version of a common use case of `filter`: selecting only objects + // containing specific `key:value` pairs. + _.where = function(obj, attrs) { + return _.filter(obj, _.matcher(attrs)); + }; + + // Convenience version of a common use case of `find`: getting the first object + // containing specific `key:value` pairs. + _.findWhere = function(obj, attrs) { + return _.find(obj, _.matcher(attrs)); + }; + + // Return the maximum element (or element-based computation). + _.max = function(obj, iteratee, context) { + var result = -Infinity, lastComputed = -Infinity, + value, computed; + if (iteratee == null && obj != null) { + obj = isArrayLike(obj) ? obj : _.values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value > result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + _.each(obj, function(value, index, list) { + computed = iteratee(value, index, list); + if (computed > lastComputed || computed === -Infinity && result === -Infinity) { + result = value; + lastComputed = computed; + } + }); + } + return result; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iteratee, context) { + var result = Infinity, lastComputed = Infinity, + value, computed; + if (iteratee == null && obj != null) { + obj = isArrayLike(obj) ? obj : _.values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value < result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + _.each(obj, function(value, index, list) { + computed = iteratee(value, index, list); + if (computed < lastComputed || computed === Infinity && result === Infinity) { + result = value; + lastComputed = computed; + } + }); + } + return result; + }; + + // Shuffle a collection, using the modern version of the + // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). + _.shuffle = function(obj) { + var set = isArrayLike(obj) ? obj : _.values(obj); + var length = set.length; + var shuffled = Array(length); + for (var index = 0, rand; index < length; index++) { + rand = _.random(0, index); + if (rand !== index) shuffled[index] = shuffled[rand]; + shuffled[rand] = set[index]; + } + return shuffled; + }; + + // Sample **n** random values from a collection. + // If **n** is not specified, returns a single random element. + // The internal `guard` argument allows it to work with `map`. + _.sample = function(obj, n, guard) { + if (n == null || guard) { + if (!isArrayLike(obj)) obj = _.values(obj); + return obj[_.random(obj.length - 1)]; + } + return _.shuffle(obj).slice(0, Math.max(0, n)); + }; + + // Sort the object's values by a criterion produced by an iteratee. + _.sortBy = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + return _.pluck(_.map(obj, function(value, index, list) { + return { + value: value, + index: index, + criteria: iteratee(value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria; + var b = right.criteria; + if (a !== b) { + if (a > b || a === void 0) return 1; + if (a < b || b === void 0) return -1; + } + return left.index - right.index; + }), 'value'); + }; + + // An internal function used for aggregate "group by" operations. + var group = function(behavior) { + return function(obj, iteratee, context) { + var result = {}; + iteratee = cb(iteratee, context); + _.each(obj, function(value, index) { + var key = iteratee(value, index, obj); + behavior(result, value, key); + }); + return result; + }; + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = group(function(result, value, key) { + if (_.has(result, key)) result[key].push(value); else result[key] = [value]; + }); + + // Indexes the object's values by a criterion, similar to `groupBy`, but for + // when you know that your index values will be unique. + _.indexBy = group(function(result, value, key) { + result[key] = value; + }); + + // Counts instances of an object that group by a certain criterion. Pass + // either a string attribute to count by, or a function that returns the + // criterion. + _.countBy = group(function(result, value, key) { + if (_.has(result, key)) result[key]++; else result[key] = 1; + }); + + // Safely create a real, live array from anything iterable. + _.toArray = function(obj) { + if (!obj) return []; + if (_.isArray(obj)) return slice.call(obj); + if (isArrayLike(obj)) return _.map(obj, _.identity); + return _.values(obj); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + if (obj == null) return 0; + return isArrayLike(obj) ? obj.length : _.keys(obj).length; + }; + + // Split a collection into two arrays: one whose elements all satisfy the given + // predicate, and one whose elements all do not satisfy the predicate. + _.partition = function(obj, predicate, context) { + predicate = cb(predicate, context); + var pass = [], fail = []; + _.each(obj, function(value, key, obj) { + (predicate(value, key, obj) ? pass : fail).push(value); + }); + return [pass, fail]; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head` and `take`. The **guard** check + // allows it to work with `_.map`. + _.first = _.head = _.take = function(array, n, guard) { + if (array == null) return void 0; + if (n == null || guard) return array[0]; + return _.initial(array, array.length - n); + }; + + // Returns everything but the last entry of the array. Especially useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. + _.initial = function(array, n, guard) { + return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); + }; + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. + _.last = function(array, n, guard) { + if (array == null) return void 0; + if (n == null || guard) return array[array.length - 1]; + return _.rest(array, Math.max(0, array.length - n)); + }; + + // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. + // Especially useful on the arguments object. Passing an **n** will return + // the rest N values in the array. + _.rest = _.tail = _.drop = function(array, n, guard) { + return slice.call(array, n == null || guard ? 1 : n); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, _.identity); + }; + + // Internal implementation of a recursive `flatten` function. + var flatten = function(input, shallow, strict, startIndex) { + var output = [], idx = 0; + for (var i = startIndex || 0, length = getLength(input); i < length; i++) { + var value = input[i]; + if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { + //flatten current level of array or arguments object + if (!shallow) value = flatten(value, shallow, strict); + var j = 0, len = value.length; + output.length += len; + while (j < len) { + output[idx++] = value[j++]; + } + } else if (!strict) { + output[idx++] = value; + } + } + return output; + }; + + // Flatten out an array, either recursively (by default), or just one level. + _.flatten = function(array, shallow) { + return flatten(array, shallow, false); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iteratee, context) { + if (!_.isBoolean(isSorted)) { + context = iteratee; + iteratee = isSorted; + isSorted = false; + } + if (iteratee != null) iteratee = cb(iteratee, context); + var result = []; + var seen = []; + for (var i = 0, length = getLength(array); i < length; i++) { + var value = array[i], + computed = iteratee ? iteratee(value, i, array) : value; + if (isSorted) { + if (!i || seen !== computed) result.push(value); + seen = computed; + } else if (iteratee) { + if (!_.contains(seen, computed)) { + seen.push(computed); + result.push(value); + } + } else if (!_.contains(result, value)) { + result.push(value); + } + } + return result; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(flatten(arguments, true, true)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. + _.intersection = function(array) { + var result = []; + var argsLength = arguments.length; + for (var i = 0, length = getLength(array); i < length; i++) { + var item = array[i]; + if (_.contains(result, item)) continue; + for (var j = 1; j < argsLength; j++) { + if (!_.contains(arguments[j], item)) break; + } + if (j === argsLength) result.push(item); + } + return result; + }; + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + _.difference = function(array) { + var rest = flatten(arguments, true, true, 1); + return _.filter(array, function(value){ + return !_.contains(rest, value); + }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + return _.unzip(arguments); + }; + + // Complement of _.zip. Unzip accepts an array of arrays and groups + // each array's elements on shared indices + _.unzip = function(array) { + var length = array && _.max(array, getLength).length || 0; + var result = Array(length); + + for (var index = 0; index < length; index++) { + result[index] = _.pluck(array, index); + } + return result; + }; + + // Converts lists into objects. Pass either a single array of `[key, value]` + // pairs, or two parallel arrays of the same length -- one of keys, and one of + // the corresponding values. + _.object = function(list, values) { + var result = {}; + for (var i = 0, length = getLength(list); i < length; i++) { + if (values) { + result[list[i]] = values[i]; + } else { + result[list[i][0]] = list[i][1]; + } + } + return result; + }; + + // Generator function to create the findIndex and findLastIndex functions + function createPredicateIndexFinder(dir) { + return function(array, predicate, context) { + predicate = cb(predicate, context); + var length = getLength(array); + var index = dir > 0 ? 0 : length - 1; + for (; index >= 0 && index < length; index += dir) { + if (predicate(array[index], index, array)) return index; + } + return -1; + }; + } + + // Returns the first index on an array-like that passes a predicate test + _.findIndex = createPredicateIndexFinder(1); + _.findLastIndex = createPredicateIndexFinder(-1); + + // Use a comparator function to figure out the smallest index at which + // an object should be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iteratee, context) { + iteratee = cb(iteratee, context, 1); + var value = iteratee(obj); + var low = 0, high = getLength(array); + while (low < high) { + var mid = Math.floor((low + high) / 2); + if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; + } + return low; + }; + + // Generator function to create the indexOf and lastIndexOf functions + function createIndexFinder(dir, predicateFind, sortedIndex) { + return function(array, item, idx) { + var i = 0, length = getLength(array); + if (typeof idx == 'number') { + if (dir > 0) { + i = idx >= 0 ? idx : Math.max(idx + length, i); + } else { + length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; + } + } else if (sortedIndex && idx && length) { + idx = sortedIndex(array, item); + return array[idx] === item ? idx : -1; + } + if (item !== item) { + idx = predicateFind(slice.call(array, i, length), _.isNaN); + return idx >= 0 ? idx + i : -1; + } + for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { + if (array[idx] === item) return idx; + } + return -1; + }; + } + + // Return the position of the first occurrence of an item in an array, + // or -1 if the item is not included in the array. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex); + _.lastIndexOf = createIndexFinder(-1, _.findLastIndex); + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (stop == null) { + stop = start || 0; + start = 0; + } + step = step || 1; + + var length = Math.max(Math.ceil((stop - start) / step), 0); + var range = Array(length); + + for (var idx = 0; idx < length; idx++, start += step) { + range[idx] = start; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Determines whether to execute a function as a constructor + // or a normal function with the provided arguments + var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { + if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); + var self = baseCreate(sourceFunc.prototype); + var result = sourceFunc.apply(self, args); + if (_.isObject(result)) return result; + return self; + }; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if + // available. + _.bind = function(func, context) { + if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); + var args = slice.call(arguments, 2); + var bound = function() { + return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); + }; + return bound; + }; + + // Partially apply a function by creating a version that has had some of its + // arguments pre-filled, without changing its dynamic `this` context. _ acts + // as a placeholder, allowing any combination of arguments to be pre-filled. + _.partial = function(func) { + var boundArgs = slice.call(arguments, 1); + var bound = function() { + var position = 0, length = boundArgs.length; + var args = Array(length); + for (var i = 0; i < length; i++) { + args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i]; + } + while (position < arguments.length) args.push(arguments[position++]); + return executeBound(func, bound, this, this, args); + }; + return bound; + }; + + // Bind a number of an object's methods to that object. Remaining arguments + // are the method names to be bound. Useful for ensuring that all callbacks + // defined on an object belong to it. + _.bindAll = function(obj) { + var i, length = arguments.length, key; + if (length <= 1) throw new Error('bindAll must be passed function names'); + for (i = 1; i < length; i++) { + key = arguments[i]; + obj[key] = _.bind(obj[key], obj); + } + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memoize = function(key) { + var cache = memoize.cache; + var address = '' + (hasher ? hasher.apply(this, arguments) : key); + if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); + return cache[address]; + }; + memoize.cache = {}; + return memoize; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ + return func.apply(null, args); + }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = _.partial(_.delay, _, 1); + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. Normally, the throttled function will run + // as much as it can, without ever going more than once per `wait` duration; + // but if you'd like to disable the execution on the leading edge, pass + // `{leading: false}`. To disable execution on the trailing edge, ditto. + _.throttle = function(func, wait, options) { + var context, args, result; + var timeout = null; + var previous = 0; + if (!options) options = {}; + var later = function() { + previous = options.leading === false ? 0 : _.now(); + timeout = null; + result = func.apply(context, args); + if (!timeout) context = args = null; + }; + return function() { + var now = _.now(); + if (!previous && options.leading === false) previous = now; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + previous = now; + result = func.apply(context, args); + if (!timeout) context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + _.debounce = function(func, wait, immediate) { + var timeout, args, context, timestamp, result; + + var later = function() { + var last = _.now() - timestamp; + + if (last < wait && last >= 0) { + timeout = setTimeout(later, wait - last); + } else { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + if (!timeout) context = args = null; + } + } + }; + + return function() { + context = this; + args = arguments; + timestamp = _.now(); + var callNow = immediate && !timeout; + if (!timeout) timeout = setTimeout(later, wait); + if (callNow) { + result = func.apply(context, args); + context = args = null; + } + + return result; + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return _.partial(wrapper, func); + }; + + // Returns a negated version of the passed-in predicate. + _.negate = function(predicate) { + return function() { + return !predicate.apply(this, arguments); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var args = arguments; + var start = args.length - 1; + return function() { + var i = start; + var result = args[start].apply(this, arguments); + while (i--) result = args[i].call(this, result); + return result; + }; + }; + + // Returns a function that will only be executed on and after the Nth call. + _.after = function(times, func) { + return function() { + if (--times < 1) { + return func.apply(this, arguments); + } + }; + }; + + // Returns a function that will only be executed up to (but not including) the Nth call. + _.before = function(times, func) { + var memo; + return function() { + if (--times > 0) { + memo = func.apply(this, arguments); + } + if (times <= 1) func = null; + return memo; + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = _.partial(_.before, 2); + + // Object Functions + // ---------------- + + // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. + var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); + var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', + 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; + + function collectNonEnumProps(obj, keys) { + var nonEnumIdx = nonEnumerableProps.length; + var constructor = obj.constructor; + var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto; + + // Constructor is a special case. + var prop = 'constructor'; + if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop); + + while (nonEnumIdx--) { + prop = nonEnumerableProps[nonEnumIdx]; + if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) { + keys.push(prop); + } + } + } + + // Retrieve the names of an object's own properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = function(obj) { + if (!_.isObject(obj)) return []; + if (nativeKeys) return nativeKeys(obj); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + }; + + // Retrieve all the property names of an object. + _.allKeys = function(obj) { + if (!_.isObject(obj)) return []; + var keys = []; + for (var key in obj) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var values = Array(length); + for (var i = 0; i < length; i++) { + values[i] = obj[keys[i]]; + } + return values; + }; + + // Returns the results of applying the iteratee to each element of the object + // In contrast to _.map it returns an object + _.mapObject = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var keys = _.keys(obj), + length = keys.length, + results = {}, + currentKey; + for (var index = 0; index < length; index++) { + currentKey = keys[index]; + results[currentKey] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + }; + + // Convert an object into a list of `[key, value]` pairs. + _.pairs = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var pairs = Array(length); + for (var i = 0; i < length; i++) { + pairs[i] = [keys[i], obj[keys[i]]]; + } + return pairs; + }; + + // Invert the keys and values of an object. The values must be serializable. + _.invert = function(obj) { + var result = {}; + var keys = _.keys(obj); + for (var i = 0, length = keys.length; i < length; i++) { + result[obj[keys[i]]] = keys[i]; + } + return result; + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = createAssigner(_.allKeys); + + // Assigns a given object with all the own properties in the passed-in object(s) + // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) + _.extendOwn = _.assign = createAssigner(_.keys); + + // Returns the first key on an object that passes a predicate test + _.findKey = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = _.keys(obj), key; + for (var i = 0, length = keys.length; i < length; i++) { + key = keys[i]; + if (predicate(obj[key], key, obj)) return key; + } + }; + + // Return a copy of the object only containing the whitelisted properties. + _.pick = function(object, oiteratee, context) { + var result = {}, obj = object, iteratee, keys; + if (obj == null) return result; + if (_.isFunction(oiteratee)) { + keys = _.allKeys(obj); + iteratee = optimizeCb(oiteratee, context); + } else { + keys = flatten(arguments, false, false, 1); + iteratee = function(value, key, obj) { return key in obj; }; + obj = Object(obj); + } + for (var i = 0, length = keys.length; i < length; i++) { + var key = keys[i]; + var value = obj[key]; + if (iteratee(value, key, obj)) result[key] = value; + } + return result; + }; + + // Return a copy of the object without the blacklisted properties. + _.omit = function(obj, iteratee, context) { + if (_.isFunction(iteratee)) { + iteratee = _.negate(iteratee); + } else { + var keys = _.map(flatten(arguments, false, false, 1), String); + iteratee = function(value, key) { + return !_.contains(keys, key); + }; + } + return _.pick(obj, iteratee, context); + }; + + // Fill in a given object with default properties. + _.defaults = createAssigner(_.allKeys, true); + + // Creates an object that inherits from the given prototype object. + // If additional properties are provided then they will be added to the + // created object. + _.create = function(prototype, props) { + var result = baseCreate(prototype); + if (props) _.extendOwn(result, props); + return result; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Returns whether an object has a given set of `key:value` pairs. + _.isMatch = function(object, attrs) { + var keys = _.keys(attrs), length = keys.length; + if (object == null) return !length; + var obj = Object(object); + for (var i = 0; i < length; i++) { + var key = keys[i]; + if (attrs[key] !== obj[key] || !(key in obj)) return false; + } + return true; + }; + + + // Internal recursive comparison function for `isEqual`. + var eq = function(a, b, aStack, bStack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). + if (a === b) return a !== 0 || 1 / a === 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a instanceof _) a = a._wrapped; + if (b instanceof _) b = b._wrapped; + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className !== toString.call(b)) return false; + switch (className) { + // Strings, numbers, regular expressions, dates, and booleans are compared by value. + case '[object RegExp]': + // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return '' + a === '' + b; + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. + // Object(NaN) is equivalent to NaN + if (+a !== +a) return +b !== +b; + // An `egal` comparison is performed for other numeric values. + return +a === 0 ? 1 / +a === 1 / b : +a === +b; + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a === +b; + } + + var areArrays = className === '[object Array]'; + if (!areArrays) { + if (typeof a != 'object' || typeof b != 'object') return false; + + // Objects with different constructors are not equivalent, but `Object`s or `Array`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && + _.isFunction(bCtor) && bCtor instanceof bCtor) + && ('constructor' in a && 'constructor' in b)) { + return false; + } + } + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + + // Initializing stack of traversed objects. + // It's done here since we only need them for objects and arrays comparison. + aStack = aStack || []; + bStack = bStack || []; + var length = aStack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] === a) return bStack[length] === b; + } + + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); + + // Recursively compare objects and arrays. + if (areArrays) { + // Compare array lengths to determine if a deep comparison is necessary. + length = a.length; + if (length !== b.length) return false; + // Deep compare the contents, ignoring non-numeric properties. + while (length--) { + if (!eq(a[length], b[length], aStack, bStack)) return false; + } + } else { + // Deep compare objects. + var keys = _.keys(a), key; + length = keys.length; + // Ensure that both objects contain the same number of properties before comparing deep equality. + if (_.keys(b).length !== length) return false; + while (length--) { + // Deep compare each member + key = keys[length]; + if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; + } + } + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + return true; + }; + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (obj == null) return true; + if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; + return _.keys(obj).length === 0; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType === 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) === '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + var type = typeof obj; + return type === 'function' || type === 'object' && !!obj; + }; + + // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. + _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { + _['is' + name] = function(obj) { + return toString.call(obj) === '[object ' + name + ']'; + }; + }); + + // Define a fallback version of the method in browsers (ahem, IE < 9), where + // there isn't any inspectable "Arguments" type. + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return _.has(obj, 'callee'); + }; + } + + // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8, + // IE 11 (#1621), and in Safari 8 (#1929). + if (typeof /./ != 'function' && typeof Int8Array != 'object') { + _.isFunction = function(obj) { + return typeof obj == 'function' || false; + }; + } + + // Is a given object a finite number? + _.isFinite = function(obj) { + return isFinite(obj) && !isNaN(parseFloat(obj)); + }; + + // Is the given value `NaN`? (NaN is the only number which does not equal itself). + _.isNaN = function(obj) { + return _.isNumber(obj) && obj !== +obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Shortcut function for checking if an object has a given property directly + // on itself (in other words, not on a prototype). + _.has = function(obj, key) { + return obj != null && hasOwnProperty.call(obj, key); + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iteratees. + _.identity = function(value) { + return value; + }; + + // Predicate-generating functions. Often useful outside of Underscore. + _.constant = function(value) { + return function() { + return value; + }; + }; + + _.noop = function(){}; + + _.property = property; + + // Generates a function for a given object that returns a given property. + _.propertyOf = function(obj) { + return obj == null ? function(){} : function(key) { + return obj[key]; + }; + }; + + // Returns a predicate for checking whether an object has a given set of + // `key:value` pairs. + _.matcher = _.matches = function(attrs) { + attrs = _.extendOwn({}, attrs); + return function(obj) { + return _.isMatch(obj, attrs); + }; + }; + + // Run a function **n** times. + _.times = function(n, iteratee, context) { + var accum = Array(Math.max(0, n)); + iteratee = optimizeCb(iteratee, context, 1); + for (var i = 0; i < n; i++) accum[i] = iteratee(i); + return accum; + }; + + // Return a random integer between min and max (inclusive). + _.random = function(min, max) { + if (max == null) { + max = min; + min = 0; + } + return min + Math.floor(Math.random() * (max - min + 1)); + }; + + // A (possibly faster) way to get the current timestamp as an integer. + _.now = Date.now || function() { + return new Date().getTime(); + }; + + // List of HTML entities for escaping. + var escapeMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' + }; + var unescapeMap = _.invert(escapeMap); + + // Functions for escaping and unescaping strings to/from HTML interpolation. + var createEscaper = function(map) { + var escaper = function(match) { + return map[match]; + }; + // Regexes for identifying a key that needs to be escaped + var source = '(?:' + _.keys(map).join('|') + ')'; + var testRegexp = RegExp(source); + var replaceRegexp = RegExp(source, 'g'); + return function(string) { + string = string == null ? '' : '' + string; + return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; + }; + }; + _.escape = createEscaper(escapeMap); + _.unescape = createEscaper(unescapeMap); + + // If the value of the named `property` is a function then invoke it with the + // `object` as context; otherwise, return it. + _.result = function(object, property, fallback) { + var value = object == null ? void 0 : object[property]; + if (value === void 0) { + value = fallback; + } + return _.isFunction(value) ? value.call(object) : value; + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\u2028|\u2029/g; + + var escapeChar = function(match) { + return '\\' + escapes[match]; + }; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + // NB: `oldSettings` only exists for backwards compatibility. + _.template = function(text, settings, oldSettings) { + if (!settings && oldSettings) settings = oldSettings; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset).replace(escaper, escapeChar); + index = offset + match.length; + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } else if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } else if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + + // Adobe VMs need the match returned to produce the correct offest. + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + 'return __p;\n'; + + try { + var render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled source as a convenience for precompilation. + var argument = settings.variable || 'obj'; + template.source = 'function(' + argument + '){\n' + source + '}'; + + return template; + }; + + // Add a "chain" function. Start chaining a wrapped Underscore object. + _.chain = function(obj) { + var instance = _(obj); + instance._chain = true; + return instance; + }; + + // OOP + // --------------- + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + + // Helper function to continue chaining intermediate results. + var result = function(instance, obj) { + return instance._chain ? _(obj).chain() : obj; + }; + + // Add your own custom functions to the Underscore object. + _.mixin = function(obj) { + _.each(_.functions(obj), function(name) { + var func = _[name] = obj[name]; + _.prototype[name] = function() { + var args = [this._wrapped]; + push.apply(args, arguments); + return result(this, func.apply(_, args)); + }; + }); + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + var obj = this._wrapped; + method.apply(obj, arguments); + if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; + return result(this, obj); + }; + }); + + // Add all accessor Array functions to the wrapper. + _.each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + return result(this, method.apply(this._wrapped, arguments)); + }; + }); + + // Extracts the result from a wrapped and chained object. + _.prototype.value = function() { + return this._wrapped; + }; + + // Provide unwrapping proxy for some methods used in engine operations + // such as arithmetic and JSON stringification. + _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; + + _.prototype.toString = function() { + return '' + this._wrapped; + }; + + // AMD registration happens at the end for compatibility with AMD loaders + // that may not enforce next-turn semantics on modules. Even though general + // practice for AMD registration is to be anonymous, underscore registers + // as a named module because, like jQuery, it is a base library that is + // popular enough to be bundled in a third party lib, but not be part of + // an AMD load request. Those cases could generate an error when an + // anonymous define() is called outside of a loader request. + if (typeof define === 'function' && define.amd) { + define('underscore', [], function() { + return _; + }); + } +}.call(this)); + +},{}],26:[function(require,module,exports){ +arguments[4][19][0].apply(exports,arguments) +},{"dup":19}],27:[function(require,module,exports){ +module.exports = function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.readUInt8 === 'function'; +} +},{}],28:[function(require,module,exports){ +(function (process,global){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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 formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } + + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; + } + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; +}; + + +// Mark that a method should not be used. +// Returns a modified function which warns once by default. +// If --no-deprecation is set, then it is a no-op. +exports.deprecate = function(fn, msg) { + // Allow for deprecating things in the process of starting up. + if (isUndefined(global.process)) { + return function() { + return exports.deprecate(fn, msg).apply(this, arguments); + }; + } + + if (process.noDeprecation === true) { + return fn; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); + } else { + console.error(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } + + return deprecated; +}; + + +var debugs = {}; +var debugEnviron; +exports.debuglog = function(set) { + if (isUndefined(debugEnviron)) + debugEnviron = process.env.NODE_DEBUG || ''; + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; + } + } + return debugs[set]; +}; + + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. + */ +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); +} +exports.inspect = inspect; + + +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; + +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; + + +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; + } +} + + +function stylizeNoColor(str, styleType) { + return str; +} + + +function arrayToHash(array) { + var hash = {}; + + array.forEach(function(val, idx) { + hash[val] = true; + }); + + return hash; +} + + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); + + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); + } + + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } + + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +exports.isBuffer = require('./support/isBuffer'); + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + + +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); +} + + +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; + +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); +} + + +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +}; + + +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = require('inherits'); + +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; + + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; +}; + +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./support/isBuffer":27,"_process":24,"inherits":26}],29:[function(require,module,exports){ +// Returns a wrapper function that returns a wrapped callback +// The wrapper function should do some stuff, and return a +// presumably different callback function. +// This makes sure that own properties are retained, so that +// decorations and such are not lost along the way. +module.exports = wrappy +function wrappy (fn, cb) { + if (fn && cb) return wrappy(fn)(cb) + + if (typeof fn !== 'function') + throw new TypeError('need wrapper function') + + Object.keys(fn).forEach(function (k) { + wrapper[k] = fn[k] + }) + + return wrapper + + function wrapper() { + var args = new Array(arguments.length) + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i] + } + var ret = fn.apply(this, args) + var cb = args[args.length-1] + if (typeof ret === 'function' && ret !== cb) { + Object.keys(cb).forEach(function (k) { + ret[k] = cb[k] + }) + } + return ret + } +} + +},{}]},{},[7])(7) +}); \ No newline at end of file diff --git a/site/assets/javascripts/workers/search.bd0b6b67.min.js b/site/assets/javascripts/workers/search.bd0b6b67.min.js new file mode 100644 index 0000000000..6526529551 --- /dev/null +++ b/site/assets/javascripts/workers/search.bd0b6b67.min.js @@ -0,0 +1,48 @@ +(()=>{var ge=Object.create;var z=Object.defineProperty,ye=Object.defineProperties,me=Object.getOwnPropertyDescriptor,ve=Object.getOwnPropertyDescriptors,xe=Object.getOwnPropertyNames,G=Object.getOwnPropertySymbols,Se=Object.getPrototypeOf,X=Object.prototype.hasOwnProperty,Qe=Object.prototype.propertyIsEnumerable;var J=(t,e,r)=>e in t?z(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,M=(t,e)=>{for(var r in e||(e={}))X.call(e,r)&&J(t,r,e[r]);if(G)for(var r of G(e))Qe.call(e,r)&&J(t,r,e[r]);return t},Z=(t,e)=>ye(t,ve(e)),be=t=>z(t,"__esModule",{value:!0});var K=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Le=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of xe(e))!X.call(t,i)&&(r||i!=="default")&&z(t,i,{get:()=>e[i],enumerable:!(n=me(e,i))||n.enumerable});return t},W=(t,e)=>Le(be(z(t!=null?ge(Se(t)):{},"default",!e&&t&&t.__esModule?{get:()=>t.default,enumerable:!0}:{value:t,enumerable:!0})),t);var U=(t,e,r)=>new Promise((n,i)=>{var s=u=>{try{a(r.next(u))}catch(c){i(c)}},o=u=>{try{a(r.throw(u))}catch(c){i(c)}},a=u=>u.done?n(u.value):Promise.resolve(u.value).then(s,o);a((r=r.apply(t,e)).next())});var re=K((ee,te)=>{/** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + */(function(){var t=function(e){var r=new t.Builder;return r.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),r.searchPipeline.add(t.stemmer),e.call(r,r),r.build()};t.version="2.3.9";/*! + * lunr.utils + * Copyright (C) 2020 Oliver Nightingale + */t.utils={},t.utils.warn=function(e){return function(r){e.console&&console.warn&&console.warn(r)}}(this),t.utils.asString=function(e){return e==null?"":e.toString()},t.utils.clone=function(e){if(e==null)return e;for(var r=Object.create(null),n=Object.keys(e),i=0;i0){var h=t.utils.clone(r)||{};h.position=[a,c],h.index=s.length,s.push(new t.Token(n.slice(a,o),h))}a=o+1}}return s},t.tokenizer.separator=/[\s\-]+/;/*! + * lunr.Pipeline + * Copyright (C) 2020 Oliver Nightingale + */t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions=Object.create(null),t.Pipeline.registerFunction=function(e,r){r in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+r),e.label=r,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var r=e.label&&e.label in this.registeredFunctions;r||t.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. +`,e)},t.Pipeline.load=function(e){var r=new t.Pipeline;return e.forEach(function(n){var i=t.Pipeline.registeredFunctions[n];if(i)r.add(i);else throw new Error("Cannot load unregistered function: "+n)}),r},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(r){t.Pipeline.warnIfFunctionNotRegistered(r),this._stack.push(r)},this)},t.Pipeline.prototype.after=function(e,r){t.Pipeline.warnIfFunctionNotRegistered(r);var n=this._stack.indexOf(e);if(n==-1)throw new Error("Cannot find existingFn");n=n+1,this._stack.splice(n,0,r)},t.Pipeline.prototype.before=function(e,r){t.Pipeline.warnIfFunctionNotRegistered(r);var n=this._stack.indexOf(e);if(n==-1)throw new Error("Cannot find existingFn");this._stack.splice(n,0,r)},t.Pipeline.prototype.remove=function(e){var r=this._stack.indexOf(e);r!=-1&&this._stack.splice(r,1)},t.Pipeline.prototype.run=function(e){for(var r=this._stack.length,n=0;n1&&(oe&&(n=s),o!=e);)i=n-r,s=r+Math.floor(i/2),o=this.elements[s*2];if(o==e||o>e)return s*2;if(ou?h+=2:a==u&&(r+=n[c+1]*i[h+1],c+=2,h+=2);return r},t.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},t.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),r=1,n=0;r0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new t.TokenSet;s.node.edges["*"]=u}if(s.str.length==0&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var c=s.node.edges["*"];else{var c=new t.TokenSet;s.node.edges["*"]=c}s.str.length==1&&(c.final=!0),i.push({node:c,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var h=s.str.charAt(0),y=s.str.charAt(1),g;y in s.node.edges?g=s.node.edges[y]:(g=new t.TokenSet,s.node.edges[y]=g),s.str.length==1&&(g.final=!0),i.push({node:g,editsRemaining:s.editsRemaining-1,str:h+s.str.slice(2)})}}}return n},t.TokenSet.fromString=function(e){for(var r=new t.TokenSet,n=r,i=0,s=e.length;i=e;r--){var n=this.uncheckedNodes[r],i=n.child.toString();i in this.minimizedNodes?n.parent.edges[n.char]=this.minimizedNodes[i]:(n.child._str=i,this.minimizedNodes[i]=n.child),this.uncheckedNodes.pop()}};/*! + * lunr.Index + * Copyright (C) 2020 Oliver Nightingale + */t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(r){var n=new t.QueryParser(e,r);n.parse()})},t.Index.prototype.query=function(e){for(var r=new t.Query(this.fields),n=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),u=0;u1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,r){var n=e[this._ref],i=Object.keys(this._fields);this._documents[n]=r||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,r;do e=this.next(),r=e.charCodeAt(0);while(r>47&&r<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var r=e.next();if(r==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(r.charCodeAt(0)==92){e.escapeCharacter();continue}if(r==":")return t.QueryLexer.lexField;if(r=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(r=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(r=="+"&&e.width()===1||r=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(r.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,r){this.lexer=new t.QueryLexer(e),this.query=r,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var r=e.peekLexeme();if(r!=null)switch(r.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var n="expected either a field or a term, found "+r.type;throw r.str.length>=1&&(n+=" with value '"+r.str+"'"),new t.QueryParseError(n,r.start,r.end)}},t.QueryParser.parsePresence=function(e){var r=e.consumeLexeme();if(r!=null){switch(r.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var n="unrecognised presence operator'"+r.str+"'";throw new t.QueryParseError(n,r.start,r.end)}var i=e.peekLexeme();if(i==null){var n="expecting term or field, found nothing";throw new t.QueryParseError(n,r.start,r.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var n="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(n,i.start,i.end)}}},t.QueryParser.parseField=function(e){var r=e.consumeLexeme();if(r!=null){if(e.query.allFields.indexOf(r.str)==-1){var n=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+r.str+"', possible fields: "+n;throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.fields=[r.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,r.start,r.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var r=e.consumeLexeme();if(r!=null){e.currentClause.term=r.str.toLowerCase(),r.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var n=e.peekLexeme();if(n==null){e.nextClause();return}switch(n.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+n.type+"'";throw new t.QueryParseError(i,n.start,n.end)}}},t.QueryParser.parseEditDistance=function(e){var r=e.consumeLexeme();if(r!=null){var n=parseInt(r.str,10);if(isNaN(n)){var i="edit distance must be numeric";throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.editDistance=n;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var r=e.consumeLexeme();if(r!=null){var n=parseInt(r.str,10);if(isNaN(n)){var i="boost must be numeric";throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.boost=n;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},function(e,r){typeof define=="function"&&define.amd?define(r):typeof ee=="object"?te.exports=r():e.lunr=r()}(this,function(){return t})})()});var H=K((Ie,ne)=>{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var we=/["'&<>]/;ne.exports=Ee;function Ee(t){var e=""+t,r=we.exec(e);if(!r)return e;var n,i="",s=0,o=0;for(s=r.index;s=0;r--){let n=t[r];typeof n!="object"?n=document.createTextNode(n):n.parentNode&&n.parentNode.removeChild(n),r?e.insertBefore(this.previousSibling,n):e.replaceChild(n,this)}}}));var ie=W(H());function se(t){let e=new Map,r=new Set;for(let n of t){let[i,s]=n.location.split("#"),o=n.location,a=n.title,u=n.tags,c=(0,ie.default)(n.text).replace(/\s+(?=[,.:;!?])/g,"").replace(/\s+/g," ");if(s){let h=e.get(i);r.has(h)?e.set(o,{location:o,title:a,text:c,parent:h}):(h.title=n.title,h.text=c,r.add(h))}else e.set(o,M({location:o,title:a,text:c},u&&{tags:u}))}return e}var oe=W(H());function ae(t,e){let r=new RegExp(t.separator,"img"),n=(i,s,o)=>`${s}${o}`;return i=>{i=i.replace(/[\s*+\-:~^]+/g," ").trim();let s=new RegExp(`(^|${t.separator})(${i.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return o=>(e?(0,oe.default)(o):o).replace(s,n).replace(/<\/mark>(\s+)]*>/img,"$1")}}function ue(t){let e=new lunr.Query(["title","text"]);return new lunr.QueryParser(t,e).parse(),e.clauses}function ce(t,e){var i;let r=new Set(t),n={};for(let s=0;s!n.has(i)))]}var q=class{constructor({config:e,docs:r,options:n}){this.options=n,this.documents=se(r),this.highlight=ae(e,!1),lunr.tokenizer.separator=new RegExp(e.separator),this.index=lunr(function(){e.lang.length===1&&e.lang[0]!=="en"?this.use(lunr[e.lang[0]]):e.lang.length>1&&this.use(lunr.multiLanguage(...e.lang));let i=ke(["trimmer","stopWordFilter","stemmer"],n.pipeline);for(let s of e.lang.map(o=>o==="en"?lunr:lunr[o]))for(let o of i)this.pipeline.remove(s[o]),this.searchPipeline.remove(s[o]);this.ref("location"),this.field("title",{boost:1e3}),this.field("text"),this.field("tags",{boost:1e6});for(let s of r)this.add(s)})}search(e){if(e)try{let r=this.highlight(e),n=ue(e).filter(o=>o.presence!==lunr.Query.presence.PROHIBITED),i=this.index.search(`${e}*`).reduce((o,{ref:a,score:u,matchData:c})=>{let h=this.documents.get(a);if(typeof h!="undefined"){let{location:y,title:g,text:b,tags:m,parent:Q}=h,p=ce(n,Object.keys(c.metadata)),d=+!Q+ +Object.values(p).every(w=>w);o.push(Z(M({location:y,title:r(g),text:r(b)},m&&{tags:m.map(r)}),{score:u*(1+d),terms:p}))}return o},[]).sort((o,a)=>a.score-o.score).reduce((o,a)=>{let u=this.documents.get(a.location);if(typeof u!="undefined"){let c="parent"in u?u.parent.location:u.location;o.set(c,[...o.get(c)||[],a])}return o},new Map),s;if(this.options.suggestions){let o=this.index.query(a=>{for(let u of n)a.term(u.term,{fields:["title"],presence:lunr.Query.presence.REQUIRED,wildcard:lunr.Query.wildcard.TRAILING})});s=o.length?Object.keys(o[0].matchData.metadata):[]}return M({items:[...i.values()]},typeof s!="undefined"&&{suggestions:s})}catch(r){console.warn(`Invalid query: ${e} \u2013 see https://bit.ly/2s3ChXG`)}return{items:[]}}};var Y;function Te(t){return U(this,null,function*(){let e="../lunr";if(typeof parent!="undefined"&&"IFrameWorker"in parent){let n=document.querySelector("script[src]"),[i]=n.src.split("/worker");e=e.replace("..",i)}let r=[];for(let n of t.lang){switch(n){case"ja":r.push(`${e}/tinyseg.js`);break;case"hi":case"th":r.push(`${e}/wordcut.js`);break}n!=="en"&&r.push(`${e}/min/lunr.${n}.min.js`)}t.lang.length>1&&r.push(`${e}/min/lunr.multi.min.js`),r.length&&(yield importScripts(`${e}/min/lunr.stemmer.support.min.js`,...r))})}function Pe(t){return U(this,null,function*(){switch(t.type){case 0:return yield Te(t.data.config),Y=new q(t.data),{type:1};case 2:return{type:3,data:Y?Y.search(t.data):{items:[]}};default:throw new TypeError("Invalid message type")}})}self.lunr=le.default;addEventListener("message",t=>U(void 0,null,function*(){postMessage(yield Pe(t.data))}));})(); +//# sourceMappingURL=search.bd0b6b67.min.js.map + diff --git a/site/assets/javascripts/workers/search.bd0b6b67.min.js.map b/site/assets/javascripts/workers/search.bd0b6b67.min.js.map new file mode 100644 index 0000000000..8dee1ffbe7 --- /dev/null +++ b/site/assets/javascripts/workers/search.bd0b6b67.min.js.map @@ -0,0 +1,8 @@ +{ + "version": 3, + "sources": ["node_modules/lunr/lunr.js", "node_modules/escape-html/index.js", "src/assets/javascripts/integrations/search/worker/main/index.ts", "src/assets/javascripts/polyfills/index.ts", "src/assets/javascripts/integrations/search/document/index.ts", "src/assets/javascripts/integrations/search/highlighter/index.ts", "src/assets/javascripts/integrations/search/query/_/index.ts", "src/assets/javascripts/integrations/search/_/index.ts"], + "sourceRoot": "../../../..", + "sourcesContent": ["/**\n * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9\n * Copyright (C) 2020 Oliver Nightingale\n * @license MIT\n */\n\n;(function(){\n\n/**\n * A convenience function for configuring and constructing\n * a new lunr Index.\n *\n * A lunr.Builder instance is created and the pipeline setup\n * with a trimmer, stop word filter and stemmer.\n *\n * This builder object is yielded to the configuration function\n * that is passed as a parameter, allowing the list of fields\n * and other builder parameters to be customised.\n *\n * All documents _must_ be added within the passed config function.\n *\n * @example\n * var idx = lunr(function () {\n * this.field('title')\n * this.field('body')\n * this.ref('id')\n *\n * documents.forEach(function (doc) {\n * this.add(doc)\n * }, this)\n * })\n *\n * @see {@link lunr.Builder}\n * @see {@link lunr.Pipeline}\n * @see {@link lunr.trimmer}\n * @see {@link lunr.stopWordFilter}\n * @see {@link lunr.stemmer}\n * @namespace {function} lunr\n */\nvar lunr = function (config) {\n var builder = new lunr.Builder\n\n builder.pipeline.add(\n lunr.trimmer,\n lunr.stopWordFilter,\n lunr.stemmer\n )\n\n builder.searchPipeline.add(\n lunr.stemmer\n )\n\n config.call(builder, builder)\n return builder.build()\n}\n\nlunr.version = \"2.3.9\"\n/*!\n * lunr.utils\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A namespace containing utils for the rest of the lunr library\n * @namespace lunr.utils\n */\nlunr.utils = {}\n\n/**\n * Print a warning message to the console.\n *\n * @param {String} message The message to be printed.\n * @memberOf lunr.utils\n * @function\n */\nlunr.utils.warn = (function (global) {\n /* eslint-disable no-console */\n return function (message) {\n if (global.console && console.warn) {\n console.warn(message)\n }\n }\n /* eslint-enable no-console */\n})(this)\n\n/**\n * Convert an object to a string.\n *\n * In the case of `null` and `undefined` the function returns\n * the empty string, in all other cases the result of calling\n * `toString` on the passed object is returned.\n *\n * @param {Any} obj The object to convert to a string.\n * @return {String} string representation of the passed object.\n * @memberOf lunr.utils\n */\nlunr.utils.asString = function (obj) {\n if (obj === void 0 || obj === null) {\n return \"\"\n } else {\n return obj.toString()\n }\n}\n\n/**\n * Clones an object.\n *\n * Will create a copy of an existing object such that any mutations\n * on the copy cannot affect the original.\n *\n * Only shallow objects are supported, passing a nested object to this\n * function will cause a TypeError.\n *\n * Objects with primitives, and arrays of primitives are supported.\n *\n * @param {Object} obj The object to clone.\n * @return {Object} a clone of the passed object.\n * @throws {TypeError} when a nested object is passed.\n * @memberOf Utils\n */\nlunr.utils.clone = function (obj) {\n if (obj === null || obj === undefined) {\n return obj\n }\n\n var clone = Object.create(null),\n keys = Object.keys(obj)\n\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i],\n val = obj[key]\n\n if (Array.isArray(val)) {\n clone[key] = val.slice()\n continue\n }\n\n if (typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean') {\n clone[key] = val\n continue\n }\n\n throw new TypeError(\"clone is not deep and does not support nested objects\")\n }\n\n return clone\n}\nlunr.FieldRef = function (docRef, fieldName, stringValue) {\n this.docRef = docRef\n this.fieldName = fieldName\n this._stringValue = stringValue\n}\n\nlunr.FieldRef.joiner = \"/\"\n\nlunr.FieldRef.fromString = function (s) {\n var n = s.indexOf(lunr.FieldRef.joiner)\n\n if (n === -1) {\n throw \"malformed field ref string\"\n }\n\n var fieldRef = s.slice(0, n),\n docRef = s.slice(n + 1)\n\n return new lunr.FieldRef (docRef, fieldRef, s)\n}\n\nlunr.FieldRef.prototype.toString = function () {\n if (this._stringValue == undefined) {\n this._stringValue = this.fieldName + lunr.FieldRef.joiner + this.docRef\n }\n\n return this._stringValue\n}\n/*!\n * lunr.Set\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A lunr set.\n *\n * @constructor\n */\nlunr.Set = function (elements) {\n this.elements = Object.create(null)\n\n if (elements) {\n this.length = elements.length\n\n for (var i = 0; i < this.length; i++) {\n this.elements[elements[i]] = true\n }\n } else {\n this.length = 0\n }\n}\n\n/**\n * A complete set that contains all elements.\n *\n * @static\n * @readonly\n * @type {lunr.Set}\n */\nlunr.Set.complete = {\n intersect: function (other) {\n return other\n },\n\n union: function () {\n return this\n },\n\n contains: function () {\n return true\n }\n}\n\n/**\n * An empty set that contains no elements.\n *\n * @static\n * @readonly\n * @type {lunr.Set}\n */\nlunr.Set.empty = {\n intersect: function () {\n return this\n },\n\n union: function (other) {\n return other\n },\n\n contains: function () {\n return false\n }\n}\n\n/**\n * Returns true if this set contains the specified object.\n *\n * @param {object} object - Object whose presence in this set is to be tested.\n * @returns {boolean} - True if this set contains the specified object.\n */\nlunr.Set.prototype.contains = function (object) {\n return !!this.elements[object]\n}\n\n/**\n * Returns a new set containing only the elements that are present in both\n * this set and the specified set.\n *\n * @param {lunr.Set} other - set to intersect with this set.\n * @returns {lunr.Set} a new set that is the intersection of this and the specified set.\n */\n\nlunr.Set.prototype.intersect = function (other) {\n var a, b, elements, intersection = []\n\n if (other === lunr.Set.complete) {\n return this\n }\n\n if (other === lunr.Set.empty) {\n return other\n }\n\n if (this.length < other.length) {\n a = this\n b = other\n } else {\n a = other\n b = this\n }\n\n elements = Object.keys(a.elements)\n\n for (var i = 0; i < elements.length; i++) {\n var element = elements[i]\n if (element in b.elements) {\n intersection.push(element)\n }\n }\n\n return new lunr.Set (intersection)\n}\n\n/**\n * Returns a new set combining the elements of this and the specified set.\n *\n * @param {lunr.Set} other - set to union with this set.\n * @return {lunr.Set} a new set that is the union of this and the specified set.\n */\n\nlunr.Set.prototype.union = function (other) {\n if (other === lunr.Set.complete) {\n return lunr.Set.complete\n }\n\n if (other === lunr.Set.empty) {\n return this\n }\n\n return new lunr.Set(Object.keys(this.elements).concat(Object.keys(other.elements)))\n}\n/**\n * A function to calculate the inverse document frequency for\n * a posting. This is shared between the builder and the index\n *\n * @private\n * @param {object} posting - The posting for a given term\n * @param {number} documentCount - The total number of documents.\n */\nlunr.idf = function (posting, documentCount) {\n var documentsWithTerm = 0\n\n for (var fieldName in posting) {\n if (fieldName == '_index') continue // Ignore the term index, its not a field\n documentsWithTerm += Object.keys(posting[fieldName]).length\n }\n\n var x = (documentCount - documentsWithTerm + 0.5) / (documentsWithTerm + 0.5)\n\n return Math.log(1 + Math.abs(x))\n}\n\n/**\n * A token wraps a string representation of a token\n * as it is passed through the text processing pipeline.\n *\n * @constructor\n * @param {string} [str=''] - The string token being wrapped.\n * @param {object} [metadata={}] - Metadata associated with this token.\n */\nlunr.Token = function (str, metadata) {\n this.str = str || \"\"\n this.metadata = metadata || {}\n}\n\n/**\n * Returns the token string that is being wrapped by this object.\n *\n * @returns {string}\n */\nlunr.Token.prototype.toString = function () {\n return this.str\n}\n\n/**\n * A token update function is used when updating or optionally\n * when cloning a token.\n *\n * @callback lunr.Token~updateFunction\n * @param {string} str - The string representation of the token.\n * @param {Object} metadata - All metadata associated with this token.\n */\n\n/**\n * Applies the given function to the wrapped string token.\n *\n * @example\n * token.update(function (str, metadata) {\n * return str.toUpperCase()\n * })\n *\n * @param {lunr.Token~updateFunction} fn - A function to apply to the token string.\n * @returns {lunr.Token}\n */\nlunr.Token.prototype.update = function (fn) {\n this.str = fn(this.str, this.metadata)\n return this\n}\n\n/**\n * Creates a clone of this token. Optionally a function can be\n * applied to the cloned token.\n *\n * @param {lunr.Token~updateFunction} [fn] - An optional function to apply to the cloned token.\n * @returns {lunr.Token}\n */\nlunr.Token.prototype.clone = function (fn) {\n fn = fn || function (s) { return s }\n return new lunr.Token (fn(this.str, this.metadata), this.metadata)\n}\n/*!\n * lunr.tokenizer\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A function for splitting a string into tokens ready to be inserted into\n * the search index. Uses `lunr.tokenizer.separator` to split strings, change\n * the value of this property to change how strings are split into tokens.\n *\n * This tokenizer will convert its parameter to a string by calling `toString` and\n * then will split this string on the character in `lunr.tokenizer.separator`.\n * Arrays will have their elements converted to strings and wrapped in a lunr.Token.\n *\n * Optional metadata can be passed to the tokenizer, this metadata will be cloned and\n * added as metadata to every token that is created from the object to be tokenized.\n *\n * @static\n * @param {?(string|object|object[])} obj - The object to convert into tokens\n * @param {?object} metadata - Optional metadata to associate with every token\n * @returns {lunr.Token[]}\n * @see {@link lunr.Pipeline}\n */\nlunr.tokenizer = function (obj, metadata) {\n if (obj == null || obj == undefined) {\n return []\n }\n\n if (Array.isArray(obj)) {\n return obj.map(function (t) {\n return new lunr.Token(\n lunr.utils.asString(t).toLowerCase(),\n lunr.utils.clone(metadata)\n )\n })\n }\n\n var str = obj.toString().toLowerCase(),\n len = str.length,\n tokens = []\n\n for (var sliceEnd = 0, sliceStart = 0; sliceEnd <= len; sliceEnd++) {\n var char = str.charAt(sliceEnd),\n sliceLength = sliceEnd - sliceStart\n\n if ((char.match(lunr.tokenizer.separator) || sliceEnd == len)) {\n\n if (sliceLength > 0) {\n var tokenMetadata = lunr.utils.clone(metadata) || {}\n tokenMetadata[\"position\"] = [sliceStart, sliceLength]\n tokenMetadata[\"index\"] = tokens.length\n\n tokens.push(\n new lunr.Token (\n str.slice(sliceStart, sliceEnd),\n tokenMetadata\n )\n )\n }\n\n sliceStart = sliceEnd + 1\n }\n\n }\n\n return tokens\n}\n\n/**\n * The separator used to split a string into tokens. Override this property to change the behaviour of\n * `lunr.tokenizer` behaviour when tokenizing strings. By default this splits on whitespace and hyphens.\n *\n * @static\n * @see lunr.tokenizer\n */\nlunr.tokenizer.separator = /[\\s\\-]+/\n/*!\n * lunr.Pipeline\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.Pipelines maintain an ordered list of functions to be applied to all\n * tokens in documents entering the search index and queries being ran against\n * the index.\n *\n * An instance of lunr.Index created with the lunr shortcut will contain a\n * pipeline with a stop word filter and an English language stemmer. Extra\n * functions can be added before or after either of these functions or these\n * default functions can be removed.\n *\n * When run the pipeline will call each function in turn, passing a token, the\n * index of that token in the original list of all tokens and finally a list of\n * all the original tokens.\n *\n * The output of functions in the pipeline will be passed to the next function\n * in the pipeline. To exclude a token from entering the index the function\n * should return undefined, the rest of the pipeline will not be called with\n * this token.\n *\n * For serialisation of pipelines to work, all functions used in an instance of\n * a pipeline should be registered with lunr.Pipeline. Registered functions can\n * then be loaded. If trying to load a serialised pipeline that uses functions\n * that are not registered an error will be thrown.\n *\n * If not planning on serialising the pipeline then registering pipeline functions\n * is not necessary.\n *\n * @constructor\n */\nlunr.Pipeline = function () {\n this._stack = []\n}\n\nlunr.Pipeline.registeredFunctions = Object.create(null)\n\n/**\n * A pipeline function maps lunr.Token to lunr.Token. A lunr.Token contains the token\n * string as well as all known metadata. A pipeline function can mutate the token string\n * or mutate (or add) metadata for a given token.\n *\n * A pipeline function can indicate that the passed token should be discarded by returning\n * null, undefined or an empty string. This token will not be passed to any downstream pipeline\n * functions and will not be added to the index.\n *\n * Multiple tokens can be returned by returning an array of tokens. Each token will be passed\n * to any downstream pipeline functions and all will returned tokens will be added to the index.\n *\n * Any number of pipeline functions may be chained together using a lunr.Pipeline.\n *\n * @interface lunr.PipelineFunction\n * @param {lunr.Token} token - A token from the document being processed.\n * @param {number} i - The index of this token in the complete list of tokens for this document/field.\n * @param {lunr.Token[]} tokens - All tokens for this document/field.\n * @returns {(?lunr.Token|lunr.Token[])}\n */\n\n/**\n * Register a function with the pipeline.\n *\n * Functions that are used in the pipeline should be registered if the pipeline\n * needs to be serialised, or a serialised pipeline needs to be loaded.\n *\n * Registering a function does not add it to a pipeline, functions must still be\n * added to instances of the pipeline for them to be used when running a pipeline.\n *\n * @param {lunr.PipelineFunction} fn - The function to check for.\n * @param {String} label - The label to register this function with\n */\nlunr.Pipeline.registerFunction = function (fn, label) {\n if (label in this.registeredFunctions) {\n lunr.utils.warn('Overwriting existing registered function: ' + label)\n }\n\n fn.label = label\n lunr.Pipeline.registeredFunctions[fn.label] = fn\n}\n\n/**\n * Warns if the function is not registered as a Pipeline function.\n *\n * @param {lunr.PipelineFunction} fn - The function to check for.\n * @private\n */\nlunr.Pipeline.warnIfFunctionNotRegistered = function (fn) {\n var isRegistered = fn.label && (fn.label in this.registeredFunctions)\n\n if (!isRegistered) {\n lunr.utils.warn('Function is not registered with pipeline. This may cause problems when serialising the index.\\n', fn)\n }\n}\n\n/**\n * Loads a previously serialised pipeline.\n *\n * All functions to be loaded must already be registered with lunr.Pipeline.\n * If any function from the serialised data has not been registered then an\n * error will be thrown.\n *\n * @param {Object} serialised - The serialised pipeline to load.\n * @returns {lunr.Pipeline}\n */\nlunr.Pipeline.load = function (serialised) {\n var pipeline = new lunr.Pipeline\n\n serialised.forEach(function (fnName) {\n var fn = lunr.Pipeline.registeredFunctions[fnName]\n\n if (fn) {\n pipeline.add(fn)\n } else {\n throw new Error('Cannot load unregistered function: ' + fnName)\n }\n })\n\n return pipeline\n}\n\n/**\n * Adds new functions to the end of the pipeline.\n *\n * Logs a warning if the function has not been registered.\n *\n * @param {lunr.PipelineFunction[]} functions - Any number of functions to add to the pipeline.\n */\nlunr.Pipeline.prototype.add = function () {\n var fns = Array.prototype.slice.call(arguments)\n\n fns.forEach(function (fn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(fn)\n this._stack.push(fn)\n }, this)\n}\n\n/**\n * Adds a single function after a function that already exists in the\n * pipeline.\n *\n * Logs a warning if the function has not been registered.\n *\n * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline.\n * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline.\n */\nlunr.Pipeline.prototype.after = function (existingFn, newFn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(newFn)\n\n var pos = this._stack.indexOf(existingFn)\n if (pos == -1) {\n throw new Error('Cannot find existingFn')\n }\n\n pos = pos + 1\n this._stack.splice(pos, 0, newFn)\n}\n\n/**\n * Adds a single function before a function that already exists in the\n * pipeline.\n *\n * Logs a warning if the function has not been registered.\n *\n * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline.\n * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline.\n */\nlunr.Pipeline.prototype.before = function (existingFn, newFn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(newFn)\n\n var pos = this._stack.indexOf(existingFn)\n if (pos == -1) {\n throw new Error('Cannot find existingFn')\n }\n\n this._stack.splice(pos, 0, newFn)\n}\n\n/**\n * Removes a function from the pipeline.\n *\n * @param {lunr.PipelineFunction} fn The function to remove from the pipeline.\n */\nlunr.Pipeline.prototype.remove = function (fn) {\n var pos = this._stack.indexOf(fn)\n if (pos == -1) {\n return\n }\n\n this._stack.splice(pos, 1)\n}\n\n/**\n * Runs the current list of functions that make up the pipeline against the\n * passed tokens.\n *\n * @param {Array} tokens The tokens to run through the pipeline.\n * @returns {Array}\n */\nlunr.Pipeline.prototype.run = function (tokens) {\n var stackLength = this._stack.length\n\n for (var i = 0; i < stackLength; i++) {\n var fn = this._stack[i]\n var memo = []\n\n for (var j = 0; j < tokens.length; j++) {\n var result = fn(tokens[j], j, tokens)\n\n if (result === null || result === void 0 || result === '') continue\n\n if (Array.isArray(result)) {\n for (var k = 0; k < result.length; k++) {\n memo.push(result[k])\n }\n } else {\n memo.push(result)\n }\n }\n\n tokens = memo\n }\n\n return tokens\n}\n\n/**\n * Convenience method for passing a string through a pipeline and getting\n * strings out. This method takes care of wrapping the passed string in a\n * token and mapping the resulting tokens back to strings.\n *\n * @param {string} str - The string to pass through the pipeline.\n * @param {?object} metadata - Optional metadata to associate with the token\n * passed to the pipeline.\n * @returns {string[]}\n */\nlunr.Pipeline.prototype.runString = function (str, metadata) {\n var token = new lunr.Token (str, metadata)\n\n return this.run([token]).map(function (t) {\n return t.toString()\n })\n}\n\n/**\n * Resets the pipeline by removing any existing processors.\n *\n */\nlunr.Pipeline.prototype.reset = function () {\n this._stack = []\n}\n\n/**\n * Returns a representation of the pipeline ready for serialisation.\n *\n * Logs a warning if the function has not been registered.\n *\n * @returns {Array}\n */\nlunr.Pipeline.prototype.toJSON = function () {\n return this._stack.map(function (fn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(fn)\n\n return fn.label\n })\n}\n/*!\n * lunr.Vector\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A vector is used to construct the vector space of documents and queries. These\n * vectors support operations to determine the similarity between two documents or\n * a document and a query.\n *\n * Normally no parameters are required for initializing a vector, but in the case of\n * loading a previously dumped vector the raw elements can be provided to the constructor.\n *\n * For performance reasons vectors are implemented with a flat array, where an elements\n * index is immediately followed by its value. E.g. [index, value, index, value]. This\n * allows the underlying array to be as sparse as possible and still offer decent\n * performance when being used for vector calculations.\n *\n * @constructor\n * @param {Number[]} [elements] - The flat list of element index and element value pairs.\n */\nlunr.Vector = function (elements) {\n this._magnitude = 0\n this.elements = elements || []\n}\n\n\n/**\n * Calculates the position within the vector to insert a given index.\n *\n * This is used internally by insert and upsert. If there are duplicate indexes then\n * the position is returned as if the value for that index were to be updated, but it\n * is the callers responsibility to check whether there is a duplicate at that index\n *\n * @param {Number} insertIdx - The index at which the element should be inserted.\n * @returns {Number}\n */\nlunr.Vector.prototype.positionForIndex = function (index) {\n // For an empty vector the tuple can be inserted at the beginning\n if (this.elements.length == 0) {\n return 0\n }\n\n var start = 0,\n end = this.elements.length / 2,\n sliceLength = end - start,\n pivotPoint = Math.floor(sliceLength / 2),\n pivotIndex = this.elements[pivotPoint * 2]\n\n while (sliceLength > 1) {\n if (pivotIndex < index) {\n start = pivotPoint\n }\n\n if (pivotIndex > index) {\n end = pivotPoint\n }\n\n if (pivotIndex == index) {\n break\n }\n\n sliceLength = end - start\n pivotPoint = start + Math.floor(sliceLength / 2)\n pivotIndex = this.elements[pivotPoint * 2]\n }\n\n if (pivotIndex == index) {\n return pivotPoint * 2\n }\n\n if (pivotIndex > index) {\n return pivotPoint * 2\n }\n\n if (pivotIndex < index) {\n return (pivotPoint + 1) * 2\n }\n}\n\n/**\n * Inserts an element at an index within the vector.\n *\n * Does not allow duplicates, will throw an error if there is already an entry\n * for this index.\n *\n * @param {Number} insertIdx - The index at which the element should be inserted.\n * @param {Number} val - The value to be inserted into the vector.\n */\nlunr.Vector.prototype.insert = function (insertIdx, val) {\n this.upsert(insertIdx, val, function () {\n throw \"duplicate index\"\n })\n}\n\n/**\n * Inserts or updates an existing index within the vector.\n *\n * @param {Number} insertIdx - The index at which the element should be inserted.\n * @param {Number} val - The value to be inserted into the vector.\n * @param {function} fn - A function that is called for updates, the existing value and the\n * requested value are passed as arguments\n */\nlunr.Vector.prototype.upsert = function (insertIdx, val, fn) {\n this._magnitude = 0\n var position = this.positionForIndex(insertIdx)\n\n if (this.elements[position] == insertIdx) {\n this.elements[position + 1] = fn(this.elements[position + 1], val)\n } else {\n this.elements.splice(position, 0, insertIdx, val)\n }\n}\n\n/**\n * Calculates the magnitude of this vector.\n *\n * @returns {Number}\n */\nlunr.Vector.prototype.magnitude = function () {\n if (this._magnitude) return this._magnitude\n\n var sumOfSquares = 0,\n elementsLength = this.elements.length\n\n for (var i = 1; i < elementsLength; i += 2) {\n var val = this.elements[i]\n sumOfSquares += val * val\n }\n\n return this._magnitude = Math.sqrt(sumOfSquares)\n}\n\n/**\n * Calculates the dot product of this vector and another vector.\n *\n * @param {lunr.Vector} otherVector - The vector to compute the dot product with.\n * @returns {Number}\n */\nlunr.Vector.prototype.dot = function (otherVector) {\n var dotProduct = 0,\n a = this.elements, b = otherVector.elements,\n aLen = a.length, bLen = b.length,\n aVal = 0, bVal = 0,\n i = 0, j = 0\n\n while (i < aLen && j < bLen) {\n aVal = a[i], bVal = b[j]\n if (aVal < bVal) {\n i += 2\n } else if (aVal > bVal) {\n j += 2\n } else if (aVal == bVal) {\n dotProduct += a[i + 1] * b[j + 1]\n i += 2\n j += 2\n }\n }\n\n return dotProduct\n}\n\n/**\n * Calculates the similarity between this vector and another vector.\n *\n * @param {lunr.Vector} otherVector - The other vector to calculate the\n * similarity with.\n * @returns {Number}\n */\nlunr.Vector.prototype.similarity = function (otherVector) {\n return this.dot(otherVector) / this.magnitude() || 0\n}\n\n/**\n * Converts the vector to an array of the elements within the vector.\n *\n * @returns {Number[]}\n */\nlunr.Vector.prototype.toArray = function () {\n var output = new Array (this.elements.length / 2)\n\n for (var i = 1, j = 0; i < this.elements.length; i += 2, j++) {\n output[j] = this.elements[i]\n }\n\n return output\n}\n\n/**\n * A JSON serializable representation of the vector.\n *\n * @returns {Number[]}\n */\nlunr.Vector.prototype.toJSON = function () {\n return this.elements\n}\n/* eslint-disable */\n/*!\n * lunr.stemmer\n * Copyright (C) 2020 Oliver Nightingale\n * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt\n */\n\n/**\n * lunr.stemmer is an english language stemmer, this is a JavaScript\n * implementation of the PorterStemmer taken from http://tartarus.org/~martin\n *\n * @static\n * @implements {lunr.PipelineFunction}\n * @param {lunr.Token} token - The string to stem\n * @returns {lunr.Token}\n * @see {@link lunr.Pipeline}\n * @function\n */\nlunr.stemmer = (function(){\n var step2list = {\n \"ational\" : \"ate\",\n \"tional\" : \"tion\",\n \"enci\" : \"ence\",\n \"anci\" : \"ance\",\n \"izer\" : \"ize\",\n \"bli\" : \"ble\",\n \"alli\" : \"al\",\n \"entli\" : \"ent\",\n \"eli\" : \"e\",\n \"ousli\" : \"ous\",\n \"ization\" : \"ize\",\n \"ation\" : \"ate\",\n \"ator\" : \"ate\",\n \"alism\" : \"al\",\n \"iveness\" : \"ive\",\n \"fulness\" : \"ful\",\n \"ousness\" : \"ous\",\n \"aliti\" : \"al\",\n \"iviti\" : \"ive\",\n \"biliti\" : \"ble\",\n \"logi\" : \"log\"\n },\n\n step3list = {\n \"icate\" : \"ic\",\n \"ative\" : \"\",\n \"alize\" : \"al\",\n \"iciti\" : \"ic\",\n \"ical\" : \"ic\",\n \"ful\" : \"\",\n \"ness\" : \"\"\n },\n\n c = \"[^aeiou]\", // consonant\n v = \"[aeiouy]\", // vowel\n C = c + \"[^aeiouy]*\", // consonant sequence\n V = v + \"[aeiou]*\", // vowel sequence\n\n mgr0 = \"^(\" + C + \")?\" + V + C, // [C]VC... is m>0\n meq1 = \"^(\" + C + \")?\" + V + C + \"(\" + V + \")?$\", // [C]VC[V] is m=1\n mgr1 = \"^(\" + C + \")?\" + V + C + V + C, // [C]VCVC... is m>1\n s_v = \"^(\" + C + \")?\" + v; // vowel in stem\n\n var re_mgr0 = new RegExp(mgr0);\n var re_mgr1 = new RegExp(mgr1);\n var re_meq1 = new RegExp(meq1);\n var re_s_v = new RegExp(s_v);\n\n var re_1a = /^(.+?)(ss|i)es$/;\n var re2_1a = /^(.+?)([^s])s$/;\n var re_1b = /^(.+?)eed$/;\n var re2_1b = /^(.+?)(ed|ing)$/;\n var re_1b_2 = /.$/;\n var re2_1b_2 = /(at|bl|iz)$/;\n var re3_1b_2 = new RegExp(\"([^aeiouylsz])\\\\1$\");\n var re4_1b_2 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n\n var re_1c = /^(.+?[^aeiou])y$/;\n var re_2 = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;\n\n var re_3 = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;\n\n var re_4 = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;\n var re2_4 = /^(.+?)(s|t)(ion)$/;\n\n var re_5 = /^(.+?)e$/;\n var re_5_1 = /ll$/;\n var re3_5 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n\n var porterStemmer = function porterStemmer(w) {\n var stem,\n suffix,\n firstch,\n re,\n re2,\n re3,\n re4;\n\n if (w.length < 3) { return w; }\n\n firstch = w.substr(0,1);\n if (firstch == \"y\") {\n w = firstch.toUpperCase() + w.substr(1);\n }\n\n // Step 1a\n re = re_1a\n re2 = re2_1a;\n\n if (re.test(w)) { w = w.replace(re,\"$1$2\"); }\n else if (re2.test(w)) { w = w.replace(re2,\"$1$2\"); }\n\n // Step 1b\n re = re_1b;\n re2 = re2_1b;\n if (re.test(w)) {\n var fp = re.exec(w);\n re = re_mgr0;\n if (re.test(fp[1])) {\n re = re_1b_2;\n w = w.replace(re,\"\");\n }\n } else if (re2.test(w)) {\n var fp = re2.exec(w);\n stem = fp[1];\n re2 = re_s_v;\n if (re2.test(stem)) {\n w = stem;\n re2 = re2_1b_2;\n re3 = re3_1b_2;\n re4 = re4_1b_2;\n if (re2.test(w)) { w = w + \"e\"; }\n else if (re3.test(w)) { re = re_1b_2; w = w.replace(re,\"\"); }\n else if (re4.test(w)) { w = w + \"e\"; }\n }\n }\n\n // Step 1c - replace suffix y or Y by i if preceded by a non-vowel which is not the first letter of the word (so cry -> cri, by -> by, say -> say)\n re = re_1c;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n w = stem + \"i\";\n }\n\n // Step 2\n re = re_2;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n suffix = fp[2];\n re = re_mgr0;\n if (re.test(stem)) {\n w = stem + step2list[suffix];\n }\n }\n\n // Step 3\n re = re_3;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n suffix = fp[2];\n re = re_mgr0;\n if (re.test(stem)) {\n w = stem + step3list[suffix];\n }\n }\n\n // Step 4\n re = re_4;\n re2 = re2_4;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n re = re_mgr1;\n if (re.test(stem)) {\n w = stem;\n }\n } else if (re2.test(w)) {\n var fp = re2.exec(w);\n stem = fp[1] + fp[2];\n re2 = re_mgr1;\n if (re2.test(stem)) {\n w = stem;\n }\n }\n\n // Step 5\n re = re_5;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n re = re_mgr1;\n re2 = re_meq1;\n re3 = re3_5;\n if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) {\n w = stem;\n }\n }\n\n re = re_5_1;\n re2 = re_mgr1;\n if (re.test(w) && re2.test(w)) {\n re = re_1b_2;\n w = w.replace(re,\"\");\n }\n\n // and turn initial Y back to y\n\n if (firstch == \"y\") {\n w = firstch.toLowerCase() + w.substr(1);\n }\n\n return w;\n };\n\n return function (token) {\n return token.update(porterStemmer);\n }\n})();\n\nlunr.Pipeline.registerFunction(lunr.stemmer, 'stemmer')\n/*!\n * lunr.stopWordFilter\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.generateStopWordFilter builds a stopWordFilter function from the provided\n * list of stop words.\n *\n * The built in lunr.stopWordFilter is built using this generator and can be used\n * to generate custom stopWordFilters for applications or non English languages.\n *\n * @function\n * @param {Array} token The token to pass through the filter\n * @returns {lunr.PipelineFunction}\n * @see lunr.Pipeline\n * @see lunr.stopWordFilter\n */\nlunr.generateStopWordFilter = function (stopWords) {\n var words = stopWords.reduce(function (memo, stopWord) {\n memo[stopWord] = stopWord\n return memo\n }, {})\n\n return function (token) {\n if (token && words[token.toString()] !== token.toString()) return token\n }\n}\n\n/**\n * lunr.stopWordFilter is an English language stop word list filter, any words\n * contained in the list will not be passed through the filter.\n *\n * This is intended to be used in the Pipeline. If the token does not pass the\n * filter then undefined will be returned.\n *\n * @function\n * @implements {lunr.PipelineFunction}\n * @params {lunr.Token} token - A token to check for being a stop word.\n * @returns {lunr.Token}\n * @see {@link lunr.Pipeline}\n */\nlunr.stopWordFilter = lunr.generateStopWordFilter([\n 'a',\n 'able',\n 'about',\n 'across',\n 'after',\n 'all',\n 'almost',\n 'also',\n 'am',\n 'among',\n 'an',\n 'and',\n 'any',\n 'are',\n 'as',\n 'at',\n 'be',\n 'because',\n 'been',\n 'but',\n 'by',\n 'can',\n 'cannot',\n 'could',\n 'dear',\n 'did',\n 'do',\n 'does',\n 'either',\n 'else',\n 'ever',\n 'every',\n 'for',\n 'from',\n 'get',\n 'got',\n 'had',\n 'has',\n 'have',\n 'he',\n 'her',\n 'hers',\n 'him',\n 'his',\n 'how',\n 'however',\n 'i',\n 'if',\n 'in',\n 'into',\n 'is',\n 'it',\n 'its',\n 'just',\n 'least',\n 'let',\n 'like',\n 'likely',\n 'may',\n 'me',\n 'might',\n 'most',\n 'must',\n 'my',\n 'neither',\n 'no',\n 'nor',\n 'not',\n 'of',\n 'off',\n 'often',\n 'on',\n 'only',\n 'or',\n 'other',\n 'our',\n 'own',\n 'rather',\n 'said',\n 'say',\n 'says',\n 'she',\n 'should',\n 'since',\n 'so',\n 'some',\n 'than',\n 'that',\n 'the',\n 'their',\n 'them',\n 'then',\n 'there',\n 'these',\n 'they',\n 'this',\n 'tis',\n 'to',\n 'too',\n 'twas',\n 'us',\n 'wants',\n 'was',\n 'we',\n 'were',\n 'what',\n 'when',\n 'where',\n 'which',\n 'while',\n 'who',\n 'whom',\n 'why',\n 'will',\n 'with',\n 'would',\n 'yet',\n 'you',\n 'your'\n])\n\nlunr.Pipeline.registerFunction(lunr.stopWordFilter, 'stopWordFilter')\n/*!\n * lunr.trimmer\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.trimmer is a pipeline function for trimming non word\n * characters from the beginning and end of tokens before they\n * enter the index.\n *\n * This implementation may not work correctly for non latin\n * characters and should either be removed or adapted for use\n * with languages with non-latin characters.\n *\n * @static\n * @implements {lunr.PipelineFunction}\n * @param {lunr.Token} token The token to pass through the filter\n * @returns {lunr.Token}\n * @see lunr.Pipeline\n */\nlunr.trimmer = function (token) {\n return token.update(function (s) {\n return s.replace(/^\\W+/, '').replace(/\\W+$/, '')\n })\n}\n\nlunr.Pipeline.registerFunction(lunr.trimmer, 'trimmer')\n/*!\n * lunr.TokenSet\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A token set is used to store the unique list of all tokens\n * within an index. Token sets are also used to represent an\n * incoming query to the index, this query token set and index\n * token set are then intersected to find which tokens to look\n * up in the inverted index.\n *\n * A token set can hold multiple tokens, as in the case of the\n * index token set, or it can hold a single token as in the\n * case of a simple query token set.\n *\n * Additionally token sets are used to perform wildcard matching.\n * Leading, contained and trailing wildcards are supported, and\n * from this edit distance matching can also be provided.\n *\n * Token sets are implemented as a minimal finite state automata,\n * where both common prefixes and suffixes are shared between tokens.\n * This helps to reduce the space used for storing the token set.\n *\n * @constructor\n */\nlunr.TokenSet = function () {\n this.final = false\n this.edges = {}\n this.id = lunr.TokenSet._nextId\n lunr.TokenSet._nextId += 1\n}\n\n/**\n * Keeps track of the next, auto increment, identifier to assign\n * to a new tokenSet.\n *\n * TokenSets require a unique identifier to be correctly minimised.\n *\n * @private\n */\nlunr.TokenSet._nextId = 1\n\n/**\n * Creates a TokenSet instance from the given sorted array of words.\n *\n * @param {String[]} arr - A sorted array of strings to create the set from.\n * @returns {lunr.TokenSet}\n * @throws Will throw an error if the input array is not sorted.\n */\nlunr.TokenSet.fromArray = function (arr) {\n var builder = new lunr.TokenSet.Builder\n\n for (var i = 0, len = arr.length; i < len; i++) {\n builder.insert(arr[i])\n }\n\n builder.finish()\n return builder.root\n}\n\n/**\n * Creates a token set from a query clause.\n *\n * @private\n * @param {Object} clause - A single clause from lunr.Query.\n * @param {string} clause.term - The query clause term.\n * @param {number} [clause.editDistance] - The optional edit distance for the term.\n * @returns {lunr.TokenSet}\n */\nlunr.TokenSet.fromClause = function (clause) {\n if ('editDistance' in clause) {\n return lunr.TokenSet.fromFuzzyString(clause.term, clause.editDistance)\n } else {\n return lunr.TokenSet.fromString(clause.term)\n }\n}\n\n/**\n * Creates a token set representing a single string with a specified\n * edit distance.\n *\n * Insertions, deletions, substitutions and transpositions are each\n * treated as an edit distance of 1.\n *\n * Increasing the allowed edit distance will have a dramatic impact\n * on the performance of both creating and intersecting these TokenSets.\n * It is advised to keep the edit distance less than 3.\n *\n * @param {string} str - The string to create the token set from.\n * @param {number} editDistance - The allowed edit distance to match.\n * @returns {lunr.Vector}\n */\nlunr.TokenSet.fromFuzzyString = function (str, editDistance) {\n var root = new lunr.TokenSet\n\n var stack = [{\n node: root,\n editsRemaining: editDistance,\n str: str\n }]\n\n while (stack.length) {\n var frame = stack.pop()\n\n // no edit\n if (frame.str.length > 0) {\n var char = frame.str.charAt(0),\n noEditNode\n\n if (char in frame.node.edges) {\n noEditNode = frame.node.edges[char]\n } else {\n noEditNode = new lunr.TokenSet\n frame.node.edges[char] = noEditNode\n }\n\n if (frame.str.length == 1) {\n noEditNode.final = true\n }\n\n stack.push({\n node: noEditNode,\n editsRemaining: frame.editsRemaining,\n str: frame.str.slice(1)\n })\n }\n\n if (frame.editsRemaining == 0) {\n continue\n }\n\n // insertion\n if (\"*\" in frame.node.edges) {\n var insertionNode = frame.node.edges[\"*\"]\n } else {\n var insertionNode = new lunr.TokenSet\n frame.node.edges[\"*\"] = insertionNode\n }\n\n if (frame.str.length == 0) {\n insertionNode.final = true\n }\n\n stack.push({\n node: insertionNode,\n editsRemaining: frame.editsRemaining - 1,\n str: frame.str\n })\n\n // deletion\n // can only do a deletion if we have enough edits remaining\n // and if there are characters left to delete in the string\n if (frame.str.length > 1) {\n stack.push({\n node: frame.node,\n editsRemaining: frame.editsRemaining - 1,\n str: frame.str.slice(1)\n })\n }\n\n // deletion\n // just removing the last character from the str\n if (frame.str.length == 1) {\n frame.node.final = true\n }\n\n // substitution\n // can only do a substitution if we have enough edits remaining\n // and if there are characters left to substitute\n if (frame.str.length >= 1) {\n if (\"*\" in frame.node.edges) {\n var substitutionNode = frame.node.edges[\"*\"]\n } else {\n var substitutionNode = new lunr.TokenSet\n frame.node.edges[\"*\"] = substitutionNode\n }\n\n if (frame.str.length == 1) {\n substitutionNode.final = true\n }\n\n stack.push({\n node: substitutionNode,\n editsRemaining: frame.editsRemaining - 1,\n str: frame.str.slice(1)\n })\n }\n\n // transposition\n // can only do a transposition if there are edits remaining\n // and there are enough characters to transpose\n if (frame.str.length > 1) {\n var charA = frame.str.charAt(0),\n charB = frame.str.charAt(1),\n transposeNode\n\n if (charB in frame.node.edges) {\n transposeNode = frame.node.edges[charB]\n } else {\n transposeNode = new lunr.TokenSet\n frame.node.edges[charB] = transposeNode\n }\n\n if (frame.str.length == 1) {\n transposeNode.final = true\n }\n\n stack.push({\n node: transposeNode,\n editsRemaining: frame.editsRemaining - 1,\n str: charA + frame.str.slice(2)\n })\n }\n }\n\n return root\n}\n\n/**\n * Creates a TokenSet from a string.\n *\n * The string may contain one or more wildcard characters (*)\n * that will allow wildcard matching when intersecting with\n * another TokenSet.\n *\n * @param {string} str - The string to create a TokenSet from.\n * @returns {lunr.TokenSet}\n */\nlunr.TokenSet.fromString = function (str) {\n var node = new lunr.TokenSet,\n root = node\n\n /*\n * Iterates through all characters within the passed string\n * appending a node for each character.\n *\n * When a wildcard character is found then a self\n * referencing edge is introduced to continually match\n * any number of any characters.\n */\n for (var i = 0, len = str.length; i < len; i++) {\n var char = str[i],\n final = (i == len - 1)\n\n if (char == \"*\") {\n node.edges[char] = node\n node.final = final\n\n } else {\n var next = new lunr.TokenSet\n next.final = final\n\n node.edges[char] = next\n node = next\n }\n }\n\n return root\n}\n\n/**\n * Converts this TokenSet into an array of strings\n * contained within the TokenSet.\n *\n * This is not intended to be used on a TokenSet that\n * contains wildcards, in these cases the results are\n * undefined and are likely to cause an infinite loop.\n *\n * @returns {string[]}\n */\nlunr.TokenSet.prototype.toArray = function () {\n var words = []\n\n var stack = [{\n prefix: \"\",\n node: this\n }]\n\n while (stack.length) {\n var frame = stack.pop(),\n edges = Object.keys(frame.node.edges),\n len = edges.length\n\n if (frame.node.final) {\n /* In Safari, at this point the prefix is sometimes corrupted, see:\n * https://github.com/olivernn/lunr.js/issues/279 Calling any\n * String.prototype method forces Safari to \"cast\" this string to what\n * it's supposed to be, fixing the bug. */\n frame.prefix.charAt(0)\n words.push(frame.prefix)\n }\n\n for (var i = 0; i < len; i++) {\n var edge = edges[i]\n\n stack.push({\n prefix: frame.prefix.concat(edge),\n node: frame.node.edges[edge]\n })\n }\n }\n\n return words\n}\n\n/**\n * Generates a string representation of a TokenSet.\n *\n * This is intended to allow TokenSets to be used as keys\n * in objects, largely to aid the construction and minimisation\n * of a TokenSet. As such it is not designed to be a human\n * friendly representation of the TokenSet.\n *\n * @returns {string}\n */\nlunr.TokenSet.prototype.toString = function () {\n // NOTE: Using Object.keys here as this.edges is very likely\n // to enter 'hash-mode' with many keys being added\n //\n // avoiding a for-in loop here as it leads to the function\n // being de-optimised (at least in V8). From some simple\n // benchmarks the performance is comparable, but allowing\n // V8 to optimize may mean easy performance wins in the future.\n\n if (this._str) {\n return this._str\n }\n\n var str = this.final ? '1' : '0',\n labels = Object.keys(this.edges).sort(),\n len = labels.length\n\n for (var i = 0; i < len; i++) {\n var label = labels[i],\n node = this.edges[label]\n\n str = str + label + node.id\n }\n\n return str\n}\n\n/**\n * Returns a new TokenSet that is the intersection of\n * this TokenSet and the passed TokenSet.\n *\n * This intersection will take into account any wildcards\n * contained within the TokenSet.\n *\n * @param {lunr.TokenSet} b - An other TokenSet to intersect with.\n * @returns {lunr.TokenSet}\n */\nlunr.TokenSet.prototype.intersect = function (b) {\n var output = new lunr.TokenSet,\n frame = undefined\n\n var stack = [{\n qNode: b,\n output: output,\n node: this\n }]\n\n while (stack.length) {\n frame = stack.pop()\n\n // NOTE: As with the #toString method, we are using\n // Object.keys and a for loop instead of a for-in loop\n // as both of these objects enter 'hash' mode, causing\n // the function to be de-optimised in V8\n var qEdges = Object.keys(frame.qNode.edges),\n qLen = qEdges.length,\n nEdges = Object.keys(frame.node.edges),\n nLen = nEdges.length\n\n for (var q = 0; q < qLen; q++) {\n var qEdge = qEdges[q]\n\n for (var n = 0; n < nLen; n++) {\n var nEdge = nEdges[n]\n\n if (nEdge == qEdge || qEdge == '*') {\n var node = frame.node.edges[nEdge],\n qNode = frame.qNode.edges[qEdge],\n final = node.final && qNode.final,\n next = undefined\n\n if (nEdge in frame.output.edges) {\n // an edge already exists for this character\n // no need to create a new node, just set the finality\n // bit unless this node is already final\n next = frame.output.edges[nEdge]\n next.final = next.final || final\n\n } else {\n // no edge exists yet, must create one\n // set the finality bit and insert it\n // into the output\n next = new lunr.TokenSet\n next.final = final\n frame.output.edges[nEdge] = next\n }\n\n stack.push({\n qNode: qNode,\n output: next,\n node: node\n })\n }\n }\n }\n }\n\n return output\n}\nlunr.TokenSet.Builder = function () {\n this.previousWord = \"\"\n this.root = new lunr.TokenSet\n this.uncheckedNodes = []\n this.minimizedNodes = {}\n}\n\nlunr.TokenSet.Builder.prototype.insert = function (word) {\n var node,\n commonPrefix = 0\n\n if (word < this.previousWord) {\n throw new Error (\"Out of order word insertion\")\n }\n\n for (var i = 0; i < word.length && i < this.previousWord.length; i++) {\n if (word[i] != this.previousWord[i]) break\n commonPrefix++\n }\n\n this.minimize(commonPrefix)\n\n if (this.uncheckedNodes.length == 0) {\n node = this.root\n } else {\n node = this.uncheckedNodes[this.uncheckedNodes.length - 1].child\n }\n\n for (var i = commonPrefix; i < word.length; i++) {\n var nextNode = new lunr.TokenSet,\n char = word[i]\n\n node.edges[char] = nextNode\n\n this.uncheckedNodes.push({\n parent: node,\n char: char,\n child: nextNode\n })\n\n node = nextNode\n }\n\n node.final = true\n this.previousWord = word\n}\n\nlunr.TokenSet.Builder.prototype.finish = function () {\n this.minimize(0)\n}\n\nlunr.TokenSet.Builder.prototype.minimize = function (downTo) {\n for (var i = this.uncheckedNodes.length - 1; i >= downTo; i--) {\n var node = this.uncheckedNodes[i],\n childKey = node.child.toString()\n\n if (childKey in this.minimizedNodes) {\n node.parent.edges[node.char] = this.minimizedNodes[childKey]\n } else {\n // Cache the key for this node since\n // we know it can't change anymore\n node.child._str = childKey\n\n this.minimizedNodes[childKey] = node.child\n }\n\n this.uncheckedNodes.pop()\n }\n}\n/*!\n * lunr.Index\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * An index contains the built index of all documents and provides a query interface\n * to the index.\n *\n * Usually instances of lunr.Index will not be created using this constructor, instead\n * lunr.Builder should be used to construct new indexes, or lunr.Index.load should be\n * used to load previously built and serialized indexes.\n *\n * @constructor\n * @param {Object} attrs - The attributes of the built search index.\n * @param {Object} attrs.invertedIndex - An index of term/field to document reference.\n * @param {Object} attrs.fieldVectors - Field vectors\n * @param {lunr.TokenSet} attrs.tokenSet - An set of all corpus tokens.\n * @param {string[]} attrs.fields - The names of indexed document fields.\n * @param {lunr.Pipeline} attrs.pipeline - The pipeline to use for search terms.\n */\nlunr.Index = function (attrs) {\n this.invertedIndex = attrs.invertedIndex\n this.fieldVectors = attrs.fieldVectors\n this.tokenSet = attrs.tokenSet\n this.fields = attrs.fields\n this.pipeline = attrs.pipeline\n}\n\n/**\n * A result contains details of a document matching a search query.\n * @typedef {Object} lunr.Index~Result\n * @property {string} ref - The reference of the document this result represents.\n * @property {number} score - A number between 0 and 1 representing how similar this document is to the query.\n * @property {lunr.MatchData} matchData - Contains metadata about this match including which term(s) caused the match.\n */\n\n/**\n * Although lunr provides the ability to create queries using lunr.Query, it also provides a simple\n * query language which itself is parsed into an instance of lunr.Query.\n *\n * For programmatically building queries it is advised to directly use lunr.Query, the query language\n * is best used for human entered text rather than program generated text.\n *\n * At its simplest queries can just be a single term, e.g. `hello`, multiple terms are also supported\n * and will be combined with OR, e.g `hello world` will match documents that contain either 'hello'\n * or 'world', though those that contain both will rank higher in the results.\n *\n * Wildcards can be included in terms to match one or more unspecified characters, these wildcards can\n * be inserted anywhere within the term, and more than one wildcard can exist in a single term. Adding\n * wildcards will increase the number of documents that will be found but can also have a negative\n * impact on query performance, especially with wildcards at the beginning of a term.\n *\n * Terms can be restricted to specific fields, e.g. `title:hello`, only documents with the term\n * hello in the title field will match this query. Using a field not present in the index will lead\n * to an error being thrown.\n *\n * Modifiers can also be added to terms, lunr supports edit distance and boost modifiers on terms. A term\n * boost will make documents matching that term score higher, e.g. `foo^5`. Edit distance is also supported\n * to provide fuzzy matching, e.g. 'hello~2' will match documents with hello with an edit distance of 2.\n * Avoid large values for edit distance to improve query performance.\n *\n * Each term also supports a presence modifier. By default a term's presence in document is optional, however\n * this can be changed to either required or prohibited. For a term's presence to be required in a document the\n * term should be prefixed with a '+', e.g. `+foo bar` is a search for documents that must contain 'foo' and\n * optionally contain 'bar'. Conversely a leading '-' sets the terms presence to prohibited, i.e. it must not\n * appear in a document, e.g. `-foo bar` is a search for documents that do not contain 'foo' but may contain 'bar'.\n *\n * To escape special characters the backslash character '\\' can be used, this allows searches to include\n * characters that would normally be considered modifiers, e.g. `foo\\~2` will search for a term \"foo~2\" instead\n * of attempting to apply a boost of 2 to the search term \"foo\".\n *\n * @typedef {string} lunr.Index~QueryString\n * @example Simple single term query\n * hello\n * @example Multiple term query\n * hello world\n * @example term scoped to a field\n * title:hello\n * @example term with a boost of 10\n * hello^10\n * @example term with an edit distance of 2\n * hello~2\n * @example terms with presence modifiers\n * -foo +bar baz\n */\n\n/**\n * Performs a search against the index using lunr query syntax.\n *\n * Results will be returned sorted by their score, the most relevant results\n * will be returned first. For details on how the score is calculated, please see\n * the {@link https://lunrjs.com/guides/searching.html#scoring|guide}.\n *\n * For more programmatic querying use lunr.Index#query.\n *\n * @param {lunr.Index~QueryString} queryString - A string containing a lunr query.\n * @throws {lunr.QueryParseError} If the passed query string cannot be parsed.\n * @returns {lunr.Index~Result[]}\n */\nlunr.Index.prototype.search = function (queryString) {\n return this.query(function (query) {\n var parser = new lunr.QueryParser(queryString, query)\n parser.parse()\n })\n}\n\n/**\n * A query builder callback provides a query object to be used to express\n * the query to perform on the index.\n *\n * @callback lunr.Index~queryBuilder\n * @param {lunr.Query} query - The query object to build up.\n * @this lunr.Query\n */\n\n/**\n * Performs a query against the index using the yielded lunr.Query object.\n *\n * If performing programmatic queries against the index, this method is preferred\n * over lunr.Index#search so as to avoid the additional query parsing overhead.\n *\n * A query object is yielded to the supplied function which should be used to\n * express the query to be run against the index.\n *\n * Note that although this function takes a callback parameter it is _not_ an\n * asynchronous operation, the callback is just yielded a query object to be\n * customized.\n *\n * @param {lunr.Index~queryBuilder} fn - A function that is used to build the query.\n * @returns {lunr.Index~Result[]}\n */\nlunr.Index.prototype.query = function (fn) {\n // for each query clause\n // * process terms\n // * expand terms from token set\n // * find matching documents and metadata\n // * get document vectors\n // * score documents\n\n var query = new lunr.Query(this.fields),\n matchingFields = Object.create(null),\n queryVectors = Object.create(null),\n termFieldCache = Object.create(null),\n requiredMatches = Object.create(null),\n prohibitedMatches = Object.create(null)\n\n /*\n * To support field level boosts a query vector is created per\n * field. An empty vector is eagerly created to support negated\n * queries.\n */\n for (var i = 0; i < this.fields.length; i++) {\n queryVectors[this.fields[i]] = new lunr.Vector\n }\n\n fn.call(query, query)\n\n for (var i = 0; i < query.clauses.length; i++) {\n /*\n * Unless the pipeline has been disabled for this term, which is\n * the case for terms with wildcards, we need to pass the clause\n * term through the search pipeline. A pipeline returns an array\n * of processed terms. Pipeline functions may expand the passed\n * term, which means we may end up performing multiple index lookups\n * for a single query term.\n */\n var clause = query.clauses[i],\n terms = null,\n clauseMatches = lunr.Set.empty\n\n if (clause.usePipeline) {\n terms = this.pipeline.runString(clause.term, {\n fields: clause.fields\n })\n } else {\n terms = [clause.term]\n }\n\n for (var m = 0; m < terms.length; m++) {\n var term = terms[m]\n\n /*\n * Each term returned from the pipeline needs to use the same query\n * clause object, e.g. the same boost and or edit distance. The\n * simplest way to do this is to re-use the clause object but mutate\n * its term property.\n */\n clause.term = term\n\n /*\n * From the term in the clause we create a token set which will then\n * be used to intersect the indexes token set to get a list of terms\n * to lookup in the inverted index\n */\n var termTokenSet = lunr.TokenSet.fromClause(clause),\n expandedTerms = this.tokenSet.intersect(termTokenSet).toArray()\n\n /*\n * If a term marked as required does not exist in the tokenSet it is\n * impossible for the search to return any matches. We set all the field\n * scoped required matches set to empty and stop examining any further\n * clauses.\n */\n if (expandedTerms.length === 0 && clause.presence === lunr.Query.presence.REQUIRED) {\n for (var k = 0; k < clause.fields.length; k++) {\n var field = clause.fields[k]\n requiredMatches[field] = lunr.Set.empty\n }\n\n break\n }\n\n for (var j = 0; j < expandedTerms.length; j++) {\n /*\n * For each term get the posting and termIndex, this is required for\n * building the query vector.\n */\n var expandedTerm = expandedTerms[j],\n posting = this.invertedIndex[expandedTerm],\n termIndex = posting._index\n\n for (var k = 0; k < clause.fields.length; k++) {\n /*\n * For each field that this query term is scoped by (by default\n * all fields are in scope) we need to get all the document refs\n * that have this term in that field.\n *\n * The posting is the entry in the invertedIndex for the matching\n * term from above.\n */\n var field = clause.fields[k],\n fieldPosting = posting[field],\n matchingDocumentRefs = Object.keys(fieldPosting),\n termField = expandedTerm + \"/\" + field,\n matchingDocumentsSet = new lunr.Set(matchingDocumentRefs)\n\n /*\n * if the presence of this term is required ensure that the matching\n * documents are added to the set of required matches for this clause.\n *\n */\n if (clause.presence == lunr.Query.presence.REQUIRED) {\n clauseMatches = clauseMatches.union(matchingDocumentsSet)\n\n if (requiredMatches[field] === undefined) {\n requiredMatches[field] = lunr.Set.complete\n }\n }\n\n /*\n * if the presence of this term is prohibited ensure that the matching\n * documents are added to the set of prohibited matches for this field,\n * creating that set if it does not yet exist.\n */\n if (clause.presence == lunr.Query.presence.PROHIBITED) {\n if (prohibitedMatches[field] === undefined) {\n prohibitedMatches[field] = lunr.Set.empty\n }\n\n prohibitedMatches[field] = prohibitedMatches[field].union(matchingDocumentsSet)\n\n /*\n * Prohibited matches should not be part of the query vector used for\n * similarity scoring and no metadata should be extracted so we continue\n * to the next field\n */\n continue\n }\n\n /*\n * The query field vector is populated using the termIndex found for\n * the term and a unit value with the appropriate boost applied.\n * Using upsert because there could already be an entry in the vector\n * for the term we are working with. In that case we just add the scores\n * together.\n */\n queryVectors[field].upsert(termIndex, clause.boost, function (a, b) { return a + b })\n\n /**\n * If we've already seen this term, field combo then we've already collected\n * the matching documents and metadata, no need to go through all that again\n */\n if (termFieldCache[termField]) {\n continue\n }\n\n for (var l = 0; l < matchingDocumentRefs.length; l++) {\n /*\n * All metadata for this term/field/document triple\n * are then extracted and collected into an instance\n * of lunr.MatchData ready to be returned in the query\n * results\n */\n var matchingDocumentRef = matchingDocumentRefs[l],\n matchingFieldRef = new lunr.FieldRef (matchingDocumentRef, field),\n metadata = fieldPosting[matchingDocumentRef],\n fieldMatch\n\n if ((fieldMatch = matchingFields[matchingFieldRef]) === undefined) {\n matchingFields[matchingFieldRef] = new lunr.MatchData (expandedTerm, field, metadata)\n } else {\n fieldMatch.add(expandedTerm, field, metadata)\n }\n\n }\n\n termFieldCache[termField] = true\n }\n }\n }\n\n /**\n * If the presence was required we need to update the requiredMatches field sets.\n * We do this after all fields for the term have collected their matches because\n * the clause terms presence is required in _any_ of the fields not _all_ of the\n * fields.\n */\n if (clause.presence === lunr.Query.presence.REQUIRED) {\n for (var k = 0; k < clause.fields.length; k++) {\n var field = clause.fields[k]\n requiredMatches[field] = requiredMatches[field].intersect(clauseMatches)\n }\n }\n }\n\n /**\n * Need to combine the field scoped required and prohibited\n * matching documents into a global set of required and prohibited\n * matches\n */\n var allRequiredMatches = lunr.Set.complete,\n allProhibitedMatches = lunr.Set.empty\n\n for (var i = 0; i < this.fields.length; i++) {\n var field = this.fields[i]\n\n if (requiredMatches[field]) {\n allRequiredMatches = allRequiredMatches.intersect(requiredMatches[field])\n }\n\n if (prohibitedMatches[field]) {\n allProhibitedMatches = allProhibitedMatches.union(prohibitedMatches[field])\n }\n }\n\n var matchingFieldRefs = Object.keys(matchingFields),\n results = [],\n matches = Object.create(null)\n\n /*\n * If the query is negated (contains only prohibited terms)\n * we need to get _all_ fieldRefs currently existing in the\n * index. This is only done when we know that the query is\n * entirely prohibited terms to avoid any cost of getting all\n * fieldRefs unnecessarily.\n *\n * Additionally, blank MatchData must be created to correctly\n * populate the results.\n */\n if (query.isNegated()) {\n matchingFieldRefs = Object.keys(this.fieldVectors)\n\n for (var i = 0; i < matchingFieldRefs.length; i++) {\n var matchingFieldRef = matchingFieldRefs[i]\n var fieldRef = lunr.FieldRef.fromString(matchingFieldRef)\n matchingFields[matchingFieldRef] = new lunr.MatchData\n }\n }\n\n for (var i = 0; i < matchingFieldRefs.length; i++) {\n /*\n * Currently we have document fields that match the query, but we\n * need to return documents. The matchData and scores are combined\n * from multiple fields belonging to the same document.\n *\n * Scores are calculated by field, using the query vectors created\n * above, and combined into a final document score using addition.\n */\n var fieldRef = lunr.FieldRef.fromString(matchingFieldRefs[i]),\n docRef = fieldRef.docRef\n\n if (!allRequiredMatches.contains(docRef)) {\n continue\n }\n\n if (allProhibitedMatches.contains(docRef)) {\n continue\n }\n\n var fieldVector = this.fieldVectors[fieldRef],\n score = queryVectors[fieldRef.fieldName].similarity(fieldVector),\n docMatch\n\n if ((docMatch = matches[docRef]) !== undefined) {\n docMatch.score += score\n docMatch.matchData.combine(matchingFields[fieldRef])\n } else {\n var match = {\n ref: docRef,\n score: score,\n matchData: matchingFields[fieldRef]\n }\n matches[docRef] = match\n results.push(match)\n }\n }\n\n /*\n * Sort the results objects by score, highest first.\n */\n return results.sort(function (a, b) {\n return b.score - a.score\n })\n}\n\n/**\n * Prepares the index for JSON serialization.\n *\n * The schema for this JSON blob will be described in a\n * separate JSON schema file.\n *\n * @returns {Object}\n */\nlunr.Index.prototype.toJSON = function () {\n var invertedIndex = Object.keys(this.invertedIndex)\n .sort()\n .map(function (term) {\n return [term, this.invertedIndex[term]]\n }, this)\n\n var fieldVectors = Object.keys(this.fieldVectors)\n .map(function (ref) {\n return [ref, this.fieldVectors[ref].toJSON()]\n }, this)\n\n return {\n version: lunr.version,\n fields: this.fields,\n fieldVectors: fieldVectors,\n invertedIndex: invertedIndex,\n pipeline: this.pipeline.toJSON()\n }\n}\n\n/**\n * Loads a previously serialized lunr.Index\n *\n * @param {Object} serializedIndex - A previously serialized lunr.Index\n * @returns {lunr.Index}\n */\nlunr.Index.load = function (serializedIndex) {\n var attrs = {},\n fieldVectors = {},\n serializedVectors = serializedIndex.fieldVectors,\n invertedIndex = Object.create(null),\n serializedInvertedIndex = serializedIndex.invertedIndex,\n tokenSetBuilder = new lunr.TokenSet.Builder,\n pipeline = lunr.Pipeline.load(serializedIndex.pipeline)\n\n if (serializedIndex.version != lunr.version) {\n lunr.utils.warn(\"Version mismatch when loading serialised index. Current version of lunr '\" + lunr.version + \"' does not match serialized index '\" + serializedIndex.version + \"'\")\n }\n\n for (var i = 0; i < serializedVectors.length; i++) {\n var tuple = serializedVectors[i],\n ref = tuple[0],\n elements = tuple[1]\n\n fieldVectors[ref] = new lunr.Vector(elements)\n }\n\n for (var i = 0; i < serializedInvertedIndex.length; i++) {\n var tuple = serializedInvertedIndex[i],\n term = tuple[0],\n posting = tuple[1]\n\n tokenSetBuilder.insert(term)\n invertedIndex[term] = posting\n }\n\n tokenSetBuilder.finish()\n\n attrs.fields = serializedIndex.fields\n\n attrs.fieldVectors = fieldVectors\n attrs.invertedIndex = invertedIndex\n attrs.tokenSet = tokenSetBuilder.root\n attrs.pipeline = pipeline\n\n return new lunr.Index(attrs)\n}\n/*!\n * lunr.Builder\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.Builder performs indexing on a set of documents and\n * returns instances of lunr.Index ready for querying.\n *\n * All configuration of the index is done via the builder, the\n * fields to index, the document reference, the text processing\n * pipeline and document scoring parameters are all set on the\n * builder before indexing.\n *\n * @constructor\n * @property {string} _ref - Internal reference to the document reference field.\n * @property {string[]} _fields - Internal reference to the document fields to index.\n * @property {object} invertedIndex - The inverted index maps terms to document fields.\n * @property {object} documentTermFrequencies - Keeps track of document term frequencies.\n * @property {object} documentLengths - Keeps track of the length of documents added to the index.\n * @property {lunr.tokenizer} tokenizer - Function for splitting strings into tokens for indexing.\n * @property {lunr.Pipeline} pipeline - The pipeline performs text processing on tokens before indexing.\n * @property {lunr.Pipeline} searchPipeline - A pipeline for processing search terms before querying the index.\n * @property {number} documentCount - Keeps track of the total number of documents indexed.\n * @property {number} _b - A parameter to control field length normalization, setting this to 0 disabled normalization, 1 fully normalizes field lengths, the default value is 0.75.\n * @property {number} _k1 - A parameter to control how quickly an increase in term frequency results in term frequency saturation, the default value is 1.2.\n * @property {number} termIndex - A counter incremented for each unique term, used to identify a terms position in the vector space.\n * @property {array} metadataWhitelist - A list of metadata keys that have been whitelisted for entry in the index.\n */\nlunr.Builder = function () {\n this._ref = \"id\"\n this._fields = Object.create(null)\n this._documents = Object.create(null)\n this.invertedIndex = Object.create(null)\n this.fieldTermFrequencies = {}\n this.fieldLengths = {}\n this.tokenizer = lunr.tokenizer\n this.pipeline = new lunr.Pipeline\n this.searchPipeline = new lunr.Pipeline\n this.documentCount = 0\n this._b = 0.75\n this._k1 = 1.2\n this.termIndex = 0\n this.metadataWhitelist = []\n}\n\n/**\n * Sets the document field used as the document reference. Every document must have this field.\n * The type of this field in the document should be a string, if it is not a string it will be\n * coerced into a string by calling toString.\n *\n * The default ref is 'id'.\n *\n * The ref should _not_ be changed during indexing, it should be set before any documents are\n * added to the index. Changing it during indexing can lead to inconsistent results.\n *\n * @param {string} ref - The name of the reference field in the document.\n */\nlunr.Builder.prototype.ref = function (ref) {\n this._ref = ref\n}\n\n/**\n * A function that is used to extract a field from a document.\n *\n * Lunr expects a field to be at the top level of a document, if however the field\n * is deeply nested within a document an extractor function can be used to extract\n * the right field for indexing.\n *\n * @callback fieldExtractor\n * @param {object} doc - The document being added to the index.\n * @returns {?(string|object|object[])} obj - The object that will be indexed for this field.\n * @example Extracting a nested field\n * function (doc) { return doc.nested.field }\n */\n\n/**\n * Adds a field to the list of document fields that will be indexed. Every document being\n * indexed should have this field. Null values for this field in indexed documents will\n * not cause errors but will limit the chance of that document being retrieved by searches.\n *\n * All fields should be added before adding documents to the index. Adding fields after\n * a document has been indexed will have no effect on already indexed documents.\n *\n * Fields can be boosted at build time. This allows terms within that field to have more\n * importance when ranking search results. Use a field boost to specify that matches within\n * one field are more important than other fields.\n *\n * @param {string} fieldName - The name of a field to index in all documents.\n * @param {object} attributes - Optional attributes associated with this field.\n * @param {number} [attributes.boost=1] - Boost applied to all terms within this field.\n * @param {fieldExtractor} [attributes.extractor] - Function to extract a field from a document.\n * @throws {RangeError} fieldName cannot contain unsupported characters '/'\n */\nlunr.Builder.prototype.field = function (fieldName, attributes) {\n if (/\\//.test(fieldName)) {\n throw new RangeError (\"Field '\" + fieldName + \"' contains illegal character '/'\")\n }\n\n this._fields[fieldName] = attributes || {}\n}\n\n/**\n * A parameter to tune the amount of field length normalisation that is applied when\n * calculating relevance scores. A value of 0 will completely disable any normalisation\n * and a value of 1 will fully normalise field lengths. The default is 0.75. Values of b\n * will be clamped to the range 0 - 1.\n *\n * @param {number} number - The value to set for this tuning parameter.\n */\nlunr.Builder.prototype.b = function (number) {\n if (number < 0) {\n this._b = 0\n } else if (number > 1) {\n this._b = 1\n } else {\n this._b = number\n }\n}\n\n/**\n * A parameter that controls the speed at which a rise in term frequency results in term\n * frequency saturation. The default value is 1.2. Setting this to a higher value will give\n * slower saturation levels, a lower value will result in quicker saturation.\n *\n * @param {number} number - The value to set for this tuning parameter.\n */\nlunr.Builder.prototype.k1 = function (number) {\n this._k1 = number\n}\n\n/**\n * Adds a document to the index.\n *\n * Before adding fields to the index the index should have been fully setup, with the document\n * ref and all fields to index already having been specified.\n *\n * The document must have a field name as specified by the ref (by default this is 'id') and\n * it should have all fields defined for indexing, though null or undefined values will not\n * cause errors.\n *\n * Entire documents can be boosted at build time. Applying a boost to a document indicates that\n * this document should rank higher in search results than other documents.\n *\n * @param {object} doc - The document to add to the index.\n * @param {object} attributes - Optional attributes associated with this document.\n * @param {number} [attributes.boost=1] - Boost applied to all terms within this document.\n */\nlunr.Builder.prototype.add = function (doc, attributes) {\n var docRef = doc[this._ref],\n fields = Object.keys(this._fields)\n\n this._documents[docRef] = attributes || {}\n this.documentCount += 1\n\n for (var i = 0; i < fields.length; i++) {\n var fieldName = fields[i],\n extractor = this._fields[fieldName].extractor,\n field = extractor ? extractor(doc) : doc[fieldName],\n tokens = this.tokenizer(field, {\n fields: [fieldName]\n }),\n terms = this.pipeline.run(tokens),\n fieldRef = new lunr.FieldRef (docRef, fieldName),\n fieldTerms = Object.create(null)\n\n this.fieldTermFrequencies[fieldRef] = fieldTerms\n this.fieldLengths[fieldRef] = 0\n\n // store the length of this field for this document\n this.fieldLengths[fieldRef] += terms.length\n\n // calculate term frequencies for this field\n for (var j = 0; j < terms.length; j++) {\n var term = terms[j]\n\n if (fieldTerms[term] == undefined) {\n fieldTerms[term] = 0\n }\n\n fieldTerms[term] += 1\n\n // add to inverted index\n // create an initial posting if one doesn't exist\n if (this.invertedIndex[term] == undefined) {\n var posting = Object.create(null)\n posting[\"_index\"] = this.termIndex\n this.termIndex += 1\n\n for (var k = 0; k < fields.length; k++) {\n posting[fields[k]] = Object.create(null)\n }\n\n this.invertedIndex[term] = posting\n }\n\n // add an entry for this term/fieldName/docRef to the invertedIndex\n if (this.invertedIndex[term][fieldName][docRef] == undefined) {\n this.invertedIndex[term][fieldName][docRef] = Object.create(null)\n }\n\n // store all whitelisted metadata about this token in the\n // inverted index\n for (var l = 0; l < this.metadataWhitelist.length; l++) {\n var metadataKey = this.metadataWhitelist[l],\n metadata = term.metadata[metadataKey]\n\n if (this.invertedIndex[term][fieldName][docRef][metadataKey] == undefined) {\n this.invertedIndex[term][fieldName][docRef][metadataKey] = []\n }\n\n this.invertedIndex[term][fieldName][docRef][metadataKey].push(metadata)\n }\n }\n\n }\n}\n\n/**\n * Calculates the average document length for this index\n *\n * @private\n */\nlunr.Builder.prototype.calculateAverageFieldLengths = function () {\n\n var fieldRefs = Object.keys(this.fieldLengths),\n numberOfFields = fieldRefs.length,\n accumulator = {},\n documentsWithField = {}\n\n for (var i = 0; i < numberOfFields; i++) {\n var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]),\n field = fieldRef.fieldName\n\n documentsWithField[field] || (documentsWithField[field] = 0)\n documentsWithField[field] += 1\n\n accumulator[field] || (accumulator[field] = 0)\n accumulator[field] += this.fieldLengths[fieldRef]\n }\n\n var fields = Object.keys(this._fields)\n\n for (var i = 0; i < fields.length; i++) {\n var fieldName = fields[i]\n accumulator[fieldName] = accumulator[fieldName] / documentsWithField[fieldName]\n }\n\n this.averageFieldLength = accumulator\n}\n\n/**\n * Builds a vector space model of every document using lunr.Vector\n *\n * @private\n */\nlunr.Builder.prototype.createFieldVectors = function () {\n var fieldVectors = {},\n fieldRefs = Object.keys(this.fieldTermFrequencies),\n fieldRefsLength = fieldRefs.length,\n termIdfCache = Object.create(null)\n\n for (var i = 0; i < fieldRefsLength; i++) {\n var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]),\n fieldName = fieldRef.fieldName,\n fieldLength = this.fieldLengths[fieldRef],\n fieldVector = new lunr.Vector,\n termFrequencies = this.fieldTermFrequencies[fieldRef],\n terms = Object.keys(termFrequencies),\n termsLength = terms.length\n\n\n var fieldBoost = this._fields[fieldName].boost || 1,\n docBoost = this._documents[fieldRef.docRef].boost || 1\n\n for (var j = 0; j < termsLength; j++) {\n var term = terms[j],\n tf = termFrequencies[term],\n termIndex = this.invertedIndex[term]._index,\n idf, score, scoreWithPrecision\n\n if (termIdfCache[term] === undefined) {\n idf = lunr.idf(this.invertedIndex[term], this.documentCount)\n termIdfCache[term] = idf\n } else {\n idf = termIdfCache[term]\n }\n\n score = idf * ((this._k1 + 1) * tf) / (this._k1 * (1 - this._b + this._b * (fieldLength / this.averageFieldLength[fieldName])) + tf)\n score *= fieldBoost\n score *= docBoost\n scoreWithPrecision = Math.round(score * 1000) / 1000\n // Converts 1.23456789 to 1.234.\n // Reducing the precision so that the vectors take up less\n // space when serialised. Doing it now so that they behave\n // the same before and after serialisation. Also, this is\n // the fastest approach to reducing a number's precision in\n // JavaScript.\n\n fieldVector.insert(termIndex, scoreWithPrecision)\n }\n\n fieldVectors[fieldRef] = fieldVector\n }\n\n this.fieldVectors = fieldVectors\n}\n\n/**\n * Creates a token set of all tokens in the index using lunr.TokenSet\n *\n * @private\n */\nlunr.Builder.prototype.createTokenSet = function () {\n this.tokenSet = lunr.TokenSet.fromArray(\n Object.keys(this.invertedIndex).sort()\n )\n}\n\n/**\n * Builds the index, creating an instance of lunr.Index.\n *\n * This completes the indexing process and should only be called\n * once all documents have been added to the index.\n *\n * @returns {lunr.Index}\n */\nlunr.Builder.prototype.build = function () {\n this.calculateAverageFieldLengths()\n this.createFieldVectors()\n this.createTokenSet()\n\n return new lunr.Index({\n invertedIndex: this.invertedIndex,\n fieldVectors: this.fieldVectors,\n tokenSet: this.tokenSet,\n fields: Object.keys(this._fields),\n pipeline: this.searchPipeline\n })\n}\n\n/**\n * Applies a plugin to the index builder.\n *\n * A plugin is a function that is called with the index builder as its context.\n * Plugins can be used to customise or extend the behaviour of the index\n * in some way. A plugin is just a function, that encapsulated the custom\n * behaviour that should be applied when building the index.\n *\n * The plugin function will be called with the index builder as its argument, additional\n * arguments can also be passed when calling use. The function will be called\n * with the index builder as its context.\n *\n * @param {Function} plugin The plugin to apply.\n */\nlunr.Builder.prototype.use = function (fn) {\n var args = Array.prototype.slice.call(arguments, 1)\n args.unshift(this)\n fn.apply(this, args)\n}\n/**\n * Contains and collects metadata about a matching document.\n * A single instance of lunr.MatchData is returned as part of every\n * lunr.Index~Result.\n *\n * @constructor\n * @param {string} term - The term this match data is associated with\n * @param {string} field - The field in which the term was found\n * @param {object} metadata - The metadata recorded about this term in this field\n * @property {object} metadata - A cloned collection of metadata associated with this document.\n * @see {@link lunr.Index~Result}\n */\nlunr.MatchData = function (term, field, metadata) {\n var clonedMetadata = Object.create(null),\n metadataKeys = Object.keys(metadata || {})\n\n // Cloning the metadata to prevent the original\n // being mutated during match data combination.\n // Metadata is kept in an array within the inverted\n // index so cloning the data can be done with\n // Array#slice\n for (var i = 0; i < metadataKeys.length; i++) {\n var key = metadataKeys[i]\n clonedMetadata[key] = metadata[key].slice()\n }\n\n this.metadata = Object.create(null)\n\n if (term !== undefined) {\n this.metadata[term] = Object.create(null)\n this.metadata[term][field] = clonedMetadata\n }\n}\n\n/**\n * An instance of lunr.MatchData will be created for every term that matches a\n * document. However only one instance is required in a lunr.Index~Result. This\n * method combines metadata from another instance of lunr.MatchData with this\n * objects metadata.\n *\n * @param {lunr.MatchData} otherMatchData - Another instance of match data to merge with this one.\n * @see {@link lunr.Index~Result}\n */\nlunr.MatchData.prototype.combine = function (otherMatchData) {\n var terms = Object.keys(otherMatchData.metadata)\n\n for (var i = 0; i < terms.length; i++) {\n var term = terms[i],\n fields = Object.keys(otherMatchData.metadata[term])\n\n if (this.metadata[term] == undefined) {\n this.metadata[term] = Object.create(null)\n }\n\n for (var j = 0; j < fields.length; j++) {\n var field = fields[j],\n keys = Object.keys(otherMatchData.metadata[term][field])\n\n if (this.metadata[term][field] == undefined) {\n this.metadata[term][field] = Object.create(null)\n }\n\n for (var k = 0; k < keys.length; k++) {\n var key = keys[k]\n\n if (this.metadata[term][field][key] == undefined) {\n this.metadata[term][field][key] = otherMatchData.metadata[term][field][key]\n } else {\n this.metadata[term][field][key] = this.metadata[term][field][key].concat(otherMatchData.metadata[term][field][key])\n }\n\n }\n }\n }\n}\n\n/**\n * Add metadata for a term/field pair to this instance of match data.\n *\n * @param {string} term - The term this match data is associated with\n * @param {string} field - The field in which the term was found\n * @param {object} metadata - The metadata recorded about this term in this field\n */\nlunr.MatchData.prototype.add = function (term, field, metadata) {\n if (!(term in this.metadata)) {\n this.metadata[term] = Object.create(null)\n this.metadata[term][field] = metadata\n return\n }\n\n if (!(field in this.metadata[term])) {\n this.metadata[term][field] = metadata\n return\n }\n\n var metadataKeys = Object.keys(metadata)\n\n for (var i = 0; i < metadataKeys.length; i++) {\n var key = metadataKeys[i]\n\n if (key in this.metadata[term][field]) {\n this.metadata[term][field][key] = this.metadata[term][field][key].concat(metadata[key])\n } else {\n this.metadata[term][field][key] = metadata[key]\n }\n }\n}\n/**\n * A lunr.Query provides a programmatic way of defining queries to be performed\n * against a {@link lunr.Index}.\n *\n * Prefer constructing a lunr.Query using the {@link lunr.Index#query} method\n * so the query object is pre-initialized with the right index fields.\n *\n * @constructor\n * @property {lunr.Query~Clause[]} clauses - An array of query clauses.\n * @property {string[]} allFields - An array of all available fields in a lunr.Index.\n */\nlunr.Query = function (allFields) {\n this.clauses = []\n this.allFields = allFields\n}\n\n/**\n * Constants for indicating what kind of automatic wildcard insertion will be used when constructing a query clause.\n *\n * This allows wildcards to be added to the beginning and end of a term without having to manually do any string\n * concatenation.\n *\n * The wildcard constants can be bitwise combined to select both leading and trailing wildcards.\n *\n * @constant\n * @default\n * @property {number} wildcard.NONE - The term will have no wildcards inserted, this is the default behaviour\n * @property {number} wildcard.LEADING - Prepend the term with a wildcard, unless a leading wildcard already exists\n * @property {number} wildcard.TRAILING - Append a wildcard to the term, unless a trailing wildcard already exists\n * @see lunr.Query~Clause\n * @see lunr.Query#clause\n * @see lunr.Query#term\n * @example query term with trailing wildcard\n * query.term('foo', { wildcard: lunr.Query.wildcard.TRAILING })\n * @example query term with leading and trailing wildcard\n * query.term('foo', {\n * wildcard: lunr.Query.wildcard.LEADING | lunr.Query.wildcard.TRAILING\n * })\n */\n\nlunr.Query.wildcard = new String (\"*\")\nlunr.Query.wildcard.NONE = 0\nlunr.Query.wildcard.LEADING = 1\nlunr.Query.wildcard.TRAILING = 2\n\n/**\n * Constants for indicating what kind of presence a term must have in matching documents.\n *\n * @constant\n * @enum {number}\n * @see lunr.Query~Clause\n * @see lunr.Query#clause\n * @see lunr.Query#term\n * @example query term with required presence\n * query.term('foo', { presence: lunr.Query.presence.REQUIRED })\n */\nlunr.Query.presence = {\n /**\n * Term's presence in a document is optional, this is the default value.\n */\n OPTIONAL: 1,\n\n /**\n * Term's presence in a document is required, documents that do not contain\n * this term will not be returned.\n */\n REQUIRED: 2,\n\n /**\n * Term's presence in a document is prohibited, documents that do contain\n * this term will not be returned.\n */\n PROHIBITED: 3\n}\n\n/**\n * A single clause in a {@link lunr.Query} contains a term and details on how to\n * match that term against a {@link lunr.Index}.\n *\n * @typedef {Object} lunr.Query~Clause\n * @property {string[]} fields - The fields in an index this clause should be matched against.\n * @property {number} [boost=1] - Any boost that should be applied when matching this clause.\n * @property {number} [editDistance] - Whether the term should have fuzzy matching applied, and how fuzzy the match should be.\n * @property {boolean} [usePipeline] - Whether the term should be passed through the search pipeline.\n * @property {number} [wildcard=lunr.Query.wildcard.NONE] - Whether the term should have wildcards appended or prepended.\n * @property {number} [presence=lunr.Query.presence.OPTIONAL] - The terms presence in any matching documents.\n */\n\n/**\n * Adds a {@link lunr.Query~Clause} to this query.\n *\n * Unless the clause contains the fields to be matched all fields will be matched. In addition\n * a default boost of 1 is applied to the clause.\n *\n * @param {lunr.Query~Clause} clause - The clause to add to this query.\n * @see lunr.Query~Clause\n * @returns {lunr.Query}\n */\nlunr.Query.prototype.clause = function (clause) {\n if (!('fields' in clause)) {\n clause.fields = this.allFields\n }\n\n if (!('boost' in clause)) {\n clause.boost = 1\n }\n\n if (!('usePipeline' in clause)) {\n clause.usePipeline = true\n }\n\n if (!('wildcard' in clause)) {\n clause.wildcard = lunr.Query.wildcard.NONE\n }\n\n if ((clause.wildcard & lunr.Query.wildcard.LEADING) && (clause.term.charAt(0) != lunr.Query.wildcard)) {\n clause.term = \"*\" + clause.term\n }\n\n if ((clause.wildcard & lunr.Query.wildcard.TRAILING) && (clause.term.slice(-1) != lunr.Query.wildcard)) {\n clause.term = \"\" + clause.term + \"*\"\n }\n\n if (!('presence' in clause)) {\n clause.presence = lunr.Query.presence.OPTIONAL\n }\n\n this.clauses.push(clause)\n\n return this\n}\n\n/**\n * A negated query is one in which every clause has a presence of\n * prohibited. These queries require some special processing to return\n * the expected results.\n *\n * @returns boolean\n */\nlunr.Query.prototype.isNegated = function () {\n for (var i = 0; i < this.clauses.length; i++) {\n if (this.clauses[i].presence != lunr.Query.presence.PROHIBITED) {\n return false\n }\n }\n\n return true\n}\n\n/**\n * Adds a term to the current query, under the covers this will create a {@link lunr.Query~Clause}\n * to the list of clauses that make up this query.\n *\n * The term is used as is, i.e. no tokenization will be performed by this method. Instead conversion\n * to a token or token-like string should be done before calling this method.\n *\n * The term will be converted to a string by calling `toString`. Multiple terms can be passed as an\n * array, each term in the array will share the same options.\n *\n * @param {object|object[]} term - The term(s) to add to the query.\n * @param {object} [options] - Any additional properties to add to the query clause.\n * @returns {lunr.Query}\n * @see lunr.Query#clause\n * @see lunr.Query~Clause\n * @example adding a single term to a query\n * query.term(\"foo\")\n * @example adding a single term to a query and specifying search fields, term boost and automatic trailing wildcard\n * query.term(\"foo\", {\n * fields: [\"title\"],\n * boost: 10,\n * wildcard: lunr.Query.wildcard.TRAILING\n * })\n * @example using lunr.tokenizer to convert a string to tokens before using them as terms\n * query.term(lunr.tokenizer(\"foo bar\"))\n */\nlunr.Query.prototype.term = function (term, options) {\n if (Array.isArray(term)) {\n term.forEach(function (t) { this.term(t, lunr.utils.clone(options)) }, this)\n return this\n }\n\n var clause = options || {}\n clause.term = term.toString()\n\n this.clause(clause)\n\n return this\n}\nlunr.QueryParseError = function (message, start, end) {\n this.name = \"QueryParseError\"\n this.message = message\n this.start = start\n this.end = end\n}\n\nlunr.QueryParseError.prototype = new Error\nlunr.QueryLexer = function (str) {\n this.lexemes = []\n this.str = str\n this.length = str.length\n this.pos = 0\n this.start = 0\n this.escapeCharPositions = []\n}\n\nlunr.QueryLexer.prototype.run = function () {\n var state = lunr.QueryLexer.lexText\n\n while (state) {\n state = state(this)\n }\n}\n\nlunr.QueryLexer.prototype.sliceString = function () {\n var subSlices = [],\n sliceStart = this.start,\n sliceEnd = this.pos\n\n for (var i = 0; i < this.escapeCharPositions.length; i++) {\n sliceEnd = this.escapeCharPositions[i]\n subSlices.push(this.str.slice(sliceStart, sliceEnd))\n sliceStart = sliceEnd + 1\n }\n\n subSlices.push(this.str.slice(sliceStart, this.pos))\n this.escapeCharPositions.length = 0\n\n return subSlices.join('')\n}\n\nlunr.QueryLexer.prototype.emit = function (type) {\n this.lexemes.push({\n type: type,\n str: this.sliceString(),\n start: this.start,\n end: this.pos\n })\n\n this.start = this.pos\n}\n\nlunr.QueryLexer.prototype.escapeCharacter = function () {\n this.escapeCharPositions.push(this.pos - 1)\n this.pos += 1\n}\n\nlunr.QueryLexer.prototype.next = function () {\n if (this.pos >= this.length) {\n return lunr.QueryLexer.EOS\n }\n\n var char = this.str.charAt(this.pos)\n this.pos += 1\n return char\n}\n\nlunr.QueryLexer.prototype.width = function () {\n return this.pos - this.start\n}\n\nlunr.QueryLexer.prototype.ignore = function () {\n if (this.start == this.pos) {\n this.pos += 1\n }\n\n this.start = this.pos\n}\n\nlunr.QueryLexer.prototype.backup = function () {\n this.pos -= 1\n}\n\nlunr.QueryLexer.prototype.acceptDigitRun = function () {\n var char, charCode\n\n do {\n char = this.next()\n charCode = char.charCodeAt(0)\n } while (charCode > 47 && charCode < 58)\n\n if (char != lunr.QueryLexer.EOS) {\n this.backup()\n }\n}\n\nlunr.QueryLexer.prototype.more = function () {\n return this.pos < this.length\n}\n\nlunr.QueryLexer.EOS = 'EOS'\nlunr.QueryLexer.FIELD = 'FIELD'\nlunr.QueryLexer.TERM = 'TERM'\nlunr.QueryLexer.EDIT_DISTANCE = 'EDIT_DISTANCE'\nlunr.QueryLexer.BOOST = 'BOOST'\nlunr.QueryLexer.PRESENCE = 'PRESENCE'\n\nlunr.QueryLexer.lexField = function (lexer) {\n lexer.backup()\n lexer.emit(lunr.QueryLexer.FIELD)\n lexer.ignore()\n return lunr.QueryLexer.lexText\n}\n\nlunr.QueryLexer.lexTerm = function (lexer) {\n if (lexer.width() > 1) {\n lexer.backup()\n lexer.emit(lunr.QueryLexer.TERM)\n }\n\n lexer.ignore()\n\n if (lexer.more()) {\n return lunr.QueryLexer.lexText\n }\n}\n\nlunr.QueryLexer.lexEditDistance = function (lexer) {\n lexer.ignore()\n lexer.acceptDigitRun()\n lexer.emit(lunr.QueryLexer.EDIT_DISTANCE)\n return lunr.QueryLexer.lexText\n}\n\nlunr.QueryLexer.lexBoost = function (lexer) {\n lexer.ignore()\n lexer.acceptDigitRun()\n lexer.emit(lunr.QueryLexer.BOOST)\n return lunr.QueryLexer.lexText\n}\n\nlunr.QueryLexer.lexEOS = function (lexer) {\n if (lexer.width() > 0) {\n lexer.emit(lunr.QueryLexer.TERM)\n }\n}\n\n// This matches the separator used when tokenising fields\n// within a document. These should match otherwise it is\n// not possible to search for some tokens within a document.\n//\n// It is possible for the user to change the separator on the\n// tokenizer so it _might_ clash with any other of the special\n// characters already used within the search string, e.g. :.\n//\n// This means that it is possible to change the separator in\n// such a way that makes some words unsearchable using a search\n// string.\nlunr.QueryLexer.termSeparator = lunr.tokenizer.separator\n\nlunr.QueryLexer.lexText = function (lexer) {\n while (true) {\n var char = lexer.next()\n\n if (char == lunr.QueryLexer.EOS) {\n return lunr.QueryLexer.lexEOS\n }\n\n // Escape character is '\\'\n if (char.charCodeAt(0) == 92) {\n lexer.escapeCharacter()\n continue\n }\n\n if (char == \":\") {\n return lunr.QueryLexer.lexField\n }\n\n if (char == \"~\") {\n lexer.backup()\n if (lexer.width() > 0) {\n lexer.emit(lunr.QueryLexer.TERM)\n }\n return lunr.QueryLexer.lexEditDistance\n }\n\n if (char == \"^\") {\n lexer.backup()\n if (lexer.width() > 0) {\n lexer.emit(lunr.QueryLexer.TERM)\n }\n return lunr.QueryLexer.lexBoost\n }\n\n // \"+\" indicates term presence is required\n // checking for length to ensure that only\n // leading \"+\" are considered\n if (char == \"+\" && lexer.width() === 1) {\n lexer.emit(lunr.QueryLexer.PRESENCE)\n return lunr.QueryLexer.lexText\n }\n\n // \"-\" indicates term presence is prohibited\n // checking for length to ensure that only\n // leading \"-\" are considered\n if (char == \"-\" && lexer.width() === 1) {\n lexer.emit(lunr.QueryLexer.PRESENCE)\n return lunr.QueryLexer.lexText\n }\n\n if (char.match(lunr.QueryLexer.termSeparator)) {\n return lunr.QueryLexer.lexTerm\n }\n }\n}\n\nlunr.QueryParser = function (str, query) {\n this.lexer = new lunr.QueryLexer (str)\n this.query = query\n this.currentClause = {}\n this.lexemeIdx = 0\n}\n\nlunr.QueryParser.prototype.parse = function () {\n this.lexer.run()\n this.lexemes = this.lexer.lexemes\n\n var state = lunr.QueryParser.parseClause\n\n while (state) {\n state = state(this)\n }\n\n return this.query\n}\n\nlunr.QueryParser.prototype.peekLexeme = function () {\n return this.lexemes[this.lexemeIdx]\n}\n\nlunr.QueryParser.prototype.consumeLexeme = function () {\n var lexeme = this.peekLexeme()\n this.lexemeIdx += 1\n return lexeme\n}\n\nlunr.QueryParser.prototype.nextClause = function () {\n var completedClause = this.currentClause\n this.query.clause(completedClause)\n this.currentClause = {}\n}\n\nlunr.QueryParser.parseClause = function (parser) {\n var lexeme = parser.peekLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n switch (lexeme.type) {\n case lunr.QueryLexer.PRESENCE:\n return lunr.QueryParser.parsePresence\n case lunr.QueryLexer.FIELD:\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.TERM:\n return lunr.QueryParser.parseTerm\n default:\n var errorMessage = \"expected either a field or a term, found \" + lexeme.type\n\n if (lexeme.str.length >= 1) {\n errorMessage += \" with value '\" + lexeme.str + \"'\"\n }\n\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n}\n\nlunr.QueryParser.parsePresence = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n switch (lexeme.str) {\n case \"-\":\n parser.currentClause.presence = lunr.Query.presence.PROHIBITED\n break\n case \"+\":\n parser.currentClause.presence = lunr.Query.presence.REQUIRED\n break\n default:\n var errorMessage = \"unrecognised presence operator'\" + lexeme.str + \"'\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n var errorMessage = \"expecting term or field, found nothing\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.FIELD:\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.TERM:\n return lunr.QueryParser.parseTerm\n default:\n var errorMessage = \"expecting term or field, found '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseField = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n if (parser.query.allFields.indexOf(lexeme.str) == -1) {\n var possibleFields = parser.query.allFields.map(function (f) { return \"'\" + f + \"'\" }).join(', '),\n errorMessage = \"unrecognised field '\" + lexeme.str + \"', possible fields: \" + possibleFields\n\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n parser.currentClause.fields = [lexeme.str]\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n var errorMessage = \"expecting term, found nothing\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n return lunr.QueryParser.parseTerm\n default:\n var errorMessage = \"expecting term, found '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseTerm = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n parser.currentClause.term = lexeme.str.toLowerCase()\n\n if (lexeme.str.indexOf(\"*\") != -1) {\n parser.currentClause.usePipeline = false\n }\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n parser.nextClause()\n return\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n parser.nextClause()\n return lunr.QueryParser.parseTerm\n case lunr.QueryLexer.FIELD:\n parser.nextClause()\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.EDIT_DISTANCE:\n return lunr.QueryParser.parseEditDistance\n case lunr.QueryLexer.BOOST:\n return lunr.QueryParser.parseBoost\n case lunr.QueryLexer.PRESENCE:\n parser.nextClause()\n return lunr.QueryParser.parsePresence\n default:\n var errorMessage = \"Unexpected lexeme type '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseEditDistance = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n var editDistance = parseInt(lexeme.str, 10)\n\n if (isNaN(editDistance)) {\n var errorMessage = \"edit distance must be numeric\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n parser.currentClause.editDistance = editDistance\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n parser.nextClause()\n return\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n parser.nextClause()\n return lunr.QueryParser.parseTerm\n case lunr.QueryLexer.FIELD:\n parser.nextClause()\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.EDIT_DISTANCE:\n return lunr.QueryParser.parseEditDistance\n case lunr.QueryLexer.BOOST:\n return lunr.QueryParser.parseBoost\n case lunr.QueryLexer.PRESENCE:\n parser.nextClause()\n return lunr.QueryParser.parsePresence\n default:\n var errorMessage = \"Unexpected lexeme type '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseBoost = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n var boost = parseInt(lexeme.str, 10)\n\n if (isNaN(boost)) {\n var errorMessage = \"boost must be numeric\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n parser.currentClause.boost = boost\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n parser.nextClause()\n return\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n parser.nextClause()\n return lunr.QueryParser.parseTerm\n case lunr.QueryLexer.FIELD:\n parser.nextClause()\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.EDIT_DISTANCE:\n return lunr.QueryParser.parseEditDistance\n case lunr.QueryLexer.BOOST:\n return lunr.QueryParser.parseBoost\n case lunr.QueryLexer.PRESENCE:\n parser.nextClause()\n return lunr.QueryParser.parsePresence\n default:\n var errorMessage = \"Unexpected lexeme type '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\n /**\n * export the module via AMD, CommonJS or as a browser global\n * Export code from https://github.com/umdjs/umd/blob/master/returnExports.js\n */\n ;(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define(factory)\n } else if (typeof exports === 'object') {\n /**\n * Node. Does not work with strict CommonJS, but\n * only CommonJS-like enviroments that support module.exports,\n * like Node.\n */\n module.exports = factory()\n } else {\n // Browser globals (root is window)\n root.lunr = factory()\n }\n }(this, function () {\n /**\n * Just return a value to define the module export.\n * This example returns an object, but the module\n * can return a function as the exported value.\n */\n return lunr\n }))\n})();\n", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport lunr from \"lunr\"\n\nimport \"~/polyfills\"\n\nimport { Search, SearchIndexConfig } from \"../../_\"\nimport {\n SearchMessage,\n SearchMessageType\n} from \"../message\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Add support for usage with `iframe-worker` polyfill\n *\n * While `importScripts` is synchronous when executed inside of a web worker,\n * it's not possible to provide a synchronous polyfilled implementation. The\n * cool thing is that awaiting a non-Promise is a noop, so extending the type\n * definition to return a `Promise` shouldn't break anything.\n *\n * @see https://bit.ly/2PjDnXi - GitHub comment\n */\ndeclare global {\n function importScripts(...urls: string[]): Promise | void\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Search index\n */\nlet index: Search\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch (= import) multi-language support through `lunr-languages`\n *\n * This function automatically imports the stemmers necessary to process the\n * languages, which are defined through the search index configuration.\n *\n * If the worker runs inside of an `iframe` (when using `iframe-worker` as\n * a shim), the base URL for the stemmers to be loaded must be determined by\n * searching for the first `script` element with a `src` attribute, which will\n * contain the contents of this script.\n *\n * @param config - Search index configuration\n *\n * @returns Promise resolving with no result\n */\nasync function setupSearchLanguages(\n config: SearchIndexConfig\n): Promise {\n let base = \"../lunr\"\n\n /* Detect `iframe-worker` and fix base URL */\n if (typeof parent !== \"undefined\" && \"IFrameWorker\" in parent) {\n const worker = document.querySelector(\"script[src]\")!\n const [path] = worker.src.split(\"/worker\")\n\n /* Prefix base with path */\n base = base.replace(\"..\", path)\n }\n\n /* Add scripts for languages */\n const scripts = []\n for (const lang of config.lang) {\n switch (lang) {\n\n /* Add segmenter for Japanese */\n case \"ja\":\n scripts.push(`${base}/tinyseg.js`)\n break\n\n /* Add segmenter for Hindi and Thai */\n case \"hi\":\n case \"th\":\n scripts.push(`${base}/wordcut.js`)\n break\n }\n\n /* Add language support */\n if (lang !== \"en\")\n scripts.push(`${base}/min/lunr.${lang}.min.js`)\n }\n\n /* Add multi-language support */\n if (config.lang.length > 1)\n scripts.push(`${base}/min/lunr.multi.min.js`)\n\n /* Load scripts synchronously */\n if (scripts.length)\n await importScripts(\n `${base}/min/lunr.stemmer.support.min.js`,\n ...scripts\n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Message handler\n *\n * @param message - Source message\n *\n * @returns Target message\n */\nexport async function handler(\n message: SearchMessage\n): Promise {\n switch (message.type) {\n\n /* Search setup message */\n case SearchMessageType.SETUP:\n await setupSearchLanguages(message.data.config)\n index = new Search(message.data)\n return {\n type: SearchMessageType.READY\n }\n\n /* Search query message */\n case SearchMessageType.QUERY:\n return {\n type: SearchMessageType.RESULT,\n data: index ? index.search(message.data) : { items: [] }\n }\n\n /* All other messages */\n default:\n throw new TypeError(\"Invalid message type\")\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Worker\n * ------------------------------------------------------------------------- */\n\n/* @ts-expect-error - expose Lunr.js in global scope, or stemmers won't work */\nself.lunr = lunr\n\n/* Handle messages */\naddEventListener(\"message\", async ev => {\n postMessage(await handler(ev.data))\n})\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Polyfills\n * ------------------------------------------------------------------------- */\n\n/* Polyfill `Object.entries` */\nif (!Object.entries)\n Object.entries = function (obj: object) {\n const data: [string, string][] = []\n for (const key of Object.keys(obj))\n // @ts-expect-error - ignore property access warning\n data.push([key, obj[key]])\n\n /* Return entries */\n return data\n }\n\n/* Polyfill `Object.values` */\nif (!Object.values)\n Object.values = function (obj: object) {\n const data: string[] = []\n for (const key of Object.keys(obj))\n // @ts-expect-error - ignore property access warning\n data.push(obj[key])\n\n /* Return values */\n return data\n }\n\n/* ------------------------------------------------------------------------- */\n\n/* Polyfills for `Element` */\nif (typeof Element !== \"undefined\") {\n\n /* Polyfill `Element.scrollTo` */\n if (!Element.prototype.scrollTo)\n Element.prototype.scrollTo = function (\n x?: ScrollToOptions | number, y?: number\n ): void {\n if (typeof x === \"object\") {\n this.scrollLeft = x.left!\n this.scrollTop = x.top!\n } else {\n this.scrollLeft = x!\n this.scrollTop = y!\n }\n }\n\n /* Polyfill `Element.replaceWith` */\n if (!Element.prototype.replaceWith)\n Element.prototype.replaceWith = function (\n ...nodes: Array\n ): void {\n const parent = this.parentNode\n if (parent) {\n if (nodes.length === 0)\n parent.removeChild(this)\n\n /* Replace children and create text nodes */\n for (let i = nodes.length - 1; i >= 0; i--) {\n let node = nodes[i]\n if (typeof node !== \"object\")\n node = document.createTextNode(node)\n else if (node.parentNode)\n node.parentNode.removeChild(node)\n\n /* Replace child or insert before previous sibling */\n if (!i)\n parent.replaceChild(node, this)\n else\n parent.insertBefore(this.previousSibling!, node)\n }\n }\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexDocument } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search document\n */\nexport interface SearchDocument extends SearchIndexDocument {\n parent?: SearchIndexDocument /* Parent article */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search document mapping\n */\nexport type SearchDocumentMap = Map\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search document mapping\n *\n * @param docs - Search index documents\n *\n * @returns Search document map\n */\nexport function setupSearchDocumentMap(\n docs: SearchIndexDocument[]\n): SearchDocumentMap {\n const documents = new Map()\n const parents = new Set()\n for (const doc of docs) {\n const [path, hash] = doc.location.split(\"#\")\n\n /* Extract location, title and tags */\n const location = doc.location\n const title = doc.title\n const tags = doc.tags\n\n /* Escape and cleanup text */\n const text = escapeHTML(doc.text)\n .replace(/\\s+(?=[,.:;!?])/g, \"\")\n .replace(/\\s+/g, \" \")\n\n /* Handle section */\n if (hash) {\n const parent = documents.get(path)!\n\n /* Ignore first section, override article */\n if (!parents.has(parent)) {\n parent.title = doc.title\n parent.text = text\n\n /* Remember that we processed the article */\n parents.add(parent)\n\n /* Add subsequent section */\n } else {\n documents.set(location, {\n location,\n title,\n text,\n parent\n })\n }\n\n /* Add article */\n } else {\n documents.set(location, {\n location,\n title,\n text,\n ...tags && { tags }\n })\n }\n }\n return documents\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexConfig } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search highlight function\n *\n * @param value - Value\n *\n * @returns Highlighted value\n */\nexport type SearchHighlightFn = (value: string) => string\n\n/**\n * Search highlight factory function\n *\n * @param query - Query value\n *\n * @returns Search highlight function\n */\nexport type SearchHighlightFactoryFn = (query: string) => SearchHighlightFn\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search highlighter\n *\n * @param config - Search index configuration\n * @param escape - Whether to escape HTML\n *\n * @returns Search highlight factory function\n */\nexport function setupSearchHighlighter(\n config: SearchIndexConfig, escape: boolean\n): SearchHighlightFactoryFn {\n const separator = new RegExp(config.separator, \"img\")\n const highlight = (_: unknown, data: string, term: string) => {\n return `${data}${term}`\n }\n\n /* Return factory function */\n return (query: string) => {\n query = query\n .replace(/[\\s*+\\-:~^]+/g, \" \")\n .trim()\n\n /* Create search term match expression */\n const match = new RegExp(`(^|${config.separator})(${\n query\n .replace(/[|\\\\{}()[\\]^$+*?.-]/g, \"\\\\$&\")\n .replace(separator, \"|\")\n })`, \"img\")\n\n /* Highlight string value */\n return value => (\n escape\n ? escapeHTML(value)\n : value\n )\n .replace(match, highlight)\n .replace(/<\\/mark>(\\s+)]*>/img, \"$1\")\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search query clause\n */\nexport interface SearchQueryClause {\n presence: lunr.Query.presence /* Clause presence */\n term: string /* Clause term */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search query terms\n */\nexport type SearchQueryTerms = Record\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Parse a search query for analysis\n *\n * @param value - Query value\n *\n * @returns Search query clauses\n */\nexport function parseSearchQuery(\n value: string\n): SearchQueryClause[] {\n const query = new (lunr as any).Query([\"title\", \"text\"])\n const parser = new (lunr as any).QueryParser(value, query)\n\n /* Parse and return query clauses */\n parser.parse()\n return query.clauses\n}\n\n/**\n * Analyze the search query clauses in regard to the search terms found\n *\n * @param query - Search query clauses\n * @param terms - Search terms\n *\n * @returns Search query terms\n */\nexport function getSearchQueryTerms(\n query: SearchQueryClause[], terms: string[]\n): SearchQueryTerms {\n const clauses = new Set(query)\n\n /* Match query clauses against terms */\n const result: SearchQueryTerms = {}\n for (let t = 0; t < terms.length; t++)\n for (const clause of clauses)\n if (terms[t].startsWith(clause.term)) {\n result[clause.term] = true\n clauses.delete(clause)\n }\n\n /* Annotate unmatched non-stopword query clauses */\n for (const clause of clauses)\n if (lunr.stopWordFilter?.(clause.term as any))\n result[clause.term] = false\n\n /* Return query terms */\n return result\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n SearchDocument,\n SearchDocumentMap,\n setupSearchDocumentMap\n} from \"../document\"\nimport {\n SearchHighlightFactoryFn,\n setupSearchHighlighter\n} from \"../highlighter\"\nimport { SearchOptions } from \"../options\"\nimport {\n SearchQueryTerms,\n getSearchQueryTerms,\n parseSearchQuery\n} from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search index configuration\n */\nexport interface SearchIndexConfig {\n lang: string[] /* Search languages */\n separator: string /* Search separator */\n}\n\n/**\n * Search index document\n */\nexport interface SearchIndexDocument {\n location: string /* Document location */\n title: string /* Document title */\n text: string /* Document text */\n tags?: string[] /* Document tags */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search index\n *\n * This interfaces describes the format of the `search_index.json` file which\n * is automatically built by the MkDocs search plugin.\n */\nexport interface SearchIndex {\n config: SearchIndexConfig /* Search index configuration */\n docs: SearchIndexDocument[] /* Search index documents */\n options: SearchOptions /* Search options */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search metadata\n */\nexport interface SearchMetadata {\n score: number /* Score (relevance) */\n terms: SearchQueryTerms /* Search query terms */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search result document\n */\nexport type SearchResultDocument = SearchDocument & SearchMetadata\n\n/**\n * Search result item\n */\nexport type SearchResultItem = SearchResultDocument[]\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search result\n */\nexport interface SearchResult {\n items: SearchResultItem[] /* Search result items */\n suggestions?: string[] /* Search suggestions */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Compute the difference of two lists of strings\n *\n * @param a - 1st list of strings\n * @param b - 2nd list of strings\n *\n * @returns Difference\n */\nfunction difference(a: string[], b: string[]): string[] {\n const [x, y] = [new Set(a), new Set(b)]\n return [\n ...new Set([...x].filter(value => !y.has(value)))\n ]\n}\n\n/* ----------------------------------------------------------------------------\n * Class\n * ------------------------------------------------------------------------- */\n\n/**\n * Search index\n */\nexport class Search {\n\n /**\n * Search document mapping\n *\n * A mapping of URLs (including hash fragments) to the actual articles and\n * sections of the documentation. The search document mapping must be created\n * regardless of whether the index was prebuilt or not, as Lunr.js itself\n * only stores the actual index.\n */\n protected documents: SearchDocumentMap\n\n /**\n * Search highlight factory function\n */\n protected highlight: SearchHighlightFactoryFn\n\n /**\n * The underlying Lunr.js search index\n */\n protected index: lunr.Index\n\n /**\n * Search options\n */\n protected options: SearchOptions\n\n /**\n * Create the search integration\n *\n * @param data - Search index\n */\n public constructor({ config, docs, options }: SearchIndex) {\n this.options = options\n\n /* Set up document map and highlighter factory */\n this.documents = setupSearchDocumentMap(docs)\n this.highlight = setupSearchHighlighter(config, false)\n\n /* Set separator for tokenizer */\n lunr.tokenizer.separator = new RegExp(config.separator)\n\n /* Create search index */\n this.index = lunr(function () {\n\n /* Set up multi-language support */\n if (config.lang.length === 1 && config.lang[0] !== \"en\") {\n this.use((lunr as any)[config.lang[0]])\n } else if (config.lang.length > 1) {\n this.use((lunr as any).multiLanguage(...config.lang))\n }\n\n /* Compute functions to be removed from the pipeline */\n const fns = difference([\n \"trimmer\", \"stopWordFilter\", \"stemmer\"\n ], options.pipeline)\n\n /* Remove functions from the pipeline for registered languages */\n for (const lang of config.lang.map(language => (\n language === \"en\" ? lunr : (lunr as any)[language]\n ))) {\n for (const fn of fns) {\n this.pipeline.remove(lang[fn])\n this.searchPipeline.remove(lang[fn])\n }\n }\n\n /* Set up reference */\n this.ref(\"location\")\n\n /* Set up fields */\n this.field(\"title\", { boost: 1e3 })\n this.field(\"text\")\n this.field(\"tags\", { boost: 1e6 })\n\n /* Index documents */\n for (const doc of docs)\n this.add(doc)\n })\n }\n\n /**\n * Search for matching documents\n *\n * The search index which MkDocs provides is divided up into articles, which\n * contain the whole content of the individual pages, and sections, which only\n * contain the contents of the subsections obtained by breaking the individual\n * pages up at `h1` ... `h6`. As there may be many sections on different pages\n * with identical titles (for example within this very project, e.g. \"Usage\"\n * or \"Installation\"), they need to be put into the context of the containing\n * page. For this reason, section results are grouped within their respective\n * articles which are the top-level results that are returned.\n *\n * @param query - Query value\n *\n * @returns Search results\n */\n public search(query: string): SearchResult {\n if (query) {\n try {\n const highlight = this.highlight(query)\n\n /* Parse query to extract clauses for analysis */\n const clauses = parseSearchQuery(query)\n .filter(clause => (\n clause.presence !== lunr.Query.presence.PROHIBITED\n ))\n\n /* Perform search and post-process results */\n const groups = this.index.search(`${query}*`)\n\n /* Apply post-query boosts based on title and search query terms */\n .reduce((item, { ref, score, matchData }) => {\n const document = this.documents.get(ref)\n if (typeof document !== \"undefined\") {\n const { location, title, text, tags, parent } = document\n\n /* Compute and analyze search query terms */\n const terms = getSearchQueryTerms(\n clauses,\n Object.keys(matchData.metadata)\n )\n\n /* Highlight title and text and apply post-query boosts */\n const boost = +!parent + +Object.values(terms).every(t => t)\n item.push({\n location,\n title: highlight(title),\n text: highlight(text),\n ...tags && { tags: tags.map(highlight) },\n score: score * (1 + boost),\n terms\n })\n }\n return item\n }, [])\n\n /* Sort search results again after applying boosts */\n .sort((a, b) => b.score - a.score)\n\n /* Group search results by page */\n .reduce((items, result) => {\n const document = this.documents.get(result.location)\n if (typeof document !== \"undefined\") {\n const ref = \"parent\" in document\n ? document.parent!.location\n : document.location\n items.set(ref, [...items.get(ref) || [], result])\n }\n return items\n }, new Map())\n\n /* Generate search suggestions, if desired */\n let suggestions: string[] | undefined\n if (this.options.suggestions) {\n const titles = this.index.query(builder => {\n for (const clause of clauses)\n builder.term(clause.term, {\n fields: [\"title\"],\n presence: lunr.Query.presence.REQUIRED,\n wildcard: lunr.Query.wildcard.TRAILING\n })\n })\n\n /* Retrieve suggestions for best match */\n suggestions = titles.length\n ? Object.keys(titles[0].matchData.metadata)\n : []\n }\n\n /* Return items and suggestions */\n return {\n items: [...groups.values()],\n ...typeof suggestions !== \"undefined\" && { suggestions }\n }\n\n /* Log errors to console (for now) */\n } catch {\n console.warn(`Invalid query: ${query} \u2013 see https://bit.ly/2s3ChXG`)\n }\n }\n\n /* Return nothing in case of error or empty query */\n return { items: [] }\n }\n}\n"], + "mappings": "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", + "names": [] +} diff --git a/site/assets/stylesheets/main.e8d9bf0c.min.css b/site/assets/stylesheets/main.e8d9bf0c.min.css new file mode 100644 index 0000000000..cfef2a07d5 --- /dev/null +++ b/site/assets/stylesheets/main.e8d9bf0c.min.css @@ -0,0 +1 @@ +@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:content-box;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:separate;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:transparent;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root{--md-default-fg-color:rgba(0,0,0,.87);--md-default-fg-color--light:rgba(0,0,0,.54);--md-default-fg-color--lighter:rgba(0,0,0,.32);--md-default-fg-color--lightest:rgba(0,0,0,.07);--md-default-bg-color:#fff;--md-default-bg-color--light:hsla(0,0%,100%,.7);--md-default-bg-color--lighter:hsla(0,0%,100%,.3);--md-default-bg-color--lightest:hsla(0,0%,100%,.12);--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7);--md-shadow-z1:0 0.2rem 0.5rem rgba(0,0,0,.05),0 0 0.05rem rgba(0,0,0,.1);--md-shadow-z2:0 0.2rem 0.5rem rgba(0,0,0,.1),0 0 0.05rem rgba(0,0,0,.25);--md-shadow-z3:0 0.2rem 0.5rem rgba(0,0,0,.2),0 0 0.05rem rgba(0,0,0,.35)}:root>*{--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-hl-color:rgba(255,255,0,.5);--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-mark-color:rgba(255,255,0,.5);--md-typeset-del-color:rgba(245,80,61,.15);--md-typeset-ins-color:rgba(11,213,112,.15);--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-table-color:rgba(0,0,0,.12);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-footer-fg-color:#fff;--md-footer-fg-color--light:hsla(0,0%,100%,.7);--md-footer-fg-color--lighter:hsla(0,0%,100%,.3);--md-footer-bg-color:rgba(0,0,0,.87);--md-footer-bg-color--dark:rgba(0,0,0,.32)}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}body,input{font-feature-settings:"kern","liga";font-family:var(--md-text-font-family)}body,code,input,kbd,pre{color:var(--md-typeset-color)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.8rem;line-height:1.6}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color--light);font-size:2em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{font-size:1.5625em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:400;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.1rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:0 .2941176471em;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset a code{color:currentcolor}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset kbd{background-color:var(--md-typeset-kbd-color);border-radius:.1rem;box-shadow:0 .1rem 0 .05rem var(--md-typeset-kbd-border-color),0 .1rem 0 var(--md-typeset-kbd-border-color),0 -.1rem .2rem var(--md-typeset-kbd-accent-color) inset;color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light);cursor:help;text-decoration:none}@media (hover:none){.md-typeset abbr{position:relative}.md-typeset abbr[title]:-webkit-any(:focus,:hover):after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z3);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;margin-top:2em;max-width:80%;min-width:-webkit-max-content;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}.md-typeset abbr[title]:-moz-any(:focus,:hover):after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z3);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;margin-top:2em;max-width:80%;min-width:-moz-max-content;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}[dir=ltr] .md-typeset abbr[title]:-webkit-any(:focus,:hover):after{left:0}[dir=ltr] .md-typeset abbr[title]:-moz-any(:focus,:hover):after{left:0}[dir=ltr] .md-typeset abbr[title]:is(:focus,:hover):after{left:0}[dir=rtl] .md-typeset abbr[title]:-webkit-any(:focus,:hover):after{right:0}[dir=rtl] .md-typeset abbr[title]:-moz-any(:focus,:hover):after{right:0}[dir=rtl] .md-typeset abbr[title]:is(:focus,:hover):after{right:0}.md-typeset abbr[title]:is(:focus,:hover):after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z3);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;margin-top:2em;max-width:80%;min-width:-webkit-max-content;min-width:-moz-max-content;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li :-webkit-any(p,blockquote),.md-typeset ul li :-webkit-any(p,blockquote){margin:.5em 0}.md-typeset ol li :-moz-any(p,blockquote),.md-typeset ul li :-moz-any(p,blockquote){margin:.5em 0}.md-typeset ol li :is(p,blockquote),.md-typeset ul li :is(p,blockquote){margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}.md-typeset ol li :-webkit-any(ul,ol),.md-typeset ul li :-webkit-any(ul,ol){margin-bottom:.5em;margin-top:.5em}.md-typeset ol li :-moz-any(ul,ol),.md-typeset ul li :-moz-any(ul,ol){margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset ol li :-webkit-any(ul,ol),[dir=ltr] .md-typeset ul li :-webkit-any(ul,ol){margin-left:.625em}[dir=ltr] .md-typeset ol li :-moz-any(ul,ol),[dir=ltr] .md-typeset ul li :-moz-any(ul,ol){margin-left:.625em}[dir=ltr] .md-typeset ol li :is(ul,ol),[dir=ltr] .md-typeset ul li :is(ul,ol){margin-left:.625em}[dir=rtl] .md-typeset ol li :-webkit-any(ul,ol),[dir=rtl] .md-typeset ul li :-webkit-any(ul,ol){margin-right:.625em}[dir=rtl] .md-typeset ol li :-moz-any(ul,ol),[dir=rtl] .md-typeset ul li :-moz-any(ul,ol){margin-right:.625em}[dir=rtl] .md-typeset ol li :is(ul,ol),[dir=rtl] .md-typeset ul li :is(ul,ol){margin-right:.625em}.md-typeset ol li :is(ul,ol),.md-typeset ul li :is(ul,ol){margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg{height:auto;max-width:100%}.md-typeset img[align=left],.md-typeset svg[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right],.md-typeset svg[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child,.md-typeset svg[align]:only-child{margin-top:0}.md-typeset img[src$="#only-dark"]{display:none}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.md-typeset figure img{display:block}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table:not([class]){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:inline-block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto}@media print{.md-typeset table:not([class]){display:table}}.md-typeset table:not([class])+*{margin-top:1.5em}.md-typeset table:not([class]) :-webkit-any(th,td)>:first-child{margin-top:0}.md-typeset table:not([class]) :-moz-any(th,td)>:first-child{margin-top:0}.md-typeset table:not([class]) :is(th,td)>:first-child{margin-top:0}.md-typeset table:not([class]) :-webkit-any(th,td)>:last-child{margin-bottom:0}.md-typeset table:not([class]) :-moz-any(th,td)>:last-child{margin-bottom:0}.md-typeset table:not([class]) :is(th,td)>:last-child{margin-bottom:0}.md-typeset table:not([class]) :-webkit-any(th,td):not([align]){text-align:left}.md-typeset table:not([class]) :-moz-any(th,td):not([align]){text-align:left}.md-typeset table:not([class]) :is(th,td):not([align]){text-align:left}[dir=rtl] .md-typeset table:not([class]) :-webkit-any(th,td):not([align]){text-align:right}[dir=rtl] .md-typeset table:not([class]) :-moz-any(th,td):not([align]){text-align:right}[dir=rtl] .md-typeset table:not([class]) :is(th,td):not([align]){text-align:right}.md-typeset table:not([class]) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) th a{color:inherit}.md-typeset table:not([class]) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) tbody tr{transition:background-color 125ms}.md-typeset table:not([class]) tbody tr:hover{background-color:rgba(0,0,0,.035);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table:not([class]) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.9375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-banner{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background:var(--md-typeset-mark-color);color:var(--md-default-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}html{font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.9375em){body[data-md-state=lock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;position:absolute;right:.5em;top:.5em;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-clipboard:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-clipboard:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:-webkit-any(:focus,:hover) code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-clipboard--inline:-moz-any(:focus,:hover) code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-clipboard--inline:is(:focus,:hover) code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{float:right;margin:.4rem 0;padding:0}@media print{.md-content__button{display:none}}[dir=rtl] .md-content__button{float:left}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog[data-md-state=open]{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{display:flex;justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__link{display:flex;flex-grow:0.01;outline-color:var(--md-accent-fg-color);overflow:hidden;padding-bottom:.4rem;padding-top:1.4rem;transition:opacity .25s}.md-footer__link:-webkit-any(:focus,:hover){opacity:.7}.md-footer__link:-moz-any(:focus,:hover){opacity:.7}.md-footer__link:is(:focus,:hover){opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.9375em){.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.9rem;line-height:2.4rem;max-width:calc(100% - 2.4rem);padding:0 1rem;position:relative}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;left:0;margin-top:-1rem;opacity:.7;padding:0 1rem;position:absolute;right:0}.md-footer-meta{background-color:var(--md-footer-bg-color--dark)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a{color:var(--md-footer-fg-color--light)}html .md-footer-meta.md-typeset a:-webkit-any(:focus,:hover){color:var(--md-footer-fg-color)}html .md-footer-meta.md-typeset a:-moz-any(:focus,:hover){color:var(--md-footer-fg-color)}html .md-footer-meta.md-typeset a:is(:focus,:hover){color:var(--md-footer-fg-color)}.md-copyright{color:var(--md-footer-fg-color--lighter);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-social{margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-typeset .md-button{border:.1rem solid;border-radius:.1rem;color:var(--md-primary-fg-color);cursor:pointer;display:inline-block;font-weight:700;padding:.625em 2em;transition:color 125ms,background-color 125ms,border-color 125ms}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);border-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-typeset .md-button:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-typeset .md-button:is(:focus,:hover){background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=ltr] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:-webkit-any(:focus,:hover){border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input:-moz-any(:focus,:hover){border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input:is(:focus,:hover){border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem transparent,0 .2rem .4rem transparent;color:var(--md-primary-bg-color);left:0;position:-webkit-sticky;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[data-md-state=shadow]{box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2);transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header[data-md-state=hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1),box-shadow .25s}.md-header__inner{align-items:center;display:flex;padding:0 .2rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.1875em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo :-webkit-any(img,svg){fill:currentcolor;display:block;height:1.2rem;width:auto}.md-header__button.md-logo :-moz-any(img,svg){fill:currentcolor;display:block;height:1.2rem;width:auto}.md-header__button.md-logo :is(img,svg){fill:currentcolor;display:block;height:1.2rem;width:auto}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}[dir=ltr] .md-header__title{margin-right:.4rem}[dir=rtl] .md-header__title{margin-left:.4rem}[dir=ltr] .md-header__title{margin-left:1rem}[dir=rtl] .md-header__title{margin-right:1rem}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem}.md-header__title[data-md-state=active] .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title[data-md-state=active] .md-header__topic{transform:translateX(1.25rem)}.md-header__title[data-md-state=active] .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;transition:max-width 0ms .25s,opacity .25s .25s;white-space:nowrap}[data-md-toggle=search]:checked~.md-header .md-header__option{max-width:0;opacity:0;transition:max-width 0ms,opacity 0ms}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.7rem;width:11.7rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}:root{--md-nav-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,');--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3}.md-nav__title{display:block;font-weight:700;overflow:hidden;padding:0 .6rem;text-overflow:ellipsis}.md-nav__title .md-nav__button{display:none}.md-nav__title .md-nav__button img{height:100%;width:auto}.md-nav__title .md-nav__button.md-logo :-webkit-any(img,svg){fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__title .md-nav__button.md-logo :-moz-any(img,svg){fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__title .md-nav__button.md-logo :is(img,svg){fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__item{padding:0 .6rem}[dir=ltr] .md-nav__item .md-nav__item{padding-right:0}[dir=rtl] .md-nav__item .md-nav__item{padding-left:0}.md-nav__link{align-items:center;cursor:pointer;display:flex;justify-content:space-between;margin-top:.625em;overflow:hidden;scroll-snap-align:start;text-overflow:ellipsis;transition:color 125ms}.md-nav__link[data-md-state=blur]{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active{color:var(--md-typeset-a-color)}.md-nav__item .md-nav__link--index [href]{width:100%}.md-nav__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-nav--primary .md-nav__link[for=__toc]{display:none}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{background-color:currentcolor;display:block;height:100%;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);width:100%}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__link>*{cursor:pointer;display:flex}.md-nav__icon{flex-shrink:0}.md-nav__source{display:none}@media screen and (max-width:76.1875em){.md-nav--primary,.md-nav--primary .md-nav{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;height:100%;left:0;position:absolute;right:0;top:0;z-index:1}.md-nav--primary :-webkit-any(.md-nav__title,.md-nav__item){font-size:.8rem;line-height:1.5}.md-nav--primary :-moz-any(.md-nav__title,.md-nav__item){font-size:.8rem;line-height:1.5}.md-nav--primary :is(.md-nav__title,.md-nav__item){font-size:.8rem;line-height:1.5}.md-nav--primary .md-nav__title{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);cursor:pointer;font-weight:400;height:5.6rem;line-height:2.4rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}[dir=ltr] .md-nav--primary .md-nav__title .md-nav__icon{left:.4rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{right:.4rem}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}.md-nav--primary .md-nav__title .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--prev);mask-image:var(--md-nav-icon--prev);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}.md-nav--primary .md-nav__title~.md-nav__list{background-color:var(--md-default-bg-color);box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest) inset;overflow-y:auto;-ms-scroll-snap-type:y mandatory;scroll-snap-type:y mandatory;touch-action:pan-y}.md-nav--primary .md-nav__title~.md-nav__list>:first-child{border-top:0}.md-nav--primary .md-nav__title[for=__drawer]{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-weight:700}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;right:.2rem;top:.2rem}.md-nav--primary .md-nav__list{flex:1}.md-nav--primary .md-nav__item{border-top:.05rem solid var(--md-default-fg-color--lightest);padding:0}.md-nav--primary .md-nav__item--active>.md-nav__link{color:var(--md-typeset-a-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link{margin-top:0;padding:.6rem .8rem}[dir=ltr] .md-nav--primary .md-nav__link .md-nav__icon{margin-right:-.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{margin-left:-.2rem}.md-nav--primary .md-nav__link .md-nav__icon{font-size:1.2rem;height:1.2rem;width:1.2rem}.md-nav--primary .md-nav__link .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-nav--primary .md-nav__icon:after{transform:scale(-1)}.md-nav--primary .md-nav--secondary .md-nav{background-color:transparent;position:static}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:1.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-right:1.4rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-right:2rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:2.6rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-right:2.6rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:3.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-right:3.2rem}.md-nav--secondary{background-color:transparent}.md-nav__toggle~.md-nav{display:flex;opacity:0;transform:translateX(100%);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity 125ms 50ms}[dir=rtl] .md-nav__toggle~.md-nav{transform:translateX(-100%)}.md-nav__toggle:checked~.md-nav{opacity:1;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 125ms 125ms}.md-nav__toggle:checked~.md-nav>.md-nav__list{-webkit-backface-visibility:hidden;backface-visibility:hidden}}@media screen and (max-width:59.9375em){.md-nav--primary .md-nav__link[for=__toc]{display:flex}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--primary .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:flex}.md-nav__source{background-color:var(--md-primary-fg-color--dark);color:var(--md-primary-bg-color);display:block;padding:0 .2rem}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-nav--integrated .md-nav__link[for=__toc]{display:flex}.md-nav--integrated .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--integrated .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{display:flex}}@media screen and (min-width:60em){.md-nav--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}}@media screen and (min-width:76.25em){.md-nav{transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon{display:none}.md-nav__toggle~.md-nav{display:none}.md-nav__toggle:-webkit-any(:checked,:indeterminate)~.md-nav{display:block}.md-nav__toggle:-moz-any(:checked,:indeterminate)~.md-nav{display:block}.md-nav__toggle:is(:checked,:indeterminate)~.md-nav{display:block}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--section{display:block;margin:1.25em 0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700;pointer-events:none}.md-nav__item--section>.md-nav__link--index [href]{pointer-events:auto}.md-nav__item--section>.md-nav__link .md-nav__icon{display:none}.md-nav__item--section>.md-nav{display:block}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{border-radius:100%;float:right;height:.9rem;transition:background-color .25s,transform .25s;width:.9rem}[dir=rtl] .md-nav__icon{float:left;transform:rotate(180deg)}.md-nav__icon:hover{background-color:var(--md-accent-fg-color--transparent)}.md-nav__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:-.1rem;width:100%}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon,.md-nav__item--nested .md-nav__toggle:indeterminate~.md-nav__link .md-nav__icon{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item--nested,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block;padding:0}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{font-weight:700;margin-top:0;padding:0 .6rem;pointer-events:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link--index [href]{pointer-events:auto}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link .md-nav__icon{display:none}.md-nav--lifted .md-nav[data-md-level="1"]{display:block}[dir=ltr] .md-nav--lifted .md-nav[data-md-level="1"]>.md-nav__list>.md-nav__item{padding-right:.6rem}[dir=rtl] .md-nav--lifted .md-nav[data-md-level="1"]>.md-nav__list>.md-nav__item{padding-left:.6rem}.md-nav--integrated>.md-nav__list>.md-nav__item--active:not(.md-nav__item--nested){padding:0 .6rem}.md-nav--integrated>.md-nav__list>.md-nav__item--active:not(.md-nav__item--nested)>.md-nav__link{padding:0}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-primary-fg-color)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-primary-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:1.25em}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}}:root{--md-search-result-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:60em){.md-search{padding:.2rem 0}}.no-js .md-search{display:none}.md-search__overlay{opacity:0;z-index:1}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__overlay{left:-2.2rem}[dir=rtl] .md-search__overlay{right:-2.2rem}.md-search__overlay{background-color:var(--md-default-bg-color);border-radius:1rem;height:2rem;overflow:hidden;pointer-events:none;position:absolute;top:-1rem;transform-origin:center;transition:transform .3s .1s,opacity .2s .2s;width:2rem}[data-md-toggle=search]:checked~.md-header .md-search__overlay{opacity:1;transition:transform .4s,opacity .1s}}@media screen and (min-width:60em){[dir=ltr] .md-search__overlay{left:0}[dir=rtl] .md-search__overlay{right:0}.md-search__overlay{background-color:rgba(0,0,0,.54);cursor:pointer;height:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0}[data-md-toggle=search]:checked~.md-header .md-search__overlay{height:200vh;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@media screen and (max-width:29.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(45)}}@media screen and (min-width:30em) and (max-width:44.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(60)}}@media screen and (min-width:45em) and (max-width:59.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(75)}}.md-search__inner{-webkit-backface-visibility:hidden;backface-visibility:hidden}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__inner{left:0}[dir=rtl] .md-search__inner{right:0}.md-search__inner{height:0;opacity:0;overflow:hidden;position:fixed;top:0;transform:translateX(5%);transition:width 0ms .3s,height 0ms .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;width:0;z-index:2}[dir=rtl] .md-search__inner{transform:translateX(-5%)}[data-md-toggle=search]:checked~.md-header .md-search__inner{height:100%;opacity:1;transform:translateX(0);transition:width 0ms 0ms,height 0ms 0ms,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;width:100%}}@media screen and (min-width:60em){.md-search__inner{float:right;padding:.1rem 0;position:relative;transition:width .25s cubic-bezier(.1,.7,.1,1);width:11.7rem}[dir=rtl] .md-search__inner{float:left}}@media screen and (min-width:60em) and (max-width:76.1875em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:23.4rem}}@media screen and (min-width:76.25em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:34.4rem}}.md-search__form{background-color:var(--md-default-bg-color);box-shadow:0 0 .6rem transparent;height:2.4rem;position:relative;transition:color .25s,background-color .25s;z-index:2}@media screen and (min-width:60em){.md-search__form{background-color:rgba(0,0,0,.26);border-radius:.1rem;height:1.8rem}.md-search__form:hover{background-color:hsla(0,0%,100%,.12)}}[data-md-toggle=search]:checked~.md-header .md-search__form{background-color:var(--md-default-bg-color);border-radius:.1rem .1rem 0 0;box-shadow:0 0 .6rem rgba(0,0,0,.07);color:var(--md-default-fg-color)}[dir=ltr] .md-search__input{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__input{padding-left:2.2rem;padding-right:3.6rem}.md-search__input{background:transparent;font-size:.9rem;height:100%;position:relative;text-overflow:ellipsis;width:100%;z-index:2}.md-search__input::-moz-placeholder{-moz-transition:color .25s;transition:color .25s}.md-search__input::-ms-input-placeholder{-ms-transition:color .25s;transition:color .25s}.md-search__input::placeholder{transition:color .25s}.md-search__input::-moz-placeholder{color:var(--md-default-fg-color--light)}.md-search__input::-ms-input-placeholder{color:var(--md-default-fg-color--light)}.md-search__input::placeholder,.md-search__input~.md-search__icon{color:var(--md-default-fg-color--light)}.md-search__input::-ms-clear{display:none}@media screen and (max-width:59.9375em){.md-search__input{font-size:.9rem;height:2.4rem;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__input{padding-left:2.2rem}[dir=rtl] .md-search__input{padding-right:2.2rem}.md-search__input{color:inherit;font-size:.8rem}.md-search__input::-moz-placeholder{color:var(--md-primary-bg-color--light)}.md-search__input::-ms-input-placeholder{color:var(--md-primary-bg-color--light)}.md-search__input::placeholder{color:var(--md-primary-bg-color--light)}.md-search__input+.md-search__icon{color:var(--md-primary-bg-color)}[data-md-toggle=search]:checked~.md-header .md-search__input{text-overflow:clip}[data-md-toggle=search]:checked~.md-header .md-search__input::-moz-placeholder{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input::-ms-input-placeholder{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:var(--md-default-fg-color--light)}}.md-search__icon{cursor:pointer;display:inline-block;height:1.2rem;transition:color .25s,opacity .25s;width:1.2rem}.md-search__icon:hover{opacity:.7}[dir=ltr] .md-search__icon[for=__search]{left:.5rem}[dir=rtl] .md-search__icon[for=__search]{right:.5rem}.md-search__icon[for=__search]{position:absolute;top:.3rem;z-index:2}[dir=rtl] .md-search__icon[for=__search] svg{transform:scaleX(-1)}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__icon[for=__search]{left:.8rem}[dir=rtl] .md-search__icon[for=__search]{right:.8rem}.md-search__icon[for=__search]{top:.6rem}.md-search__icon[for=__search] svg:first-child{display:none}}@media screen and (min-width:60em){.md-search__icon[for=__search]{pointer-events:none}.md-search__icon[for=__search] svg:last-child{display:none}}[dir=ltr] .md-search__options{right:.5rem}[dir=rtl] .md-search__options{left:.5rem}.md-search__options{pointer-events:none;position:absolute;top:.3rem;z-index:2}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__options{right:.8rem}[dir=rtl] .md-search__options{left:.8rem}.md-search__options{top:.6rem}}[dir=ltr] .md-search__options>*{margin-left:.2rem}[dir=rtl] .md-search__options>*{margin-right:.2rem}.md-search__options>*{color:var(--md-default-fg-color--light);opacity:0;transform:scale(.75);transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-search__options>:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>*{opacity:1;pointer-events:auto;transform:scale(1)}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>:hover{opacity:.7}[dir=ltr] .md-search__suggest{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__suggest{padding-left:2.2rem;padding-right:3.6rem}.md-search__suggest{align-items:center;color:var(--md-default-fg-color--lighter);display:flex;font-size:.9rem;height:100%;opacity:0;position:absolute;top:0;transition:opacity 50ms;white-space:nowrap;width:100%}@media screen and (min-width:60em){[dir=ltr] .md-search__suggest{padding-left:2.2rem}[dir=rtl] .md-search__suggest{padding-right:2.2rem}.md-search__suggest{font-size:.8rem}}[data-md-toggle=search]:checked~.md-header .md-search__suggest{opacity:1;transition:opacity .3s .1s}[dir=ltr] .md-search__output{border-bottom-left-radius:.1rem}[dir=rtl] .md-search__output{border-bottom-right-radius:.1rem}[dir=ltr] .md-search__output{border-bottom-right-radius:.1rem}[dir=rtl] .md-search__output{border-bottom-left-radius:.1rem}.md-search__output{overflow:hidden;position:absolute;width:100%;z-index:1}@media screen and (max-width:59.9375em){.md-search__output{bottom:0;top:2.4rem}}@media screen and (min-width:60em){.md-search__output{opacity:0;top:1.9rem;transition:opacity .4s}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:var(--md-shadow-z3);opacity:1}}.md-search__scrollwrap{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);height:100%;overflow-y:auto;touch-action:pan-y}@media (-webkit-max-device-pixel-ratio:1),(max-resolution:1dppx){.md-search__scrollwrap{transform:translateZ(0)}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-search__scrollwrap{width:23.4rem}}@media screen and (min-width:76.25em){.md-search__scrollwrap{width:34.4rem}}@media screen and (min-width:60em){.md-search__scrollwrap{max-height:0;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-search__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}}.md-search-result{color:var(--md-default-fg-color);word-break:break-word}.md-search-result__meta{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.8rem;padding:0 .8rem;scroll-snap-align:start}@media screen and (min-width:60em){[dir=ltr] .md-search-result__meta{padding-left:2.2rem}[dir=rtl] .md-search-result__meta{padding-right:2.2rem}}.md-search-result__list{list-style:none;margin:0;padding:0}.md-search-result__item{box-shadow:0 -.05rem var(--md-default-fg-color--lightest)}.md-search-result__item:first-child{box-shadow:none}.md-search-result__link{display:block;outline:none;scroll-snap-align:start;transition:background-color .25s}.md-search-result__link:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:is(:focus,:hover){background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:last-child p:last-child{margin-bottom:.6rem}.md-search-result__more summary{color:var(--md-typeset-a-color);cursor:pointer;display:block;font-size:.64rem;outline:none;padding:.75em .8rem;scroll-snap-align:start;transition:color .25s,background-color .25s}@media screen and (min-width:60em){[dir=ltr] .md-search-result__more summary{padding-left:2.2rem}[dir=rtl] .md-search-result__more summary{padding-right:2.2rem}}.md-search-result__more summary:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary:is(:focus,:hover){background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary::marker{display:none}.md-search-result__more summary::-webkit-details-marker{display:none}.md-search-result__more summary~*>*{opacity:.65}.md-search-result__article{overflow:hidden;padding:0 .8rem;position:relative}@media screen and (min-width:60em){[dir=ltr] .md-search-result__article{padding-left:2.2rem}[dir=rtl] .md-search-result__article{padding-right:2.2rem}}.md-search-result__article--document .md-search-result__title{font-size:.8rem;font-weight:400;line-height:1.4;margin:.55rem 0}[dir=ltr] .md-search-result__icon{left:0}[dir=rtl] .md-search-result__icon{right:0}.md-search-result__icon{color:var(--md-default-fg-color--light);height:1.2rem;margin:.5rem;position:absolute;width:1.2rem}@media screen and (max-width:59.9375em){.md-search-result__icon{display:none}}.md-search-result__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-search-result-icon);mask-image:var(--md-search-result-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-search-result__icon:after{transform:scaleX(-1)}.md-search-result__title{font-size:.64rem;font-weight:700;line-height:1.6;margin:.5em 0}.md-search-result__teaser{-webkit-box-orient:vertical;-webkit-line-clamp:2;color:var(--md-default-fg-color--light);display:-webkit-box;font-size:.64rem;line-height:1.6;margin:.5em 0;max-height:2rem;overflow:hidden;text-overflow:ellipsis}@media screen and (max-width:44.9375em){.md-search-result__teaser{-webkit-line-clamp:3;max-height:3rem}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-search-result__teaser{-webkit-line-clamp:3;max-height:3rem}}.md-search-result__teaser mark{background-color:transparent;text-decoration:underline}.md-search-result__terms{font-size:.64rem;font-style:italic;margin:.5em 0}.md-search-result mark{background-color:transparent;color:var(--md-accent-fg-color)}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}.md-select:-webkit-any(:focus-within,:hover) .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);-webkit-transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms;transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select:-moz-any(:focus-within,:hover) .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);-moz-transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms;transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select:is(:focus-within,:hover) .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select__inner:after{border-bottom:.2rem solid transparent;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid transparent;border-right:.2rem solid transparent;border-top:0;content:"";height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-select__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-select__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.2rem 0;position:-webkit-sticky;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.1875em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.1rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.1rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overflow:hidden;position:absolute;right:0;-ms-scroll-snap-type:none;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}}.md-sidebar--secondary{display:none;order:2}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{-webkit-backface-visibility:hidden;backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@media screen and (max-width:76.1875em){.md-overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@-webkit-keyframes facts{0%{height:0}to{height:.65rem}}@keyframes facts{0%{height:0}to{height:.65rem}}@-webkit-keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.65rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{font-size:.55rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0}[data-md-state=done] .md-source__facts{-webkit-animation:facts .25s ease-in;animation:facts .25s ease-in}.md-source__fact{display:inline-block}[data-md-state=done] .md-source__fact{-webkit-animation:fact .4s ease-out;animation:fact .4s ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}[dir=ltr] .md-source__fact:nth-child(1n+2):before{margin-left:.4rem}[dir=rtl] .md-source__fact:nth-child(1n+2):before{margin-right:.4rem}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);overflow:auto;width:100%}@media print{.md-tabs{display:none}}@media screen and (max-width:76.1875em){.md-tabs{display:none}}.md-tabs[data-md-state=hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.2rem}[dir=rtl] .md-tabs__list{margin-right:.2rem}.md-tabs__list{contain:content;list-style:none;margin:0;padding:0;white-space:nowrap}.md-tabs__item{display:inline-block;height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__link{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link--active,.md-tabs__link:-webkit-any(:focus,:hover){color:inherit;opacity:1}.md-tabs__link--active,.md-tabs__link:-moz-any(:focus,:hover){color:inherit;opacity:1}.md-tabs__link--active,.md-tabs__link:is(:focus,:hover){color:inherit;opacity:1}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[data-md-state=hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}.md-tags{margin-bottom:.75em}[dir=ltr] .md-tag{margin-right:.5em}[dir=rtl] .md-tag{margin-left:.5em}.md-tag{background:var(--md-default-fg-color--lightest);border-radius:.4rem;display:inline-block;font-size:.64rem;font-weight:700;line-height:1.6;margin-bottom:.5em;padding:.3125em .9375em}.md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-tag[href]:focus,.md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-tag{vertical-align:text-top}@-webkit-keyframes pulse{0%{box-shadow:0 0 0 0 var(--md-default-fg-color--lightest)}75%{box-shadow:0 0 0 .625em transparent}to{box-shadow:0 0 0 0 transparent}}@keyframes pulse{0%{box-shadow:0 0 0 0 var(--md-default-fg-color--lightest)}75%{box-shadow:0 0 0 .625em transparent}to{box-shadow:0 0 0 0 transparent}}:root{--md-tooltip-width:20rem}.md-tooltip{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x),(100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem));max-height:0;max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:var(--md-tooltip-y);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,max-height 0ms .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}:focus-within>.md-tooltip{max-height:1000%;opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height .25s,z-index 0ms}.focus-visible>.md-tooltip{outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{outline:none;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}.md-annotation:not([hidden]){display:inline-block;line-height:1.325}.md-annotation:focus-within>*{z-index:2}.md-annotation__inner{font-family:var(--md-text-font-family);top:calc(var(--md-tooltip-y) + 1.2ch)}:not(:focus-within)>.md-annotation__inner{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.md-annotation__index{color:#fff;cursor:pointer;margin:0 1ch;position:relative;transition:z-index .25s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:0}.md-annotation__index:after{-webkit-animation:pulse 2s infinite;animation:pulse 2s infinite;background-color:var(--md-default-fg-color--lighter);border-radius:2ch;content:"";height:2.2ch;left:-.126em;margin:0 -.4ch;padding:0 .4ch;position:absolute;top:.025em;transition:color .25s,background-color .25s;width:calc(100% + 1.2ch);width:max(2.2ch,100% + 1.2ch);z-index:-1}@media (prefers-reduced-motion){.md-annotation__index:after{-webkit-animation:none;animation:none}}:-webkit-any(:focus-within,:hover)>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}:-moz-any(:focus-within,:hover)>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}:is(:focus-within,:hover)>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}:focus-within>.md-annotation__index:after{-webkit-animation:none;animation:none;transition:color .25s,background-color .25s}.md-annotation__index [data-md-annotation-id]:before{content:attr(data-md-annotation-id);display:inline-block;transition:transform .4s cubic-bezier(.1,.7,.1,1)}@media not print{.md-annotation__index [data-md-annotation-id]:before{content:"+"}:focus-within>.md-annotation__index [data-md-annotation-id]:before{transform:rotate(45deg)}}:-webkit-any(:focus-within,:hover)>.md-annotation__index{color:var(--md-accent-bg-color)}:-moz-any(:focus-within,:hover)>.md-annotation__index{color:var(--md-accent-bg-color)}:is(:focus-within,:hover)>.md-annotation__index{color:var(--md-accent-bg-color)}:focus-within>.md-annotation__index{-webkit-animation:none;animation:none;transition:none}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);font-size:.7rem;outline:none;padding:.4rem .8rem;position:fixed;top:3.2rem;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[data-md-state=hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[data-md-state=hidden]{transform:translate(50%,.2rem)}.md-top:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top:is(:focus,:hover){background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;vertical-align:-.5em}@-webkit-keyframes hoverfix{0%{pointer-events:none}}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;width:.4rem}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;-ms-scroll-snap-type:y mandatory;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:-webkit-any(:focus-within,:hover) .md-version__list{max-height:10rem;opacity:1;-webkit-transition:max-height 0ms,opacity .25s;transition:max-height 0ms,opacity .25s}.md-version:-moz-any(:focus-within,:hover) .md-version__list{max-height:10rem;opacity:1;-moz-transition:max-height 0ms,opacity .25s;transition:max-height 0ms,opacity .25s}.md-version:is(:focus-within,:hover) .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (pointer:coarse){.md-version:hover .md-version__list{-webkit-animation:hoverfix .25s forwards;animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{-webkit-animation:none;animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-version__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-version__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset :-webkit-any(.admonition,details){background-color:var(--md-admonition-bg-color);border:0 solid #448aff;border-radius:.1rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid}.md-typeset :-moz-any(.admonition,details){background-color:var(--md-admonition-bg-color);border:0 solid #448aff;border-radius:.1rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid}[dir=ltr] .md-typeset :-webkit-any(.admonition,details){border-left-width:.2rem}[dir=ltr] .md-typeset :-moz-any(.admonition,details){border-left-width:.2rem}[dir=ltr] .md-typeset :is(.admonition,details){border-left-width:.2rem}[dir=rtl] .md-typeset :-webkit-any(.admonition,details){border-right-width:.2rem}[dir=rtl] .md-typeset :-moz-any(.admonition,details){border-right-width:.2rem}[dir=rtl] .md-typeset :is(.admonition,details){border-right-width:.2rem}.md-typeset :is(.admonition,details){background-color:var(--md-admonition-bg-color);border:0 solid #448aff;border-radius:.1rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid}@media print{.md-typeset :-webkit-any(.admonition,details){box-shadow:none}.md-typeset :-moz-any(.admonition,details){box-shadow:none}.md-typeset :is(.admonition,details){box-shadow:none}}.md-typeset :-webkit-any(.admonition,details)>*{box-sizing:border-box}.md-typeset :-moz-any(.admonition,details)>*{box-sizing:border-box}.md-typeset :is(.admonition,details)>*{box-sizing:border-box}.md-typeset :-webkit-any(.admonition,details) :-webkit-any(.admonition,details){margin-bottom:1em;margin-top:1em}.md-typeset :-moz-any(.admonition,details) :-moz-any(.admonition,details){margin-bottom:1em;margin-top:1em}.md-typeset :is(.admonition,details) :is(.admonition,details){margin-bottom:1em;margin-top:1em}.md-typeset :-webkit-any(.admonition,details) .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset :-moz-any(.admonition,details) .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset :is(.admonition,details) .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset :-webkit-any(.admonition,details) .md-typeset__table{padding:0 .6rem}.md-typeset :-moz-any(.admonition,details) .md-typeset__table{padding:0 .6rem}.md-typeset :is(.admonition,details) .md-typeset__table{padding:0 .6rem}.md-typeset :-webkit-any(.admonition,details)>.tabbed-set:only-child{margin-top:0}.md-typeset :-moz-any(.admonition,details)>.tabbed-set:only-child{margin-top:0}.md-typeset :is(.admonition,details)>.tabbed-set:only-child{margin-top:0}html .md-typeset :-webkit-any(.admonition,details)>:last-child{margin-bottom:.6rem}html .md-typeset :-moz-any(.admonition,details)>:last-child{margin-bottom:.6rem}html .md-typeset :is(.admonition,details)>:last-child{margin-bottom:.6rem}.md-typeset :-webkit-any(.admonition-title,summary){background-color:rgba(68,138,255,.1);border:0 solid #448aff;font-weight:700;margin-bottom:0;margin-top:0;padding-bottom:.4rem;padding-top:.4rem;position:relative}.md-typeset :-moz-any(.admonition-title,summary){background-color:rgba(68,138,255,.1);border:0 solid #448aff;font-weight:700;margin-bottom:0;margin-top:0;padding-bottom:.4rem;padding-top:.4rem;position:relative}[dir=ltr] .md-typeset :-webkit-any(.admonition-title,summary){margin-left:-.8rem;margin-right:-.6rem}[dir=ltr] .md-typeset :-moz-any(.admonition-title,summary){margin-left:-.8rem;margin-right:-.6rem}[dir=ltr] .md-typeset :is(.admonition-title,summary){margin-left:-.8rem;margin-right:-.6rem}[dir=rtl] .md-typeset :-webkit-any(.admonition-title,summary){margin-left:-.6rem;margin-right:-.8rem}[dir=rtl] .md-typeset :-moz-any(.admonition-title,summary){margin-left:-.6rem;margin-right:-.8rem}[dir=rtl] .md-typeset :is(.admonition-title,summary){margin-left:-.6rem;margin-right:-.8rem}[dir=ltr] .md-typeset :-webkit-any(.admonition-title,summary){padding-left:2rem;padding-right:.6rem}[dir=ltr] .md-typeset :-moz-any(.admonition-title,summary){padding-left:2rem;padding-right:.6rem}[dir=ltr] .md-typeset :is(.admonition-title,summary){padding-left:2rem;padding-right:.6rem}[dir=rtl] .md-typeset :-webkit-any(.admonition-title,summary){padding-left:.6rem;padding-right:2rem}[dir=rtl] .md-typeset :-moz-any(.admonition-title,summary){padding-left:.6rem;padding-right:2rem}[dir=rtl] .md-typeset :is(.admonition-title,summary){padding-left:.6rem;padding-right:2rem}[dir=ltr] .md-typeset :-webkit-any(.admonition-title,summary){border-left-width:.2rem}[dir=ltr] .md-typeset :-moz-any(.admonition-title,summary){border-left-width:.2rem}[dir=ltr] .md-typeset :is(.admonition-title,summary){border-left-width:.2rem}[dir=rtl] .md-typeset :-webkit-any(.admonition-title,summary){border-right-width:.2rem}[dir=rtl] .md-typeset :-moz-any(.admonition-title,summary){border-right-width:.2rem}[dir=rtl] .md-typeset :is(.admonition-title,summary){border-right-width:.2rem}[dir=ltr] .md-typeset :-webkit-any(.admonition-title,summary){border-top-left-radius:.1rem}[dir=ltr] .md-typeset :-moz-any(.admonition-title,summary){border-top-left-radius:.1rem}[dir=ltr] .md-typeset :is(.admonition-title,summary){border-top-left-radius:.1rem}[dir=rtl] .md-typeset :-webkit-any(.admonition-title,summary){border-top-right-radius:.1rem}[dir=rtl] .md-typeset :-moz-any(.admonition-title,summary){border-top-right-radius:.1rem}[dir=rtl] .md-typeset :is(.admonition-title,summary){border-top-right-radius:.1rem}.md-typeset :is(.admonition-title,summary){background-color:rgba(68,138,255,.1);border:0 solid #448aff;font-weight:700;margin-bottom:0;margin-top:0;padding-bottom:.4rem;padding-top:.4rem;position:relative}html .md-typeset :-webkit-any(.admonition-title,summary):last-child{margin-bottom:0}html .md-typeset :-moz-any(.admonition-title,summary):last-child{margin-bottom:0}html .md-typeset :is(.admonition-title,summary):last-child{margin-bottom:0}.md-typeset :-webkit-any(.admonition-title,summary):before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset :-moz-any(.admonition-title,summary):before{background-color:#448aff;content:"";height:1rem;mask-image:var(--md-admonition-icon--note);mask-repeat:no-repeat;mask-size:contain;position:absolute;top:.625em;width:1rem}[dir=ltr] .md-typeset :-webkit-any(.admonition-title,summary):before{left:.6rem}[dir=ltr] .md-typeset :-moz-any(.admonition-title,summary):before{left:.6rem}[dir=ltr] .md-typeset :is(.admonition-title,summary):before{left:.6rem}[dir=rtl] .md-typeset :-webkit-any(.admonition-title,summary):before{right:.6rem}[dir=rtl] .md-typeset :-moz-any(.admonition-title,summary):before{right:.6rem}[dir=rtl] .md-typeset :is(.admonition-title,summary):before{right:.6rem}.md-typeset :is(.admonition-title,summary):before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.note){border-color:#448aff}.md-typeset :-moz-any(.admonition,details):-moz-any(.note){border-color:#448aff}.md-typeset :is(.admonition,details):is(.note){border-color:#448aff}.md-typeset :-webkit-any(.note)>:-webkit-any(.admonition-title,summary){background-color:rgba(68,138,255,.1);border-color:#448aff}.md-typeset :-moz-any(.note)>:-moz-any(.admonition-title,summary){background-color:rgba(68,138,255,.1);border-color:#448aff}.md-typeset :is(.note)>:is(.admonition-title,summary){background-color:rgba(68,138,255,.1);border-color:#448aff}.md-typeset :-webkit-any(.note)>:-webkit-any(.admonition-title,summary):before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.note)>:-moz-any(.admonition-title,summary):before{background-color:#448aff;mask-image:var(--md-admonition-icon--note);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.note)>:is(.admonition-title,summary):before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.abstract,.summary,.tldr){border-color:#00b0ff}.md-typeset :-moz-any(.admonition,details):-moz-any(.abstract,.summary,.tldr){border-color:#00b0ff}.md-typeset :is(.admonition,details):is(.abstract,.summary,.tldr){border-color:#00b0ff}.md-typeset :-webkit-any(.abstract,.summary,.tldr)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,176,255,.1);border-color:#00b0ff}.md-typeset :-moz-any(.abstract,.summary,.tldr)>:-moz-any(.admonition-title,summary){background-color:rgba(0,176,255,.1);border-color:#00b0ff}.md-typeset :is(.abstract,.summary,.tldr)>:is(.admonition-title,summary){background-color:rgba(0,176,255,.1);border-color:#00b0ff}.md-typeset :-webkit-any(.abstract,.summary,.tldr)>:-webkit-any(.admonition-title,summary):before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.abstract,.summary,.tldr)>:-moz-any(.admonition-title,summary):before{background-color:#00b0ff;mask-image:var(--md-admonition-icon--abstract);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.abstract,.summary,.tldr)>:is(.admonition-title,summary):before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.info,.todo){border-color:#00b8d4}.md-typeset :-moz-any(.admonition,details):-moz-any(.info,.todo){border-color:#00b8d4}.md-typeset :is(.admonition,details):is(.info,.todo){border-color:#00b8d4}.md-typeset :-webkit-any(.info,.todo)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,184,212,.1);border-color:#00b8d4}.md-typeset :-moz-any(.info,.todo)>:-moz-any(.admonition-title,summary){background-color:rgba(0,184,212,.1);border-color:#00b8d4}.md-typeset :is(.info,.todo)>:is(.admonition-title,summary){background-color:rgba(0,184,212,.1);border-color:#00b8d4}.md-typeset :-webkit-any(.info,.todo)>:-webkit-any(.admonition-title,summary):before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.info,.todo)>:-moz-any(.admonition-title,summary):before{background-color:#00b8d4;mask-image:var(--md-admonition-icon--info);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.info,.todo)>:is(.admonition-title,summary):before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.tip,.hint,.important){border-color:#00bfa5}.md-typeset :-moz-any(.admonition,details):-moz-any(.tip,.hint,.important){border-color:#00bfa5}.md-typeset :is(.admonition,details):is(.tip,.hint,.important){border-color:#00bfa5}.md-typeset :-webkit-any(.tip,.hint,.important)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,191,165,.1);border-color:#00bfa5}.md-typeset :-moz-any(.tip,.hint,.important)>:-moz-any(.admonition-title,summary){background-color:rgba(0,191,165,.1);border-color:#00bfa5}.md-typeset :is(.tip,.hint,.important)>:is(.admonition-title,summary){background-color:rgba(0,191,165,.1);border-color:#00bfa5}.md-typeset :-webkit-any(.tip,.hint,.important)>:-webkit-any(.admonition-title,summary):before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.tip,.hint,.important)>:-moz-any(.admonition-title,summary):before{background-color:#00bfa5;mask-image:var(--md-admonition-icon--tip);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.tip,.hint,.important)>:is(.admonition-title,summary):before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.success,.check,.done){border-color:#00c853}.md-typeset :-moz-any(.admonition,details):-moz-any(.success,.check,.done){border-color:#00c853}.md-typeset :is(.admonition,details):is(.success,.check,.done){border-color:#00c853}.md-typeset :-webkit-any(.success,.check,.done)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,200,83,.1);border-color:#00c853}.md-typeset :-moz-any(.success,.check,.done)>:-moz-any(.admonition-title,summary){background-color:rgba(0,200,83,.1);border-color:#00c853}.md-typeset :is(.success,.check,.done)>:is(.admonition-title,summary){background-color:rgba(0,200,83,.1);border-color:#00c853}.md-typeset :-webkit-any(.success,.check,.done)>:-webkit-any(.admonition-title,summary):before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.success,.check,.done)>:-moz-any(.admonition-title,summary):before{background-color:#00c853;mask-image:var(--md-admonition-icon--success);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.success,.check,.done)>:is(.admonition-title,summary):before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.question,.help,.faq){border-color:#64dd17}.md-typeset :-moz-any(.admonition,details):-moz-any(.question,.help,.faq){border-color:#64dd17}.md-typeset :is(.admonition,details):is(.question,.help,.faq){border-color:#64dd17}.md-typeset :-webkit-any(.question,.help,.faq)>:-webkit-any(.admonition-title,summary){background-color:rgba(100,221,23,.1);border-color:#64dd17}.md-typeset :-moz-any(.question,.help,.faq)>:-moz-any(.admonition-title,summary){background-color:rgba(100,221,23,.1);border-color:#64dd17}.md-typeset :is(.question,.help,.faq)>:is(.admonition-title,summary){background-color:rgba(100,221,23,.1);border-color:#64dd17}.md-typeset :-webkit-any(.question,.help,.faq)>:-webkit-any(.admonition-title,summary):before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.question,.help,.faq)>:-moz-any(.admonition-title,summary):before{background-color:#64dd17;mask-image:var(--md-admonition-icon--question);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.question,.help,.faq)>:is(.admonition-title,summary):before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.warning,.caution,.attention){border-color:#ff9100}.md-typeset :-moz-any(.admonition,details):-moz-any(.warning,.caution,.attention){border-color:#ff9100}.md-typeset :is(.admonition,details):is(.warning,.caution,.attention){border-color:#ff9100}.md-typeset :-webkit-any(.warning,.caution,.attention)>:-webkit-any(.admonition-title,summary){background-color:rgba(255,145,0,.1);border-color:#ff9100}.md-typeset :-moz-any(.warning,.caution,.attention)>:-moz-any(.admonition-title,summary){background-color:rgba(255,145,0,.1);border-color:#ff9100}.md-typeset :is(.warning,.caution,.attention)>:is(.admonition-title,summary){background-color:rgba(255,145,0,.1);border-color:#ff9100}.md-typeset :-webkit-any(.warning,.caution,.attention)>:-webkit-any(.admonition-title,summary):before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.warning,.caution,.attention)>:-moz-any(.admonition-title,summary):before{background-color:#ff9100;mask-image:var(--md-admonition-icon--warning);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.warning,.caution,.attention)>:is(.admonition-title,summary):before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.failure,.fail,.missing){border-color:#ff5252}.md-typeset :-moz-any(.admonition,details):-moz-any(.failure,.fail,.missing){border-color:#ff5252}.md-typeset :is(.admonition,details):is(.failure,.fail,.missing){border-color:#ff5252}.md-typeset :-webkit-any(.failure,.fail,.missing)>:-webkit-any(.admonition-title,summary){background-color:rgba(255,82,82,.1);border-color:#ff5252}.md-typeset :-moz-any(.failure,.fail,.missing)>:-moz-any(.admonition-title,summary){background-color:rgba(255,82,82,.1);border-color:#ff5252}.md-typeset :is(.failure,.fail,.missing)>:is(.admonition-title,summary){background-color:rgba(255,82,82,.1);border-color:#ff5252}.md-typeset :-webkit-any(.failure,.fail,.missing)>:-webkit-any(.admonition-title,summary):before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.failure,.fail,.missing)>:-moz-any(.admonition-title,summary):before{background-color:#ff5252;mask-image:var(--md-admonition-icon--failure);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.failure,.fail,.missing)>:is(.admonition-title,summary):before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.danger,.error){border-color:#ff1744}.md-typeset :-moz-any(.admonition,details):-moz-any(.danger,.error){border-color:#ff1744}.md-typeset :is(.admonition,details):is(.danger,.error){border-color:#ff1744}.md-typeset :-webkit-any(.danger,.error)>:-webkit-any(.admonition-title,summary){background-color:rgba(255,23,68,.1);border-color:#ff1744}.md-typeset :-moz-any(.danger,.error)>:-moz-any(.admonition-title,summary){background-color:rgba(255,23,68,.1);border-color:#ff1744}.md-typeset :is(.danger,.error)>:is(.admonition-title,summary){background-color:rgba(255,23,68,.1);border-color:#ff1744}.md-typeset :-webkit-any(.danger,.error)>:-webkit-any(.admonition-title,summary):before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.danger,.error)>:-moz-any(.admonition-title,summary):before{background-color:#ff1744;mask-image:var(--md-admonition-icon--danger);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.danger,.error)>:is(.admonition-title,summary):before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.bug){border-color:#f50057}.md-typeset :-moz-any(.admonition,details):-moz-any(.bug){border-color:#f50057}.md-typeset :is(.admonition,details):is(.bug){border-color:#f50057}.md-typeset :-webkit-any(.bug)>:-webkit-any(.admonition-title,summary){background-color:rgba(245,0,87,.1);border-color:#f50057}.md-typeset :-moz-any(.bug)>:-moz-any(.admonition-title,summary){background-color:rgba(245,0,87,.1);border-color:#f50057}.md-typeset :is(.bug)>:is(.admonition-title,summary){background-color:rgba(245,0,87,.1);border-color:#f50057}.md-typeset :-webkit-any(.bug)>:-webkit-any(.admonition-title,summary):before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.bug)>:-moz-any(.admonition-title,summary):before{background-color:#f50057;mask-image:var(--md-admonition-icon--bug);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.bug)>:is(.admonition-title,summary):before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.example){border-color:#7c4dff}.md-typeset :-moz-any(.admonition,details):-moz-any(.example){border-color:#7c4dff}.md-typeset :is(.admonition,details):is(.example){border-color:#7c4dff}.md-typeset :-webkit-any(.example)>:-webkit-any(.admonition-title,summary){background-color:rgba(124,77,255,.1);border-color:#7c4dff}.md-typeset :-moz-any(.example)>:-moz-any(.admonition-title,summary){background-color:rgba(124,77,255,.1);border-color:#7c4dff}.md-typeset :is(.example)>:is(.admonition-title,summary){background-color:rgba(124,77,255,.1);border-color:#7c4dff}.md-typeset :-webkit-any(.example)>:-webkit-any(.admonition-title,summary):before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.example)>:-moz-any(.admonition-title,summary):before{background-color:#7c4dff;mask-image:var(--md-admonition-icon--example);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.example)>:is(.admonition-title,summary):before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.quote,.cite){border-color:#9e9e9e}.md-typeset :-moz-any(.admonition,details):-moz-any(.quote,.cite){border-color:#9e9e9e}.md-typeset :is(.admonition,details):is(.quote,.cite){border-color:#9e9e9e}.md-typeset :-webkit-any(.quote,.cite)>:-webkit-any(.admonition-title,summary){background-color:hsla(0,0%,62%,.1);border-color:#9e9e9e}.md-typeset :-moz-any(.quote,.cite)>:-moz-any(.admonition-title,summary){background-color:hsla(0,0%,62%,.1);border-color:#9e9e9e}.md-typeset :is(.quote,.cite)>:is(.admonition-title,summary){background-color:hsla(0,0%,62%,.1);border-color:#9e9e9e}.md-typeset :-webkit-any(.quote,.cite)>:-webkit-any(.admonition-title,summary):before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.quote,.cite)>:-moz-any(.admonition-title,summary):before{background-color:#9e9e9e;mask-image:var(--md-admonition-icon--quote);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.quote,.cite)>:is(.admonition-title,summary):before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateX(0);transition:none}.md-typeset .footnote>ol>li:-webkit-any(:hover,:target) .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li:-moz-any(:hover,:target) .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li:is(:hover,:target) .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateX(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateX(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateX(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before svg{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :-webkit-any(:hover,:target)>.headerlink{opacity:1;-webkit-transition:color .25s,opacity 125ms;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset :-moz-any(:hover,:target)>.headerlink{opacity:1;-moz-transition:color .25s,opacity 125ms;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset :is(:hover,:target)>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:-webkit-any(:focus,:hover),.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset .headerlink:-moz-any(:focus,:hover),.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset .headerlink:is(:focus,:hover),.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset :-webkit-any(h1,h2,h3):target{--md-scroll-offset:0.2rem}.md-typeset :-moz-any(h1,h2,h3):target{--md-scroll-offset:0.2rem}.md-typeset :is(h1,h2,h3):target{--md-scroll-offset:0.2rem}.md-typeset h4:target{--md-scroll-offset:0.15rem}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.9375em){.md-typeset div.arithmatex{margin:0 -.8rem}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto;width:-webkit-min-content;width:-moz-min-content;width:min-content}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset :-webkit-any(del,ins,.comment).critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset :-moz-any(del,ins,.comment).critic{box-decoration-break:clone}.md-typeset :is(del,ins,.comment).critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem}[dir=ltr] .md-typeset summary{padding-right:1.8rem}[dir=rtl] .md-typeset summary{padding-left:1.8rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=ltr] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:.4rem}[dir=rtl] .md-typeset summary:after{left:.4rem}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset :-webkit-any(.emojione,.twemoji,.gemoji){display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset :-moz-any(.emojione,.twemoji,.gemoji){display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset :is(.emojione,.twemoji,.gemoji){display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset :-webkit-any(.emojione,.twemoji,.gemoji) svg{fill:currentcolor;max-height:100%;width:1.125em}.md-typeset :-moz-any(.emojione,.twemoji,.gemoji) svg{fill:currentcolor;max-height:100%;width:1.125em}.md-typeset :is(.emojione,.twemoji,.gemoji) svg{fill:currentcolor;max-height:100%;width:1.125em}.highlight :-webkit-any(.o,.ow){color:var(--md-code-hl-operator-color)}.highlight :-moz-any(.o,.ow){color:var(--md-code-hl-operator-color)}.highlight :is(.o,.ow){color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight :-webkit-any(.cpf,.l,.s,.sb,.sc,.s2,.si,.s1,.ss){color:var(--md-code-hl-string-color)}.highlight :-moz-any(.cpf,.l,.s,.sb,.sc,.s2,.si,.s1,.ss){color:var(--md-code-hl-string-color)}.highlight :is(.cpf,.l,.s,.sb,.sc,.s2,.si,.s1,.ss){color:var(--md-code-hl-string-color)}.highlight :-webkit-any(.cp,.se,.sh,.sr,.sx){color:var(--md-code-hl-special-color)}.highlight :-moz-any(.cp,.se,.sh,.sr,.sx){color:var(--md-code-hl-special-color)}.highlight :is(.cp,.se,.sh,.sr,.sx){color:var(--md-code-hl-special-color)}.highlight :-webkit-any(.m,.mb,.mf,.mh,.mi,.il,.mo){color:var(--md-code-hl-number-color)}.highlight :-moz-any(.m,.mb,.mf,.mh,.mi,.il,.mo){color:var(--md-code-hl-number-color)}.highlight :is(.m,.mb,.mf,.mh,.mi,.il,.mo){color:var(--md-code-hl-number-color)}.highlight :-webkit-any(.k,.kd,.kn,.kp,.kr,.kt){color:var(--md-code-hl-keyword-color)}.highlight :-moz-any(.k,.kd,.kn,.kp,.kr,.kt){color:var(--md-code-hl-keyword-color)}.highlight :is(.k,.kd,.kn,.kp,.kr,.kt){color:var(--md-code-hl-keyword-color)}.highlight :-webkit-any(.kc,.n){color:var(--md-code-hl-name-color)}.highlight :-moz-any(.kc,.n){color:var(--md-code-hl-name-color)}.highlight :is(.kc,.n){color:var(--md-code-hl-name-color)}.highlight :-webkit-any(.no,.nb,.bp){color:var(--md-code-hl-constant-color)}.highlight :-moz-any(.no,.nb,.bp){color:var(--md-code-hl-constant-color)}.highlight :is(.no,.nb,.bp){color:var(--md-code-hl-constant-color)}.highlight :-webkit-any(.nc,.ne,.nf,.nn){color:var(--md-code-hl-function-color)}.highlight :-moz-any(.nc,.ne,.nf,.nn){color:var(--md-code-hl-function-color)}.highlight :is(.nc,.ne,.nf,.nn){color:var(--md-code-hl-function-color)}.highlight :-webkit-any(.nd,.ni,.nl,.nt){color:var(--md-code-hl-keyword-color)}.highlight :-moz-any(.nd,.ni,.nl,.nt){color:var(--md-code-hl-keyword-color)}.highlight :is(.nd,.ni,.nl,.nt){color:var(--md-code-hl-keyword-color)}.highlight :-webkit-any(.c,.cm,.c1,.ch,.cs,.sd){color:var(--md-code-hl-comment-color)}.highlight :-moz-any(.c,.cm,.c1,.ch,.cs,.sd){color:var(--md-code-hl-comment-color)}.highlight :is(.c,.cm,.c1,.ch,.cs,.sd){color:var(--md-code-hl-comment-color)}.highlight :-webkit-any(.na,.nv,.vc,.vg,.vi){color:var(--md-code-hl-variable-color)}.highlight :-moz-any(.na,.nv,.vc,.vg,.vi){color:var(--md-code-hl-variable-color)}.highlight :is(.na,.nv,.vc,.vg,.vi){color:var(--md-code-hl-variable-color)}.highlight :-webkit-any(.ge,.gr,.gh,.go,.gp,.gs,.gu,.gt){color:var(--md-code-hl-generic-color)}.highlight :-moz-any(.ge,.gr,.gh,.go,.gp,.gs,.gu,.gt){color:var(--md-code-hl-generic-color)}.highlight :is(.ge,.gr,.gh,.go,.gp,.gs,.gu,.gt){color:var(--md-code-hl-generic-color)}.highlight :-webkit-any(.gd,.gi){border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight :-moz-any(.gd,.gi){border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight :is(.gd,.gi){border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color);display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.1rem;border-top-right-radius:.1rem;display:block;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:-webkit-sticky;position:sticky;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:3}.highlight code a[id]{position:absolute;visibility:hidden}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable :-webkit-any(tbody,td){display:block;padding:0}.highlighttable :-moz-any(tbody,td){display:block;padding:0}.highlighttable :is(tbody,td){display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-top-left-radius:.1rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;padding-right:.5882352941em}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset :-webkit-any(.highlight,.highlighttable)+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset :-moz-any(.highlight,.highlighttable)+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset :is(.highlight,.highlighttable)+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset :-webkit-any(.highlight,.highlighttable)+.result:after{clear:both;content:"";display:block}.md-typeset :-moz-any(.highlight,.highlighttable)+.result:after{clear:both;content:"";display:block}.md-typeset :is(.highlight,.highlighttable)+.result:after{clear:both;content:"";display:block}@media screen and (max-width:44.9375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight .hll{margin:0 -.8rem;padding:0 .8rem}.md-content__inner>.highlight code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}.md-content__inner>.highlighttable{border-radius:0;margin:1em -.8rem}.md-content__inner>.highlighttable .hll{margin:0 -.8rem;padding:0 .8rem}}.md-typeset .keys kbd:-webkit-any(:before,:after){-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys kbd:-moz-any(:before,:after){-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys kbd:is(:before,:after){-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-left-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-left-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-right-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-right-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-left-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-right-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;-ms-scroll-snap-type:x proximity;scroll-snap-type:x proximity;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-accent-fg-color);bottom:0;content:"";display:block;height:2px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid transparent;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.64rem;font-weight:700;padding:.78125em 1.25em .625em;scroll-snap-align:start;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-accent-fg-color)}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child pre,.md-typeset .tabbed-block>.highlighttable:first-child,.md-typeset .tabbed-block>pre:first-child{margin:0}[dir=ltr] .md-typeset .tabbed-block>.highlight:first-child pre code,[dir=ltr] .md-typeset .tabbed-block>.highlighttable:first-child code,[dir=ltr] .md-typeset .tabbed-block>pre:first-child code{border-top-left-radius:0}[dir=rtl] .md-typeset .tabbed-block>.highlight:first-child pre code,[dir=rtl] .md-typeset .tabbed-block>.highlighttable:first-child code,[dir=rtl] .md-typeset .tabbed-block>pre:first-child code{border-top-right-radius:0}[dir=ltr] .md-typeset .tabbed-block>.highlight:first-child pre code,[dir=ltr] .md-typeset .tabbed-block>.highlighttable:first-child code,[dir=ltr] .md-typeset .tabbed-block>pre:first-child code{border-top-right-radius:0}[dir=rtl] .md-typeset .tabbed-block>.highlight:first-child pre code,[dir=rtl] .md-typeset .tabbed-block>.highlighttable:first-child code,[dir=rtl] .md-typeset .tabbed-block>pre:first-child code{border-top-left-radius:0}[dir=ltr] .md-typeset .tabbed-block>.highlighttable:first-child .linenos{border-top-left-radius:0}[dir=rtl] .md-typeset .tabbed-block>.highlighttable:first-child .linenos{border-top-right-radius:0}[dir=ltr] .md-typeset .tabbed-block>.highlighttable:first-child .linenos{border-top-right-radius:0}[dir=rtl] .md-typeset .tabbed-block>.highlighttable:first-child .linenos{border-top-left-radius:0}.md-typeset .tabbed-block>.result:nth-child(2){margin-top:0}.md-typeset .tabbed-block>.tabbed-set{margin:0}@media screen and (max-width:44.9375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-accent-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){background-color:var(--md-accent-fg-color--transparent)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color)}.mermaid{line-height:normal;margin:1em 0}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{float:left;margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}.md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}} \ No newline at end of file diff --git a/site/assets/stylesheets/main.e8d9bf0c.min.css.map b/site/assets/stylesheets/main.e8d9bf0c.min.css.map new file mode 100644 index 0000000000..fe77432900 --- /dev/null +++ b/site/assets/stylesheets/main.e8d9bf0c.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["src/assets/stylesheets/main/extensions/pymdownx/_keys.scss","../../../src/assets/stylesheets/main.scss","src/assets/stylesheets/main/_resets.scss","src/assets/stylesheets/main/_colors.scss","src/assets/stylesheets/main/_icons.scss","src/assets/stylesheets/main/_typeset.scss","src/assets/stylesheets/utilities/_break.scss","src/assets/stylesheets/main/layout/_banner.scss","src/assets/stylesheets/main/layout/_base.scss","src/assets/stylesheets/main/layout/_clipboard.scss","src/assets/stylesheets/main/layout/_content.scss","src/assets/stylesheets/main/layout/_dialog.scss","src/assets/stylesheets/main/layout/_footer.scss","src/assets/stylesheets/main/layout/_form.scss","src/assets/stylesheets/main/layout/_header.scss","src/assets/stylesheets/main/layout/_nav.scss","src/assets/stylesheets/main/layout/_search.scss","src/assets/stylesheets/main/layout/_select.scss","src/assets/stylesheets/main/layout/_sidebar.scss","src/assets/stylesheets/main/layout/_source.scss","src/assets/stylesheets/main/layout/_tabs.scss","src/assets/stylesheets/main/layout/_tag.scss","src/assets/stylesheets/main/layout/_tooltip.scss","src/assets/stylesheets/main/layout/_top.scss","src/assets/stylesheets/main/layout/_version.scss","src/assets/stylesheets/main/extensions/markdown/_admonition.scss","node_modules/material-design-color/material-color.scss","src/assets/stylesheets/main/extensions/markdown/_footnotes.scss","src/assets/stylesheets/main/extensions/markdown/_toc.scss","src/assets/stylesheets/main/extensions/pymdownx/_arithmatex.scss","src/assets/stylesheets/main/extensions/pymdownx/_critic.scss","src/assets/stylesheets/main/extensions/pymdownx/_details.scss","src/assets/stylesheets/main/extensions/pymdownx/_emoji.scss","src/assets/stylesheets/main/extensions/pymdownx/_highlight.scss","src/assets/stylesheets/main/extensions/pymdownx/_tabbed.scss","src/assets/stylesheets/main/extensions/pymdownx/_tasklist.scss","src/assets/stylesheets/main/integrations/_mermaid.scss","src/assets/stylesheets/main/_modifiers.scss"],"names":[],"mappings":"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AA,CAEA,yCAAA,CAAA,iCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CARA,iBAAA,CACA,UAAA,CAQA,sBAAA,CACA,yBAAA,CAPA,U9BgiGN,C8BrhGM,oCACE,wB9BuhGR,C8BlhGI,4BACE,Y9BohGN,C8B/gGI,4CACE,Y9BihGN,C+BnmGE,qDACE,mBAAA,CACA,cAAA,CACA,uB/BsmGJ,C+BzmGE,kDACE,mBAAA,CACA,cAAA,CACA,uB/BsmGJ,C+BzmGE,4CACE,mBAAA,CACA,cAAA,CACA,uB/BsmGJ,C+BnmGI,yDAGE,iBAAA,CADA,eAAA,CADA,a/BumGN,C+BxmGI,sDAGE,iBAAA,CADA,eAAA,CADA,a/BumGN,C+BxmGI,gDAGE,iBAAA,CADA,eAAA,CADA,a/BumGN,CgC7mGE,gCACE,sChCgnGJ,CgCjnGE,6BACE,sChCgnGJ,CgCjnGE,uBACE,sChCgnGJ,CgC7mGE,cACE,yChC+mGJ,CgCnmGE,4DACE,oChCqmGJ,CgCtmGE,yDACE,oChCqmGJ,CgCtmGE,mDACE,oChCqmGJ,CgC7lGE,6CACE,qChC+lGJ,CgChmGE,0CACE,qChC+lGJ,CgChmGE,oCACE,qChC+lGJ,CgCrlGE,oDACE,oChCulGJ,CgCxlGE,iDACE,oChCulGJ,CgCxlGE,2CACE,oChCulGJ,CgC9kGE,gDACE,qChCglGJ,CgCjlGE,6CACE,qChCglGJ,CgCjlGE,uCACE,qChCglGJ,CgC3kGE,gCACE,kChC6kGJ,CgC9kGE,6BACE,kChC6kGJ,CgC9kGE,uBACE,kChC6kGJ,CgCvkGE,qCACE,sChCykGJ,CgC1kGE,kCACE,sChCykGJ,CgC1kGE,4BACE,sChCykGJ,CgClkGE,yCACE,sChCokGJ,CgCrkGE,sCACE,sChCokGJ,CgCrkGE,gCACE,sChCokGJ,CgC7jGE,yCACE,qChC+jGJ,CgChkGE,sCACE,qChC+jGJ,CgChkGE,gCACE,qChC+jGJ,CgCtjGE,gDACE,qChCwjGJ,CgCzjGE,6CACE,qChCwjGJ,CgCzjGE,uCACE,qChCwjGJ,CgChjGE,6CACE,sChCkjGJ,CgCnjGE,0CAC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C7+GE,0BACE,YjC++GJ,CiC5+GI,aAJF,0BAKI,ajC++GJ,CiC3+GM,sCACE,OjC6+GR,CiC9+GM,uCACE,OjCg/GR,CiCj/GM,uCACE,OjCm/GR,CiCp/GM,uCACE,OjCs/GR,CiCv/GM,uCACE,OjCy/GR,CiC1/GM,uCACE,OjC4/GR,CiC7/GM,uCACE,OjC+/GR,CiChgHM,uCACE,OjCkgHR,CiCngHM,uCACE,OjCqgHR,CiCtgHM,wCACE,QjCwgHR,CiCzgHM,wCACE,QjC2gHR,CiC5gHM,wCACE,QjC8gHR,CiC/gHM,wCACE,QjCihHR,CiClhHM,wCACE,QjCohHR,CiCrhHM,wCACE,QjCuhHR,CiCxhHM,wCACE,QjC0hHR,CiC3hHM,wCACE,QjC6hHR,CiC9hHM,wCACE,QjCgiHR,CiCjiHM,wCACE,QjCmiHR,CiCpiHM,wCACE,QjCsiHR,CACF,CiChiHI,qJAGE,QjCkiHN,CiC/hHM,kMACE,wBjCoiHR,CiCriHM,kMACE,yBjCoiHR,CiCriHM,kMAEE,yBjCmiHR,CiCriHM,kMAEE,wBjCmiHR,CiC9hHI,yEACE,wBjCiiHN,CiCliHI,yEACE,yBjCiiHN,CiCliHI,yEAEE,yBjCgiHN,CiCliHI,yEAEE,wBjCgiHN,CiC5hHI,+CACE,YjC8hHN,CiC1hHI,sCACE,QjC4hHN,CK7hHI,wC4BcF,wDAGE,kBjCohHF,CiCvhHA,wDAGE,mBjCohHF,CiCvhHA,8CAEE,eAAA,CADA,eAAA,CAGA,iCjCmhHF,CiC/gHE,8DACE,mBjCkhHJ,CiCnhHE,8DACE,kBjCkhHJ,CiCnhHE,oDAEE,UjCihHJ,CACF,CiCrgHE,cAHF,olDAII,+BjCwgHF,CiCrgHE,g8GACE,sCjCugHJ,CACF,CiClgHA,4sDACE,uDjCqgHF,CiCjgHA,wmDACE,ajCogHF,CkCnvHA,MACE,mVAAA,CAEA,4VlCuvHF,CkC7uHE,4BAEE,oBAAA,CADA,iBlCivHJ,CkC5uHI,sDAGE,SlC8uHN,CkCjvHI,sDAGE,UlC8uHN,CkCjvHI,4CACE,iBAAA,CACA,SlC+uHN,CkCzuHE,+CAEE,SAAA,CADA,UlC4uHJ,CkCvuHE,kDAGE,WlCgvHJ,CkCnvHE,kDAGE,YlCgvHJ,CkCnvHE,wCAME,qDAAA,CAIA,UAAA,CALA,aAAA,CAEA,0CAAA,CAAA,kCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CARA,iBAAA,CACA,SAAA,CAEA,YlC+uHJ,CkCruHE,gEACE,wBT0Wa,CSzWb,mDAAA,CAAA,2ClCuuHJ,CmCxxHA,QACE,8DAAA,CAGA,+CAAA,CACA,iEAAA,CACA,oDAAA,CACA,sDAAA,CACA,mDnCyxHF,CmCrxHA,SAEE,kBAAA,CADA,YnCyxHF,CKhoHI,mC+BhKA,8BAIE,kBpCqyHJ,CoCzyHE,8BAIE,iBpCqyHJ,CoCzyHE,oBACE,UAAA,CAIA,mBAAA,CAFA,YAAA,CADA,apCuyHJ,CoCjyHI,8BACE,WpCmyHN,CoC/xHI,kCAEE,iBAAA,CAAA,cpCiyHN,CoCnyHI,kCAEE,aAAA,CAAA,kBpCiyHN,CoCnyHI,wBACE,WpCkyHN,CoC9xHM,kCACE,UpCgyHR,CACF","file":"main.css"} \ No newline at end of file diff --git a/site/assets/stylesheets/palette.e6a45f82.min.css b/site/assets/stylesheets/palette.e6a45f82.min.css new file mode 100644 index 0000000000..9d16769c2a --- /dev/null +++ b/site/assets/stylesheets/palette.e6a45f82.min.css @@ -0,0 +1 @@ +[data-md-color-accent=red]{--md-accent-fg-color:#ff1947;--md-accent-fg-color--transparent:rgba(255,25,71,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=pink]{--md-accent-fg-color:#f50056;--md-accent-fg-color--transparent:rgba(245,0,86,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=purple]{--md-accent-fg-color:#df41fb;--md-accent-fg-color--transparent:rgba(223,65,251,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=deep-purple]{--md-accent-fg-color:#7c4dff;--md-accent-fg-color--transparent:rgba(124,77,255,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=indigo]{--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=blue]{--md-accent-fg-color:#4287ff;--md-accent-fg-color--transparent:rgba(66,135,255,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=light-blue]{--md-accent-fg-color:#0091eb;--md-accent-fg-color--transparent:rgba(0,145,235,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=cyan]{--md-accent-fg-color:#00bad6;--md-accent-fg-color--transparent:rgba(0,186,214,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=teal]{--md-accent-fg-color:#00bda4;--md-accent-fg-color--transparent:rgba(0,189,164,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=green]{--md-accent-fg-color:#00c753;--md-accent-fg-color--transparent:rgba(0,199,83,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=light-green]{--md-accent-fg-color:#63de17;--md-accent-fg-color--transparent:rgba(99,222,23,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=lime]{--md-accent-fg-color:#b0eb00;--md-accent-fg-color--transparent:rgba(176,235,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=yellow]{--md-accent-fg-color:#ffd500;--md-accent-fg-color--transparent:rgba(255,213,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=amber]{--md-accent-fg-color:#fa0;--md-accent-fg-color--transparent:rgba(255,170,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=orange]{--md-accent-fg-color:#ff9100;--md-accent-fg-color--transparent:rgba(255,145,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=deep-orange]{--md-accent-fg-color:#ff6e42;--md-accent-fg-color--transparent:rgba(255,110,66,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=red]{--md-primary-fg-color:#ef5552;--md-primary-fg-color--light:#e57171;--md-primary-fg-color--dark:#e53734;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=pink]{--md-primary-fg-color:#e92063;--md-primary-fg-color--light:#ec417a;--md-primary-fg-color--dark:#c3185d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=purple]{--md-primary-fg-color:#ab47bd;--md-primary-fg-color--light:#bb69c9;--md-primary-fg-color--dark:#8c24a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=deep-purple]{--md-primary-fg-color:#7e56c2;--md-primary-fg-color--light:#9574cd;--md-primary-fg-color--dark:#673ab6;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=indigo]{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=blue]{--md-primary-fg-color:#2094f3;--md-primary-fg-color--light:#42a5f5;--md-primary-fg-color--dark:#1975d2;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=light-blue]{--md-primary-fg-color:#02a6f2;--md-primary-fg-color--light:#28b5f6;--md-primary-fg-color--dark:#0287cf;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=cyan]{--md-primary-fg-color:#00bdd6;--md-primary-fg-color--light:#25c5da;--md-primary-fg-color--dark:#0097a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=teal]{--md-primary-fg-color:#009485;--md-primary-fg-color--light:#26a699;--md-primary-fg-color--dark:#007a6c;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=green]{--md-primary-fg-color:#4cae4f;--md-primary-fg-color--light:#68bb6c;--md-primary-fg-color--dark:#398e3d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=light-green]{--md-primary-fg-color:#8bc34b;--md-primary-fg-color--light:#9ccc66;--md-primary-fg-color--dark:#689f38;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=lime]{--md-primary-fg-color:#cbdc38;--md-primary-fg-color--light:#d3e156;--md-primary-fg-color--dark:#b0b52c;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=yellow]{--md-primary-fg-color:#ffec3d;--md-primary-fg-color--light:#ffee57;--md-primary-fg-color--dark:#fbc02d;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=amber]{--md-primary-fg-color:#ffc105;--md-primary-fg-color--light:#ffc929;--md-primary-fg-color--dark:#ffa200;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=orange]{--md-primary-fg-color:#ffa724;--md-primary-fg-color--light:#ffa724;--md-primary-fg-color--dark:#fa8900;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=deep-orange]{--md-primary-fg-color:#ff6e42;--md-primary-fg-color--light:#ff8a66;--md-primary-fg-color--dark:#f4511f;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=brown]{--md-primary-fg-color:#795649;--md-primary-fg-color--light:#8d6e62;--md-primary-fg-color--dark:#5d4037;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=grey]{--md-primary-fg-color:#757575;--md-primary-fg-color--light:#9e9e9e;--md-primary-fg-color--dark:#616161;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=blue-grey]{--md-primary-fg-color:#546d78;--md-primary-fg-color--light:#607c8a;--md-primary-fg-color--dark:#455a63;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=white]{--md-primary-fg-color:#fff;--md-primary-fg-color--light:hsla(0,0%,100%,.7);--md-primary-fg-color--dark:rgba(0,0,0,.07);--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54);--md-typeset-a-color:#4051b5}@media screen and (min-width:60em){[data-md-color-primary=white] .md-search__form{background-color:rgba(0,0,0,.07)}[data-md-color-primary=white] .md-search__form:hover{background-color:rgba(0,0,0,.32)}[data-md-color-primary=white] .md-search__input+.md-search__icon{color:rgba(0,0,0,.87)}}@media screen and (min-width:76.25em){[data-md-color-primary=white] .md-tabs{border-bottom:.05rem solid rgba(0,0,0,.07)}}[data-md-color-primary=black]{--md-primary-fg-color:#000;--md-primary-fg-color--light:rgba(0,0,0,.54);--md-primary-fg-color--dark:#000;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=black] .md-header{background-color:#000}@media screen and (max-width:59.9375em){[data-md-color-primary=black] .md-nav__source{background-color:rgba(0,0,0,.87)}}@media screen and (min-width:60em){[data-md-color-primary=black] .md-search__form{background-color:hsla(0,0%,100%,.12)}[data-md-color-primary=black] .md-search__form:hover{background-color:hsla(0,0%,100%,.3)}}@media screen and (max-width:76.1875em){html [data-md-color-primary=black] .md-nav--primary .md-nav__title[for=__drawer]{background-color:#000}}@media screen and (min-width:76.25em){[data-md-color-primary=black] .md-tabs{background-color:#000}}@media screen{[data-md-color-scheme=slate]{--md-hue:232;--md-default-fg-color:hsla(var(--md-hue),75%,95%,1);--md-default-fg-color--light:hsla(var(--md-hue),75%,90%,0.62);--md-default-fg-color--lighter:hsla(var(--md-hue),75%,90%,0.32);--md-default-fg-color--lightest:hsla(var(--md-hue),75%,90%,0.12);--md-default-bg-color:hsla(var(--md-hue),15%,21%,1);--md-default-bg-color--light:hsla(var(--md-hue),15%,21%,0.54);--md-default-bg-color--lighter:hsla(var(--md-hue),15%,21%,0.26);--md-default-bg-color--lightest:hsla(var(--md-hue),15%,21%,0.07);--md-code-fg-color:hsla(var(--md-hue),18%,86%,1);--md-code-bg-color:hsla(var(--md-hue),15%,15%,1);--md-code-hl-color:rgba(66,135,255,.15);--md-code-hl-number-color:#e6695b;--md-code-hl-special-color:#f06090;--md-code-hl-function-color:#c973d9;--md-code-hl-constant-color:#9383e2;--md-code-hl-keyword-color:#6791e0;--md-code-hl-string-color:#2fb170;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-mark-color:rgba(66,135,255,.3);--md-typeset-kbd-color:hsla(var(--md-hue),15%,94%,0.12);--md-typeset-kbd-accent-color:hsla(var(--md-hue),15%,94%,0.2);--md-typeset-kbd-border-color:hsla(var(--md-hue),15%,14%,1);--md-typeset-table-color:hsla(var(--md-hue),75%,95%,0.12);--md-admonition-bg-color:hsla(var(--md-hue),0%,100%,0.025);--md-footer-bg-color:hsla(var(--md-hue),15%,12%,0.87);--md-footer-bg-color--dark:hsla(var(--md-hue),15%,10%,1)}[data-md-color-scheme=slate][data-md-color-primary=black],[data-md-color-scheme=slate][data-md-color-primary=white]{--md-typeset-a-color:#5d6cc0}[data-md-color-scheme=slate] img[src$="#only-light"]{display:none}[data-md-color-scheme=slate] img[src$="#only-dark"]{display:initial}} \ No newline at end of file diff --git a/site/assets/stylesheets/palette.e6a45f82.min.css.map b/site/assets/stylesheets/palette.e6a45f82.min.css.map new file mode 100644 index 0000000000..b33c518da1 --- /dev/null +++ b/site/assets/stylesheets/palette.e6a45f82.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["src/assets/stylesheets/palette/_accent.scss","../../../src/assets/stylesheets/palette.scss","src/assets/stylesheets/palette/_primary.scss","src/assets/stylesheets/utilities/_break.scss","src/assets/stylesheets/palette/_scheme.scss"],"names":[],"mappings":"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","file":"palette.css"} \ No newline at end of file diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000000..b5649a8b81 --- /dev/null +++ b/site/index.html @@ -0,0 +1,777 @@ + + + + + + + + + + + + + + + + My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Welcome to MkDocs

    +

    For full documentation visit mkdocs.org.

    +

    Commands

    +
      +
    • mkdocs new [dir-name] - Create a new project.
    • +
    • mkdocs serve - Start the live-reloading docs server.
    • +
    • mkdocs build - Build the documentation site.
    • +
    • mkdocs -h - Print help message and exit.
    • +
    +

    Project layout

    +
    mkdocs.yml    # The configuration file.
    +docs/
    +    index.md  # The documentation homepage.
    +    ...       # Other markdown pages, images and other files.
    +
    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/search/search_index.json b/site/search/search_index.json new file mode 100644 index 0000000000..efbcd806dd --- /dev/null +++ b/site/search/search_index.json @@ -0,0 +1 @@ +{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Welcome to MkDocs For full documentation visit mkdocs.org . Commands mkdocs new [dir-name] - Create a new project. mkdocs serve - Start the live-reloading docs server. mkdocs build - Build the documentation site. mkdocs -h - Print help message and exit. Project layout mkdocs.yml # The configuration file. docs/ index.md # The documentation homepage. ... # Other markdown pages, images and other files.","title":"Welcome to MkDocs"},{"location":"#welcome-to-mkdocs","text":"For full documentation visit mkdocs.org .","title":"Welcome to MkDocs"},{"location":"#commands","text":"mkdocs new [dir-name] - Create a new project. mkdocs serve - Start the live-reloading docs server. mkdocs build - Build the documentation site. mkdocs -h - Print help message and exit.","title":"Commands"},{"location":"#project-layout","text":"mkdocs.yml # The configuration file. docs/ index.md # The documentation homepage. ... # Other markdown pages, images and other files.","title":"Project layout"},{"location":"Credits/","text":"Icon Credits Flag Icons made by Freepik from www.flaticon.com and licensed by Creative Commons 3.0 New Unciv logo made by u-ndefined on Discord Base tile icons for the \"Fantasy Hex\" tileset belong to CuddlyClover @ https://cuddlyclover.itch.io/fantasy-hex-tiles with a few additions by me Trees for the jungle tiles in the \"Fantasy Hex\" are extracted from Desert Strike for the Amiga Almost all the improvements and units made by The Bucketeer on Discord Tile icons for the \"ThorfMaps tileset belong to Thorfinn Tait and are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Based on work at www.thorfmaps.com. Unless otherwise specified, all the following are from the Noun Project licenced under either Creative Commons or Public Domain Stat icons Gear by Alex Bickov for Production Apple by Pedro Gon\u00e7alves for Food gold by Eliricon for Gold Beaker by Delwar Hossain for Science Music by Naomi Atkinson for Culture Smiley by Alexander Skowalsky for Happiness Dove by Sandra for Faith User by St\u00e9phanie Rusch for Population Unhappy By Daryl Vandermont for Malcontent Units Ancient Era Hammer By Hea Poh Lin for Worker Flag By Melvin Poppelaars for Settler Eagle By anggun for Scout Axe By ehab.abdullah for Warrior Haka By Josh for Maori Warrior Spiked Club by Hamish Bow And Arrow By Viktor Ostrovsky for Archer Bow By Arthur Shlain for Bowman Javelin By WEBTECHOPS LLP for Atlatlist arrows by Ayub Irawan for Skirmisher Fishing Vessel By Luis Prado for Work Boats Greek Trireme By Zachary McCune for Trireme Greek Trireme By Zachary McCune for Quinquereme. The original work has been modified. dragon by BGBOXXX Design for Dromon Viking Boat by Eucalyp for Galley Chariot By Andrew Doane for Chariot Archer Elephant By Luis Prado for War Elephant Centaur by Michael Wohlwend for Horse Archer Spear By Stephen Copinger for Spearman Greek shield for Hoplite ram by Becris for Battering Ram Spear by lastspark for Marauder Spiked club for Brute Hoplite by Eucalyp for Immortal Slingshot by James Keuning for Slinger warrior By DinosoftLab for Pictish Warrior (combined with Shamrock, see Promotions) Classical Era Catapult By Jakub Ukrop Unloaded Crossbow By Hamish as Ballista Bow and arrow By Lars Meiertoberens for Composite Bowman Sword By Guilherme Furtado for Swordsman Mohawk By Dairy Free Design for Mohawk Warrior Roman Helmet By parkjisun for Legion Horse By AFY Studio for Horseman Horse Head By Juan Pablo Bravo for Companion Cavalry Elephant By Angriawan Ditya Zulkarnain for African Forest Elephant. The original work has been modified. Horse By Ranah Pixel Studio for Cataphract Medieval Era Ship By Vanisha for Galleass Crossbow By Creaticca Creative Agency for Crossbowman Longbow By Hamish for Longbowman Trebuchet By Ben Davis Sword By uzeir syarief for Longswordsman Samurai By Chanut is Industries Spear By Alvaro Cabrera for Pikeman Halberd parkjisun for Landsknecht Knight By Tyler Glaude Renaissance Era Portuguese Caravel by Zack McCune for Caravel Cannon By Orin Zuu Musket By Cezary Lopacinski for Musketman Tarbouche By Mohamed Amine for Janissary Black powder musket By Jarem Fyre for Minuteman Rapier By Hamish for Musketeer Ship By Orin Zuu for Frigate Pirate by Berkah Icon for Privateer Pirate by Smalllike for Sea Beggar* Ship By Mungang Kim for Ship of the Line Lance By parkjisun for Lancer Sword By Daniela Baptista for Sipahi Helmet by Robert Bjurshagen for Hakkapeliitta Industrial Era Rifle By Chameleon Design for Rifleman Bayonet By food lover for Carolean soldier by ProSymbols for Mehal Sefari Horse By Bakunetso Kaito for Cavalry horse racing By Sergio Morozov for Cossack Marching Band by Darrin Loeliger, US for Hussar. The original work has been modified. Artillery By Creative Mania Ship By Aisyah for Ironclad Modern Era Submarine By Hea Poh Lin, MY Helmet By Daniel Turner for Great War Infantry Cap By Creative Mania for Foreign Legion xm8 By Xela Ub for Infantry Icon for Carrier made by JackRainy , based on Aircraft Carrier By IcoLabs, BR Battleship By Vitaliy Gorbachev, KZ for Battleship machine-gun By Joana Pereira for Machine Gun artillery by Izwar Muis for Anti-Aircraft Gun Tank By corpus delicti for Landship Warship By zidney for Destroyer Atomic Era Water Gun by ProSymbols for Marine Parachute by Nociconist for Paratrooper Tank By jeff for Tank Tank Manuel Dixken, DE for Panzer Anti-Tank Gun By Tom Fricker atomic bomb by AmruID for Atomic Bomb Military vehicle By Luke Anthony Firth For Rocket Artillery Missile By Eucalyp for Mobile SAM Information Era Submarine by Freepik adapted for Nuclear Submarine APC By Luke Anthony Firth for Mechanized Infantry Battleship by Edi Prastyo for Missile Cruiser Modern Armor By Public Domain Nouns for Modern Armor Nuclear Missile By Lluisa Iborra, ES Robot by Lluisa Iborra, ES for Giant Death Robot Missile By ProSymbols for SS Booster Rocket By BomSymbols for SS Cockpit Engine By Andre for SS Engine Chamber By IYIKON for SS Stasis Chamber All Eras Pallet By James Keuning for Great Artist Gear By Melvin Salas for Great Engineer Beaker By Delwar Hossain for Great Scientist Dove by sandra for Great Prophet General By anbileru adaleru for Great General Religion by Bruno G\u00e4tjens Gonz\u00e1lez adapted for Missionary invisibility cloak by Locad for Inquisitor Resources Saffron By parkjisun for Dye Can By Nick Bluth for Aluminum Coal By Michael Wohlwend Anvil By Jason Dilworth for Iron Deer By Richard Nixon Banana By Adrian Coquet Oil By Tiago Maricate (also as Civilopedia category icon) Statue By Joris Hoogendoorn for Marble Ribbon By Anton for Silk Stone By AFY Studio Goblet By Pedro Santos for Silver Sugar By ahmad Spice By ahmad Radiation symbol By icon 54 for Uranium Wine By Adrien Coquet Wheat By Juraj Sedlak Sheep By Unrecognized Elephant By Kelsey Armstrong for Ivory Cattle By Daniela Baptista Leather By Alen Krummenacher for Furs Gem By Lluisa Iborra Joss Stick By Hea Poh Lin for Incense Pottery By Laymik, UA for Porcelain Jewelry By Shocho, IN Lemons By sachin modgekar, IN for Citrus Pipes By Nibras@design for Copper Crab By YuguDesign Truffle By parkjisun Salt By HAMEL KHALED, DZ Improvements Woodcutting axe By Chanut is Industries for Lumber Mill Monument By Setyo Ari Wibowo for Landmark Farm By Bonnie Beach Bank By Scott Dunlap for Customs House Academy By CJS Factory By RULI for Manufactory Mine By Edward Boatman Corral By Luis Prado for Pasture Plants By hendra sudibyo for Plantation Pickaxe By Creative Stall for Quarry Food stall By I Putu Kharismayadi for Trading post Road By REVA Ruins By Creative Stall for Ancient runs Ruins By Paulo Volkova for City ruins Fishing Net By Made for Fishing Boats Moai By Template Fort By Adrien Coquet Citadel By Adrien Coquet Village by Andrey Vasiliev pumping station by Peter van Driel for Polder Buildings Ancient Era Storehouse By Pedro Santos for Granary Shinto Gate by Alexander Skowalsky for Shrine Pyramid by Oscar Y\u00e1\u00f1ez for Mayan Pyramid Great Wall Of China By Arthur Shlain for Walls Markadan Tower by Vectors Market for Walls of Babylon Block By Monjin Friends for Stone Works korean palace By 1516 for Palace Obelisk By Eliricon for Monument obelisk By IconMark for Stele Cross swords By Creaticca Creative Agency for Barracks Fortress By Creative Stall for Krepost Paper By anam Circus By Ralph Schmitzer Stonehenge By icon 54 Ho Chi Minh mausoleum By Ph\u1ea1m Thanh L\u1ed9c for Mausoleum of Halicarnassus Icon for Statue of Zeus made by JackRainy , based on King By Eucalyp temple By Fabio Meroni for Temple of Artemis Classical Era Lighthouse By Dolly Holmes Lighthouse By Hea Poh Lin for The Great Lighthouse Temple By 1516 Anubis By Carpe Diem for Burial Tomb Parthenon By Christopher T. Howlett for The Oracle Stadium By sandra for Colosseum Terracotta Army By Ph\u1ea1m Thanh L\u1ed9c Stadium By Creaticca Creative Agency for Circus Maximus Market By sofi Bazaar By Tokka Elkholy Shekel Coin By Till Teenck for Mint Aqueduct By Arthur Shlain Great Wall By icon 54 Rice Field by Graphic Engineer for Terrace farm Canoe By Viktor Fedyuk (Tim P) for Floating Gardens Arc de Triomphe By Andrejs Kirma, LV for National Epic Bank by By P Thanga Vignesh for National Treasury Judge By Kriszti\u00e1n M\u00e1ty\u00e1s for Courthouse Petra By Ranah Pixel Studio for Petra Medieval Era College By Alexander Skowalsky for University Wat Arun Ratchawararam Ratchawaramahawihan By J\u00f3zsef Bal\u00e1zs-Heged\u00fcs for Wat College By Vectors Market for National College Chichen Itza By Hea Poh Lin Castle By Mint Shirt Red Fort , Gateway of India By Arunabh Jain, IN for Mughal Fort Angkor Wat By Ph\u1ea1m Thanh L\u1ed9c for Angkor Wat Alhambra By Ph\u1ea1m Thanh L\u1ed9c Books By Abir Alward for Oxford University Forge By Monjin Friends Anchor By Saeful Muslim for Harbor Hand saw By b farias for Workshop House By sofy for Longhouse Hagia Sophia By Felipe Alvarado Factory By Maxim Kulikov for Ironworks Notre Dame By Marco Livolsi Shield and Swords By Alina Oleynik for Armory Machu Picchu By Chanut is Industries Garden By Bharat Mosque by yanti for Great Mosque of Djenne Renaissance Era Museum by zidney Hermitage By Yuri Mamaev The Louvre By roundicons.com Forbidden City By 1516 Theatre By b farias Tower of Pisa By Pedro Santos Himeji Castle By Chanut is Industries Windmill By corpus delicti Coffee by SURYANI, ID for Coffee House Taj Mahal By Felipe Alvarado Observatory By Nathan Driskell Opera House By Xinh Studio Chinese traditional tower By 1516 for Porcelain Tower Bank By projecthayat Harbor By Rflor for Seaport Mansion by Freepik for Satrap's Court Bullets By Aldric Rodriguez for Arsenal St. Petersburg By Carpe Diem for Kremlin Ceilidh By P Thanga Vignesh for Ceilidh Hall Industrial Era Books By Minh Do for Public School Hospital By Adrien Coquet Stock exchange By Pundimon Military By myiconfinder for Military Academy Factory By icon 54 Modern Era Stadium By Karuna Lalvani Signal Tower By Nociconist for Broadcast Tower Hangar By Rflor for Military Base Eiffel Tower By Felipe Alvarado Statue of Liberty By 1516 Microscope By Arafat Uddin for Research Lab Christ the redeemer By Stefan Spieler for Cristo Redentor Neuschwanstein By Vectors Market Big Ben By Ben Davis, RO Atomic Era Chemistry By Creative Stall for Medical Lab Pentagon By Maxim Kulikov Solar panel By Modik for Solar Plant Recycle By Umer Younas, PK for Recycling Center Opera House Sydney By Pham Duy Phuong Hung for Sydney Opera House Water dam By Symbolon for Hydro Plant Manhattan Project By corpus delicti, GR Nuclear Plant By Andrejs Kirma Spaceship By Dinosoft Labs for Apollo Program Information Era CN Tower Toronto By mikicon for CN tower War Shelter by Frepik for Bomb Shelter Hubble Telescope By Scott Lewis for Hubble Space Telescope Build By Michael G Brown for Spaceship Factory United Nations by Imam for United Nations All Era's Illuminati by emilegraphics for the Utopia Project Christian Church by Andrejs Kirma for Monastery cathedral by Pixel Bazaar for Cathedral Mosque by yanti for Mosque Pagoda by Xinh Studio for Pagoda Social Policies Tradition coat of arms By Martina Krasnayova for Oligarchy Apple By EnQiu for Landed Elite Crown By Alexander Skowalsky for Monarchy Pyramid By Creative Stall for Aristocracy Gavel By Rflor for Legalism Liberty People By Elizabeth Lopez for Citizenship Assembly By No\u00ebl Rasendrason for Republic People By Gregor Cresnar for Meritocracy People By Wilson Joseph for Representation Torch By Hea Poh Lin for Collective Rule Honor Sword By dsathiyaraj for Military Tradition Castle By Gabriele Malaspina for Military Caste Roman Armor By Parkjisun for Professional Army Shield By Kimmi Studio for Discipline Spartan Helmet By Joni Ramadhan for Warrior Code Piety Protestantism By Evgeni Moryakov for Reformation Temple By N.K.Narasimhan for Theocracy Religion By Ben Avery for Free Religion Flame By Ian Shoobridge for Mandate Of Heaven Patronage Adapted from Gold by Aneeque Ahmed for Philantropy Ornament by Tommy Suhartomo for Aesthetics Book Gift by Wolf B\u00f6se for Scholasticism agreement by RomanP for Cultural Diplomacy professor by Andrew Doane for Educated Elite Commerce Trade By Gregor Cresnar for Trade Unions Pie Chart By Adrien Coquet for Protectionism Coins By icon 54 for Mercantilism Sextant By lastspark for Naval Tradition captain by taamir468 and Wheel by Andrejs Kirma for Merchant Navy Rationalism Science By Three Six Five for Scientific Revolution Graph By Ben Davis for Secularism Logic By Jenya K for Sovereignty Dialogue By ProSymbols for Free Thought Logic By Arthur Shlain for Humanism Freedom Social Network By Kirby Wu for Civil Society Gender Equality By corpus delicti for Universal Suffrage Feather By Eduardo Souza for Constitution Voting By Nikita Kozin for Democracy Mic By Aybige for Free Speech Autocracy War By Abdul Karim for Total War Military Grade By Ben Davis for Militarism Military Medal By iconsphere for Fascism Newspaper By Trishul for Populism Riot Police By Dan Hetteix for Police State Order Adapted from Plan by Cattaleeya Thongsriphong for Planned Economy Flag by Muhammad Tajudin for Nationalism Communism By Valerio Poltrini for Socialism Hammer and Sickle by Dmitry Baranovskiy for Communism United by Izwar Muis for United Front Technologies Ancient Agriculture By OCHA Visual Information Unit Jug By Vladimir Belochkin for Pottery Archery By icon 54 Mining By art shop Sailing By Daniela Baptista Sundial By Bonegolem for Calendar Cuneiform By Michael Wohlwend for Writing Trap By Sergey Demushkin for Trapping innovative By Matt Brooks for The Wheel Bricks By Vaibhav Radhakrishnan for Construction Mallet By Ben Avery for Bronze Working Classical Telescope for Optics Horse Riding By Hea Poh Lin for Horseback Riding Abacus By Yo! Baba for Mathematics Arch By Andrejs Kirma for Construction Brain By Tony Gines for Philosophy Coins By Adrien Coquet for Currency Engineering Blueprint By Sachin Modgekar for Engineering Metalworking By Symbolon for Iron Working Medieval Judaism By Ben Davis for Theology Institution By Luis Prado for Civil Service Compass By Bernar Novalyi Education By Tomas Knopp Casting By Jasmine Rae Friedrich Bar association By Miroslav Kurdov for Guilds Knight By Robert Bjurshagen for Chivalry Camel By Orin Zuu for Camel Archer Machinery By Greenhill Lever By Jakob Ukrop for Physics Sword By Jonathan P Lambert for Steel Renaissance Telescope By ProSymbols for Astronomy Sound waves By Makarenko Andrey for Acoustics Banking By Delwar Hossein Printing Press By Mike Wirth Flintlock By Madison Apple for Gunpowder Fossil By Raf Verbraeken for Archaeology Sextant By lastspark for Navigation Architecture By Andrew Doane Money Growth By DesignNex for Economics Metal Block By Creaticca Creative Agency for Metallurgy Chemistry By Creative Stall Industrial Science By Dinosoft Labs for Scientific Theory Factory By Lil Squid for Industrialization Rifle By Alexander Skowalsky for Rifling Grenade By Dama Adhikara for Military Science Fertilizer By Jae Deasigner Bacteria By Maxim Kulikov for Biology Electricity By Ben Davis Turbines By Leonardo Schneider for Steam Power Dynamite By Simon Martin Modern Gears By Aiden Icons for Replaceable Parts Radio By Arthur Shlain Piston By Proletkult Graphik for Combustion Plastic By Yu luck Microphone By Viktor Vorobyev for Mass Media Flight By Genius Icons Train By Federico Panzano for Railroad Fridge By b farias for Refrigeration telegraph by Luke Anthony Firth for Telegraph* Atomic Pill By Alex Arseneau for Pharmaceuticals Satellite Dish By Vectors Market for Radar Ecology By ProSymbols Nuclear Reactor By Jeremie Sommet for Nuclear Fission Rocket By kareemov for Rocketry Computer By Shastry for Computers Information telecommunications by Wichai Wi for Telcommunications Tactics By Grafix Point for Mobile Tactics Rocket Kusdarti for Advanced Ballistics Satellite By Ben Davis for Satellites Robotic Arm By Karl Gilbert for Robotics Laser by Andrew Doane for Lasers global by Rank Sol for Globilization Atom By Kelsey Armstrong for Particle Physics Nanoparticles By Gyan Lakhwani for Nanotechnology Thermonuclear fusion by Olena Panasovska, UA for Nuclear Fusion Electronics By Cuby Design Radar By CINDYFLA, ID for Stealth Future Information Technology By Vectors Markeet for Future Tech Terrain Hills By Juraj Sedl\u00e1k Mountains By icon 54 Forest by Milinda Courey for Jungle Forest By Lance B Palm Tree By Tatiana for Oasis Water By Kozan for Marsh Harvest By Made for Flood plains Puddle By Bakunetsu Kaito for Lakes Island By Chanut is Industries for Atoll Iceberg By Jaime Carrion for Ice Nations Eye of Horus By Lilit Kalachyan for Egypt Russia By Eugen Belyakoff Dragon Head By Ravignir for China Lion By parkjisun for Babylon Omega By icon 54 for Greece Shield By Nathan Driskell for America Fleaur de Lis By Jessika Gadoury for France Crown By Peter van Driel for England Wreath by VectorBakery or Roman Iron Cross By Souvik Maity for Germany Star and Crecent for Arabia Family Crest Komon by sahua d for Japan Ashika Chakra by sahua d for India Variation on crescent moon by Estu Suhartono for The Ottomans Korea by CJS for Korea Two Sword Scimitars by Those Icons for Persia Swirl by IronSV for Polynesia Dharmachakra by Parkjisun for Siam Inca by Ravignir for Inca Sun symbol black by Eddo for The Huns Lion by Nikki Rodriguez for The Netherlands Three Crowns by Daniel Falk for Sweden Flag of Austria by Olena Panasovska, UA for Austria. The original work has been modified. Elephant by Hea Poh Lin for Carthage. The original work has been modified. Orthodox Cross by Avana Vana for Byzantium Iroquois by Ravignir for Iroquois Songhai by Ravignir for Songhai Celtic Knot by Ervin Bolat for the Celts Ethiopian Icon created in Gimp by Unciv team from the following: Lion by IronSV royal crown by Vectors Market Spear by Firza Alamsyah pennant by Sara Jeffries Maya civilization by Olena Panasovska for The Maya Promotions Sight By Jejen Juliansyah Nur Agung for Scouting skill bow rain arrow by Maxicons for Barrage Bomb By Angelo Troiano for Bombardment Private E2 By Yeong Rong Kim for Shock Private First Class By Yeong Rong Kim for Drill Medic By Yohann Berger for Medic City By iconcheese for Siege Skull and Crossbones By Anton Outkine for Coastal Raider Spear By Deemak Daksina for Formation Wall By Graphic Tigers for Volley Lightning By Mooms for Blitz Move By Sandra for Mobility accuracy By vigtographics for Targeting location by Humantech for Accuracy Plane By Tran Minh Villageois for Interception Hammer by Thengakola for Air Repair Hook By Yeong Rong Kim for Boarding Party Leaf By Paul Verhulst for Indirect Fire Move By Muneer A.Safiah for Logistics Evasion By Anna Sophie for Evasion Interrupt by Stephen Plaster for Ambush Submarine by Lloyd Humphreys for Wolfpack Axe by Brian Oppenlander for Woodsman Competition by luca fruzza Icon for Flight Deck is made by JackRainy Icon for Armor Plating is made by JackRainy Slingshot by James Keuning for Slinger Withdraw Anchor by Gregor Cresnar for Amphibious survival knife by b faris for Survivalism Shamrock By P Thanga Vignesh for Pictish Courage home sweet home By Silviu Ojog for Home Sweet Home Religions Lightning Bolt by sian huxtable for Pantheon Christianity by Public Domain Nouns for Christianity Islam by Muhammed Riza for Islam taoism by parkjisun for Taosim Buddhism by Julio Yanes for Buddhism Hinduism by Mugda Damle for Hinduism Confucianism by Dabid J. Pascual for Confucianism Judaism by Dabid J. Pascual for Judaism Shinto by Dabid J. Pascual for Shinto Sikhism by Dabid J. Pascual for Sikhism Tengrism by Dabid J. Pascual for Tengriism Zoroastrianism by Dabid J. Pascual for Zoroastrianism praying by parkjisun for Religion (Civilopedia concept entry) praying by Gan Khoon Lay for Follower Hero by Andrew J. Young for Founder yell by Adrien Coquet for Enhancer Others Circle By Aybige Arrow By Joe Mortell for movement Swap By iconomania for swapping units Connection By Travis Avery Skull By Vladimir Belochkin for disbanding units Crosshair By Bakunetsu Kaito for selecting enemies to attack City By Felix Westphal Fire By Lloyd Humphreys for \"city being razed\" icon Sleep By Saeful Muslim Banner By Emir Palavan for embarked units Arrow By uzeir syarief for moving between idle units Replace By Mike Rowe for switching tiles between cities Resistance By HeadsOfBirds Viking Hat By my name is mud for pillaging improvements Aim By Kaviashri for ranged strength Capitol By Loren Klein for City-States Aircraft By Tom Fricker for aircraft icon in city button radar scan By icon 54 for Range short range radar by Vectors Point for Intercept range Puppet By Ben Davis for puppeted cities City By Muhajir ila Robbi in the Icon center Lock by Vadim Solomakhin for locked tiles Hourglass by I Create Stuff for the 'Turn' icon Shield by Gregor Cresnar for Religious Strength skill sword flame by Maxicons) for Remove Heresy Pencil by Muhamad Aldi Maulana for Enter Text Prompt Button / Pencil Parchment by hans draiman for Cultured City-States connection by Popular for Mercantile City-States crossed sword by ProSymbols for Militaristic City-States ship helm by Vectors Market for Maritime City-States Magnifying Glass by John Caserta for Mod filter tick by Adrien Coquet on Nation picker people by Wilson Joseph as base for Civilopedia category Nations Mountains by Andrew J. Young as base for Civilopedia category Terrains File:Maya.svg for Mayan numerals East side of stela C, Quirigua for Mayan calendar symbols Footprints by Abdul Wahhab for movement overlay toggle, slightly modified. Currently unused. Arrows.svg by Intralexical (@will-ca), CC0. Main menu Lightning by Rohith M S for Quickstart Loading by Universal Icons for Load Game New by Alice Design for New Game Go back by Salvia Santos for Resume Multiplayer by Roy Charles Options By Thengakola Package by shashank singh Sound credits Sounds are from FreeSound.org unless otherwise noted and are either Creative Commons or Public Domain unless otherwise noted Soft two-fingered snap By EathanMarkson as 'click' for most clicks Pencil1 By stijn as 'paper' for opening and closing the tech picker SawInOut01 By kingof_thelab for construction picking? Chain Snare #1 By lovesbody as 'fortify' Level up By Marregheriti as 'upgrade' for upgrading units levelup By Seidhepriest as 'chimes' for special actions (free tech, build city, hurry wonder etc.) Coin By TheDJoe93 as 'coin' for purchasing tiles and constructions fast simple chop 1 By dave.dev as 'whoosh' for moving units around, also in edited form to produce the 'swap units' sound. Military kick By Dodgy C as 'promote' for unit promotions Tank reload By KieranKeegan as 'setup' for siege unit setup Scribble_short By waldram as 'policy' for adopting policies Hit Impact by Mrguff as 'throw' for catapult & trebuchet attacks Slingshot fly by 2 by saturdaysoundguy as 'arrow' for arrow attacks Metal hit slide by orginaljun as 'nonmetalhit' for pre-metal melee sounds klick_anlauf By jascha as 'metalhit' for metal melee sounds Horse's whinny By Kubuzz as 'horse' for cavalry attack sounds machine gun 001 - loop By pgi as 'machinegun' for machine gun attack sound uzzi_full_single By Deganoth as 'shot' for bullet attacks Grenade Launcher 2 By Daniel Simon as city bombard sound (CC Attribution 3.0 license) Woosh by Mark DiAngelo as 'slider' sound (CC Attribution 3.0 license) Tornado-Siren-II by Delilah as part of 'nuke' sound (CC Attribution 3.0 license) Explosion-Ultra-Bass by Mark DiAngelo as part of 'nuke' sound (CC Attribution 3.0 license) Short Choir by Breviceps as 'choir' for free great person pick Death Robot! Robotic scream by vultraz168 for Giant Death Robot Attack (CC0 1.0 Universal license) ceremonial cannon fire by DylanSmithSound for cannon artillery fire by Tomashevsky for artillery 20mm cannons by Piotr123 for ship guns \"bombing\" is made by the Unciv team using Audacity from lancaster bomber by confusion_music - aircraft Artillery Explosion (Close) (Mixed) by EFlexMusic - impact SFX Hit drop/bomb effect 5 by old_waveplay - bass \"jetgun\" for Jet Fighter attack is made by the Unciv team using Audacity from Fighter Jet Aircraft Fly by (synthesised) by Headphaze Machine Gun 001 - triple shot by pgi Excerpt from Tanks Shooting by qubodup for tankshot \"torpedo\" is made by the Unciv team using Audacity from Torpedo launch underwater by jobro Artillery Explosion (Close) (Mixed) by EFlexMusic elephant 44 by y89312 for Naruesan's Elephant sound Excerpt from Missile Strike by BaDoink for guided missile Excerpt from FireBurning_v2.wav by pcaeldries for 'remove heresy' action of inquisitor ( License ) Music The following music is from https://filmmusic.io \" Thatched Villagers \" by Kevin MacLeod (https://incompetech.com)","title":"Icon Credits"},{"location":"Credits/#icon-credits","text":"Flag Icons made by Freepik from www.flaticon.com and licensed by Creative Commons 3.0 New Unciv logo made by u-ndefined on Discord Base tile icons for the \"Fantasy Hex\" tileset belong to CuddlyClover @ https://cuddlyclover.itch.io/fantasy-hex-tiles with a few additions by me Trees for the jungle tiles in the \"Fantasy Hex\" are extracted from Desert Strike for the Amiga Almost all the improvements and units made by The Bucketeer on Discord Tile icons for the \"ThorfMaps tileset belong to Thorfinn Tait and are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Based on work at www.thorfmaps.com. Unless otherwise specified, all the following are from the Noun Project licenced under either Creative Commons or Public Domain","title":"Icon Credits"},{"location":"Credits/#stat-icons","text":"Gear by Alex Bickov for Production Apple by Pedro Gon\u00e7alves for Food gold by Eliricon for Gold Beaker by Delwar Hossain for Science Music by Naomi Atkinson for Culture Smiley by Alexander Skowalsky for Happiness Dove by Sandra for Faith User by St\u00e9phanie Rusch for Population Unhappy By Daryl Vandermont for Malcontent","title":"Stat icons"},{"location":"Credits/#units","text":"","title":"Units"},{"location":"Credits/#ancient-era","text":"Hammer By Hea Poh Lin for Worker Flag By Melvin Poppelaars for Settler Eagle By anggun for Scout Axe By ehab.abdullah for Warrior Haka By Josh for Maori Warrior Spiked Club by Hamish Bow And Arrow By Viktor Ostrovsky for Archer Bow By Arthur Shlain for Bowman Javelin By WEBTECHOPS LLP for Atlatlist arrows by Ayub Irawan for Skirmisher Fishing Vessel By Luis Prado for Work Boats Greek Trireme By Zachary McCune for Trireme Greek Trireme By Zachary McCune for Quinquereme. The original work has been modified. dragon by BGBOXXX Design for Dromon Viking Boat by Eucalyp for Galley Chariot By Andrew Doane for Chariot Archer Elephant By Luis Prado for War Elephant Centaur by Michael Wohlwend for Horse Archer Spear By Stephen Copinger for Spearman Greek shield for Hoplite ram by Becris for Battering Ram Spear by lastspark for Marauder Spiked club for Brute Hoplite by Eucalyp for Immortal Slingshot by James Keuning for Slinger warrior By DinosoftLab for Pictish Warrior (combined with Shamrock, see Promotions)","title":"Ancient Era"},{"location":"Credits/#classical-era","text":"Catapult By Jakub Ukrop Unloaded Crossbow By Hamish as Ballista Bow and arrow By Lars Meiertoberens for Composite Bowman Sword By Guilherme Furtado for Swordsman Mohawk By Dairy Free Design for Mohawk Warrior Roman Helmet By parkjisun for Legion Horse By AFY Studio for Horseman Horse Head By Juan Pablo Bravo for Companion Cavalry Elephant By Angriawan Ditya Zulkarnain for African Forest Elephant. The original work has been modified. Horse By Ranah Pixel Studio for Cataphract","title":"Classical Era"},{"location":"Credits/#medieval-era","text":"Ship By Vanisha for Galleass Crossbow By Creaticca Creative Agency for Crossbowman Longbow By Hamish for Longbowman Trebuchet By Ben Davis Sword By uzeir syarief for Longswordsman Samurai By Chanut is Industries Spear By Alvaro Cabrera for Pikeman Halberd parkjisun for Landsknecht Knight By Tyler Glaude","title":"Medieval Era"},{"location":"Credits/#renaissance-era","text":"Portuguese Caravel by Zack McCune for Caravel Cannon By Orin Zuu Musket By Cezary Lopacinski for Musketman Tarbouche By Mohamed Amine for Janissary Black powder musket By Jarem Fyre for Minuteman Rapier By Hamish for Musketeer Ship By Orin Zuu for Frigate Pirate by Berkah Icon for Privateer Pirate by Smalllike for Sea Beggar* Ship By Mungang Kim for Ship of the Line Lance By parkjisun for Lancer Sword By Daniela Baptista for Sipahi Helmet by Robert Bjurshagen for Hakkapeliitta","title":"Renaissance Era"},{"location":"Credits/#industrial-era","text":"Rifle By Chameleon Design for Rifleman Bayonet By food lover for Carolean soldier by ProSymbols for Mehal Sefari Horse By Bakunetso Kaito for Cavalry horse racing By Sergio Morozov for Cossack Marching Band by Darrin Loeliger, US for Hussar. The original work has been modified. Artillery By Creative Mania Ship By Aisyah for Ironclad","title":"Industrial Era"},{"location":"Credits/#modern-era","text":"Submarine By Hea Poh Lin, MY Helmet By Daniel Turner for Great War Infantry Cap By Creative Mania for Foreign Legion xm8 By Xela Ub for Infantry Icon for Carrier made by JackRainy , based on Aircraft Carrier By IcoLabs, BR Battleship By Vitaliy Gorbachev, KZ for Battleship machine-gun By Joana Pereira for Machine Gun artillery by Izwar Muis for Anti-Aircraft Gun Tank By corpus delicti for Landship Warship By zidney for Destroyer","title":"Modern Era"},{"location":"Credits/#atomic-era","text":"Water Gun by ProSymbols for Marine Parachute by Nociconist for Paratrooper Tank By jeff for Tank Tank Manuel Dixken, DE for Panzer Anti-Tank Gun By Tom Fricker atomic bomb by AmruID for Atomic Bomb Military vehicle By Luke Anthony Firth For Rocket Artillery Missile By Eucalyp for Mobile SAM","title":"Atomic Era"},{"location":"Credits/#information-era","text":"Submarine by Freepik adapted for Nuclear Submarine APC By Luke Anthony Firth for Mechanized Infantry Battleship by Edi Prastyo for Missile Cruiser Modern Armor By Public Domain Nouns for Modern Armor Nuclear Missile By Lluisa Iborra, ES Robot by Lluisa Iborra, ES for Giant Death Robot Missile By ProSymbols for SS Booster Rocket By BomSymbols for SS Cockpit Engine By Andre for SS Engine Chamber By IYIKON for SS Stasis Chamber","title":"Information Era"},{"location":"Credits/#all-eras","text":"Pallet By James Keuning for Great Artist Gear By Melvin Salas for Great Engineer Beaker By Delwar Hossain for Great Scientist Dove by sandra for Great Prophet General By anbileru adaleru for Great General Religion by Bruno G\u00e4tjens Gonz\u00e1lez adapted for Missionary invisibility cloak by Locad for Inquisitor","title":"All Eras"},{"location":"Credits/#resources","text":"Saffron By parkjisun for Dye Can By Nick Bluth for Aluminum Coal By Michael Wohlwend Anvil By Jason Dilworth for Iron Deer By Richard Nixon Banana By Adrian Coquet Oil By Tiago Maricate (also as Civilopedia category icon) Statue By Joris Hoogendoorn for Marble Ribbon By Anton for Silk Stone By AFY Studio Goblet By Pedro Santos for Silver Sugar By ahmad Spice By ahmad Radiation symbol By icon 54 for Uranium Wine By Adrien Coquet Wheat By Juraj Sedlak Sheep By Unrecognized Elephant By Kelsey Armstrong for Ivory Cattle By Daniela Baptista Leather By Alen Krummenacher for Furs Gem By Lluisa Iborra Joss Stick By Hea Poh Lin for Incense Pottery By Laymik, UA for Porcelain Jewelry By Shocho, IN Lemons By sachin modgekar, IN for Citrus Pipes By Nibras@design for Copper Crab By YuguDesign Truffle By parkjisun Salt By HAMEL KHALED, DZ","title":"Resources"},{"location":"Credits/#improvements","text":"Woodcutting axe By Chanut is Industries for Lumber Mill Monument By Setyo Ari Wibowo for Landmark Farm By Bonnie Beach Bank By Scott Dunlap for Customs House Academy By CJS Factory By RULI for Manufactory Mine By Edward Boatman Corral By Luis Prado for Pasture Plants By hendra sudibyo for Plantation Pickaxe By Creative Stall for Quarry Food stall By I Putu Kharismayadi for Trading post Road By REVA Ruins By Creative Stall for Ancient runs Ruins By Paulo Volkova for City ruins Fishing Net By Made for Fishing Boats Moai By Template Fort By Adrien Coquet Citadel By Adrien Coquet Village by Andrey Vasiliev pumping station by Peter van Driel for Polder","title":"Improvements"},{"location":"Credits/#buildings","text":"","title":"Buildings"},{"location":"Credits/#ancient-era_1","text":"Storehouse By Pedro Santos for Granary Shinto Gate by Alexander Skowalsky for Shrine Pyramid by Oscar Y\u00e1\u00f1ez for Mayan Pyramid Great Wall Of China By Arthur Shlain for Walls Markadan Tower by Vectors Market for Walls of Babylon Block By Monjin Friends for Stone Works korean palace By 1516 for Palace Obelisk By Eliricon for Monument obelisk By IconMark for Stele Cross swords By Creaticca Creative Agency for Barracks Fortress By Creative Stall for Krepost Paper By anam Circus By Ralph Schmitzer Stonehenge By icon 54 Ho Chi Minh mausoleum By Ph\u1ea1m Thanh L\u1ed9c for Mausoleum of Halicarnassus Icon for Statue of Zeus made by JackRainy , based on King By Eucalyp temple By Fabio Meroni for Temple of Artemis","title":"Ancient Era"},{"location":"Credits/#classical-era_1","text":"Lighthouse By Dolly Holmes Lighthouse By Hea Poh Lin for The Great Lighthouse Temple By 1516 Anubis By Carpe Diem for Burial Tomb Parthenon By Christopher T. Howlett for The Oracle Stadium By sandra for Colosseum Terracotta Army By Ph\u1ea1m Thanh L\u1ed9c Stadium By Creaticca Creative Agency for Circus Maximus Market By sofi Bazaar By Tokka Elkholy Shekel Coin By Till Teenck for Mint Aqueduct By Arthur Shlain Great Wall By icon 54 Rice Field by Graphic Engineer for Terrace farm Canoe By Viktor Fedyuk (Tim P) for Floating Gardens Arc de Triomphe By Andrejs Kirma, LV for National Epic Bank by By P Thanga Vignesh for National Treasury Judge By Kriszti\u00e1n M\u00e1ty\u00e1s for Courthouse Petra By Ranah Pixel Studio for Petra","title":"Classical Era"},{"location":"Credits/#medieval-era_1","text":"College By Alexander Skowalsky for University Wat Arun Ratchawararam Ratchawaramahawihan By J\u00f3zsef Bal\u00e1zs-Heged\u00fcs for Wat College By Vectors Market for National College Chichen Itza By Hea Poh Lin Castle By Mint Shirt Red Fort , Gateway of India By Arunabh Jain, IN for Mughal Fort Angkor Wat By Ph\u1ea1m Thanh L\u1ed9c for Angkor Wat Alhambra By Ph\u1ea1m Thanh L\u1ed9c Books By Abir Alward for Oxford University Forge By Monjin Friends Anchor By Saeful Muslim for Harbor Hand saw By b farias for Workshop House By sofy for Longhouse Hagia Sophia By Felipe Alvarado Factory By Maxim Kulikov for Ironworks Notre Dame By Marco Livolsi Shield and Swords By Alina Oleynik for Armory Machu Picchu By Chanut is Industries Garden By Bharat Mosque by yanti for Great Mosque of Djenne","title":"Medieval Era"},{"location":"Credits/#renaissance-era_1","text":"Museum by zidney Hermitage By Yuri Mamaev The Louvre By roundicons.com Forbidden City By 1516 Theatre By b farias Tower of Pisa By Pedro Santos Himeji Castle By Chanut is Industries Windmill By corpus delicti Coffee by SURYANI, ID for Coffee House Taj Mahal By Felipe Alvarado Observatory By Nathan Driskell Opera House By Xinh Studio Chinese traditional tower By 1516 for Porcelain Tower Bank By projecthayat Harbor By Rflor for Seaport Mansion by Freepik for Satrap's Court Bullets By Aldric Rodriguez for Arsenal St. Petersburg By Carpe Diem for Kremlin Ceilidh By P Thanga Vignesh for Ceilidh Hall","title":"Renaissance Era"},{"location":"Credits/#industrial-era_1","text":"Books By Minh Do for Public School Hospital By Adrien Coquet Stock exchange By Pundimon Military By myiconfinder for Military Academy Factory By icon 54","title":"Industrial Era"},{"location":"Credits/#modern-era_1","text":"Stadium By Karuna Lalvani Signal Tower By Nociconist for Broadcast Tower Hangar By Rflor for Military Base Eiffel Tower By Felipe Alvarado Statue of Liberty By 1516 Microscope By Arafat Uddin for Research Lab Christ the redeemer By Stefan Spieler for Cristo Redentor Neuschwanstein By Vectors Market Big Ben By Ben Davis, RO","title":"Modern Era"},{"location":"Credits/#atomic-era_1","text":"Chemistry By Creative Stall for Medical Lab Pentagon By Maxim Kulikov Solar panel By Modik for Solar Plant Recycle By Umer Younas, PK for Recycling Center Opera House Sydney By Pham Duy Phuong Hung for Sydney Opera House Water dam By Symbolon for Hydro Plant Manhattan Project By corpus delicti, GR Nuclear Plant By Andrejs Kirma Spaceship By Dinosoft Labs for Apollo Program","title":"Atomic Era"},{"location":"Credits/#information-era_1","text":"CN Tower Toronto By mikicon for CN tower War Shelter by Frepik for Bomb Shelter Hubble Telescope By Scott Lewis for Hubble Space Telescope Build By Michael G Brown for Spaceship Factory United Nations by Imam for United Nations","title":"Information Era"},{"location":"Credits/#all-eras_1","text":"Illuminati by emilegraphics for the Utopia Project Christian Church by Andrejs Kirma for Monastery cathedral by Pixel Bazaar for Cathedral Mosque by yanti for Mosque Pagoda by Xinh Studio for Pagoda","title":"All Era's"},{"location":"Credits/#social-policies","text":"","title":"Social Policies"},{"location":"Credits/#tradition","text":"coat of arms By Martina Krasnayova for Oligarchy Apple By EnQiu for Landed Elite Crown By Alexander Skowalsky for Monarchy Pyramid By Creative Stall for Aristocracy Gavel By Rflor for Legalism","title":"Tradition"},{"location":"Credits/#liberty","text":"People By Elizabeth Lopez for Citizenship Assembly By No\u00ebl Rasendrason for Republic People By Gregor Cresnar for Meritocracy People By Wilson Joseph for Representation Torch By Hea Poh Lin for Collective Rule","title":"Liberty"},{"location":"Credits/#honor","text":"Sword By dsathiyaraj for Military Tradition Castle By Gabriele Malaspina for Military Caste Roman Armor By Parkjisun for Professional Army Shield By Kimmi Studio for Discipline Spartan Helmet By Joni Ramadhan for Warrior Code","title":"Honor"},{"location":"Credits/#piety","text":"Protestantism By Evgeni Moryakov for Reformation Temple By N.K.Narasimhan for Theocracy Religion By Ben Avery for Free Religion Flame By Ian Shoobridge for Mandate Of Heaven","title":"Piety"},{"location":"Credits/#patronage","text":"Adapted from Gold by Aneeque Ahmed for Philantropy Ornament by Tommy Suhartomo for Aesthetics Book Gift by Wolf B\u00f6se for Scholasticism agreement by RomanP for Cultural Diplomacy professor by Andrew Doane for Educated Elite","title":"Patronage"},{"location":"Credits/#commerce","text":"Trade By Gregor Cresnar for Trade Unions Pie Chart By Adrien Coquet for Protectionism Coins By icon 54 for Mercantilism Sextant By lastspark for Naval Tradition captain by taamir468 and Wheel by Andrejs Kirma for Merchant Navy","title":"Commerce"},{"location":"Credits/#rationalism","text":"Science By Three Six Five for Scientific Revolution Graph By Ben Davis for Secularism Logic By Jenya K for Sovereignty Dialogue By ProSymbols for Free Thought Logic By Arthur Shlain for Humanism","title":"Rationalism"},{"location":"Credits/#freedom","text":"Social Network By Kirby Wu for Civil Society Gender Equality By corpus delicti for Universal Suffrage Feather By Eduardo Souza for Constitution Voting By Nikita Kozin for Democracy Mic By Aybige for Free Speech","title":"Freedom"},{"location":"Credits/#autocracy","text":"War By Abdul Karim for Total War Military Grade By Ben Davis for Militarism Military Medal By iconsphere for Fascism Newspaper By Trishul for Populism Riot Police By Dan Hetteix for Police State","title":"Autocracy"},{"location":"Credits/#order","text":"Adapted from Plan by Cattaleeya Thongsriphong for Planned Economy Flag by Muhammad Tajudin for Nationalism Communism By Valerio Poltrini for Socialism Hammer and Sickle by Dmitry Baranovskiy for Communism United by Izwar Muis for United Front","title":"Order"},{"location":"Credits/#technologies","text":"","title":"Technologies"},{"location":"Credits/#ancient","text":"Agriculture By OCHA Visual Information Unit Jug By Vladimir Belochkin for Pottery Archery By icon 54 Mining By art shop Sailing By Daniela Baptista Sundial By Bonegolem for Calendar Cuneiform By Michael Wohlwend for Writing Trap By Sergey Demushkin for Trapping innovative By Matt Brooks for The Wheel Bricks By Vaibhav Radhakrishnan for Construction Mallet By Ben Avery for Bronze Working","title":"Ancient"},{"location":"Credits/#classical","text":"Telescope for Optics Horse Riding By Hea Poh Lin for Horseback Riding Abacus By Yo! Baba for Mathematics Arch By Andrejs Kirma for Construction Brain By Tony Gines for Philosophy Coins By Adrien Coquet for Currency Engineering Blueprint By Sachin Modgekar for Engineering Metalworking By Symbolon for Iron Working","title":"Classical"},{"location":"Credits/#medieval","text":"Judaism By Ben Davis for Theology Institution By Luis Prado for Civil Service Compass By Bernar Novalyi Education By Tomas Knopp Casting By Jasmine Rae Friedrich Bar association By Miroslav Kurdov for Guilds Knight By Robert Bjurshagen for Chivalry Camel By Orin Zuu for Camel Archer Machinery By Greenhill Lever By Jakob Ukrop for Physics Sword By Jonathan P Lambert for Steel","title":"Medieval"},{"location":"Credits/#renaissance","text":"Telescope By ProSymbols for Astronomy Sound waves By Makarenko Andrey for Acoustics Banking By Delwar Hossein Printing Press By Mike Wirth Flintlock By Madison Apple for Gunpowder Fossil By Raf Verbraeken for Archaeology Sextant By lastspark for Navigation Architecture By Andrew Doane Money Growth By DesignNex for Economics Metal Block By Creaticca Creative Agency for Metallurgy Chemistry By Creative Stall","title":"Renaissance"},{"location":"Credits/#industrial","text":"Science By Dinosoft Labs for Scientific Theory Factory By Lil Squid for Industrialization Rifle By Alexander Skowalsky for Rifling Grenade By Dama Adhikara for Military Science Fertilizer By Jae Deasigner Bacteria By Maxim Kulikov for Biology Electricity By Ben Davis Turbines By Leonardo Schneider for Steam Power Dynamite By Simon Martin","title":"Industrial"},{"location":"Credits/#modern","text":"Gears By Aiden Icons for Replaceable Parts Radio By Arthur Shlain Piston By Proletkult Graphik for Combustion Plastic By Yu luck Microphone By Viktor Vorobyev for Mass Media Flight By Genius Icons Train By Federico Panzano for Railroad Fridge By b farias for Refrigeration telegraph by Luke Anthony Firth for Telegraph*","title":"Modern"},{"location":"Credits/#atomic","text":"Pill By Alex Arseneau for Pharmaceuticals Satellite Dish By Vectors Market for Radar Ecology By ProSymbols Nuclear Reactor By Jeremie Sommet for Nuclear Fission Rocket By kareemov for Rocketry Computer By Shastry for Computers","title":"Atomic"},{"location":"Credits/#information","text":"telecommunications by Wichai Wi for Telcommunications Tactics By Grafix Point for Mobile Tactics Rocket Kusdarti for Advanced Ballistics Satellite By Ben Davis for Satellites Robotic Arm By Karl Gilbert for Robotics Laser by Andrew Doane for Lasers global by Rank Sol for Globilization Atom By Kelsey Armstrong for Particle Physics Nanoparticles By Gyan Lakhwani for Nanotechnology Thermonuclear fusion by Olena Panasovska, UA for Nuclear Fusion Electronics By Cuby Design Radar By CINDYFLA, ID for Stealth","title":"Information"},{"location":"Credits/#future","text":"Information Technology By Vectors Markeet for Future Tech","title":"Future"},{"location":"Credits/#terrain","text":"Hills By Juraj Sedl\u00e1k Mountains By icon 54 Forest by Milinda Courey for Jungle Forest By Lance B Palm Tree By Tatiana for Oasis Water By Kozan for Marsh Harvest By Made for Flood plains Puddle By Bakunetsu Kaito for Lakes Island By Chanut is Industries for Atoll Iceberg By Jaime Carrion for Ice","title":"Terrain"},{"location":"Credits/#nations","text":"Eye of Horus By Lilit Kalachyan for Egypt Russia By Eugen Belyakoff Dragon Head By Ravignir for China Lion By parkjisun for Babylon Omega By icon 54 for Greece Shield By Nathan Driskell for America Fleaur de Lis By Jessika Gadoury for France Crown By Peter van Driel for England Wreath by VectorBakery or Roman Iron Cross By Souvik Maity for Germany Star and Crecent for Arabia Family Crest Komon by sahua d for Japan Ashika Chakra by sahua d for India Variation on crescent moon by Estu Suhartono for The Ottomans Korea by CJS for Korea Two Sword Scimitars by Those Icons for Persia Swirl by IronSV for Polynesia Dharmachakra by Parkjisun for Siam Inca by Ravignir for Inca Sun symbol black by Eddo for The Huns Lion by Nikki Rodriguez for The Netherlands Three Crowns by Daniel Falk for Sweden Flag of Austria by Olena Panasovska, UA for Austria. The original work has been modified. Elephant by Hea Poh Lin for Carthage. The original work has been modified. Orthodox Cross by Avana Vana for Byzantium Iroquois by Ravignir for Iroquois Songhai by Ravignir for Songhai Celtic Knot by Ervin Bolat for the Celts Ethiopian Icon created in Gimp by Unciv team from the following: Lion by IronSV royal crown by Vectors Market Spear by Firza Alamsyah pennant by Sara Jeffries Maya civilization by Olena Panasovska for The Maya","title":"Nations"},{"location":"Credits/#promotions","text":"Sight By Jejen Juliansyah Nur Agung for Scouting skill bow rain arrow by Maxicons for Barrage Bomb By Angelo Troiano for Bombardment Private E2 By Yeong Rong Kim for Shock Private First Class By Yeong Rong Kim for Drill Medic By Yohann Berger for Medic City By iconcheese for Siege Skull and Crossbones By Anton Outkine for Coastal Raider Spear By Deemak Daksina for Formation Wall By Graphic Tigers for Volley Lightning By Mooms for Blitz Move By Sandra for Mobility accuracy By vigtographics for Targeting location by Humantech for Accuracy Plane By Tran Minh Villageois for Interception Hammer by Thengakola for Air Repair Hook By Yeong Rong Kim for Boarding Party Leaf By Paul Verhulst for Indirect Fire Move By Muneer A.Safiah for Logistics Evasion By Anna Sophie for Evasion Interrupt by Stephen Plaster for Ambush Submarine by Lloyd Humphreys for Wolfpack Axe by Brian Oppenlander for Woodsman Competition by luca fruzza Icon for Flight Deck is made by JackRainy Icon for Armor Plating is made by JackRainy Slingshot by James Keuning for Slinger Withdraw Anchor by Gregor Cresnar for Amphibious survival knife by b faris for Survivalism Shamrock By P Thanga Vignesh for Pictish Courage home sweet home By Silviu Ojog for Home Sweet Home","title":"Promotions"},{"location":"Credits/#religions","text":"Lightning Bolt by sian huxtable for Pantheon Christianity by Public Domain Nouns for Christianity Islam by Muhammed Riza for Islam taoism by parkjisun for Taosim Buddhism by Julio Yanes for Buddhism Hinduism by Mugda Damle for Hinduism Confucianism by Dabid J. Pascual for Confucianism Judaism by Dabid J. Pascual for Judaism Shinto by Dabid J. Pascual for Shinto Sikhism by Dabid J. Pascual for Sikhism Tengrism by Dabid J. Pascual for Tengriism Zoroastrianism by Dabid J. Pascual for Zoroastrianism praying by parkjisun for Religion (Civilopedia concept entry) praying by Gan Khoon Lay for Follower Hero by Andrew J. Young for Founder yell by Adrien Coquet for Enhancer","title":"Religions"},{"location":"Credits/#others","text":"Circle By Aybige Arrow By Joe Mortell for movement Swap By iconomania for swapping units Connection By Travis Avery Skull By Vladimir Belochkin for disbanding units Crosshair By Bakunetsu Kaito for selecting enemies to attack City By Felix Westphal Fire By Lloyd Humphreys for \"city being razed\" icon Sleep By Saeful Muslim Banner By Emir Palavan for embarked units Arrow By uzeir syarief for moving between idle units Replace By Mike Rowe for switching tiles between cities Resistance By HeadsOfBirds Viking Hat By my name is mud for pillaging improvements Aim By Kaviashri for ranged strength Capitol By Loren Klein for City-States Aircraft By Tom Fricker for aircraft icon in city button radar scan By icon 54 for Range short range radar by Vectors Point for Intercept range Puppet By Ben Davis for puppeted cities City By Muhajir ila Robbi in the Icon center Lock by Vadim Solomakhin for locked tiles Hourglass by I Create Stuff for the 'Turn' icon Shield by Gregor Cresnar for Religious Strength skill sword flame by Maxicons) for Remove Heresy Pencil by Muhamad Aldi Maulana for Enter Text Prompt Button / Pencil Parchment by hans draiman for Cultured City-States connection by Popular for Mercantile City-States crossed sword by ProSymbols for Militaristic City-States ship helm by Vectors Market for Maritime City-States Magnifying Glass by John Caserta for Mod filter tick by Adrien Coquet on Nation picker people by Wilson Joseph as base for Civilopedia category Nations Mountains by Andrew J. Young as base for Civilopedia category Terrains File:Maya.svg for Mayan numerals East side of stela C, Quirigua for Mayan calendar symbols Footprints by Abdul Wahhab for movement overlay toggle, slightly modified. Currently unused. Arrows.svg by Intralexical (@will-ca), CC0.","title":"Others"},{"location":"Credits/#main-menu","text":"Lightning by Rohith M S for Quickstart Loading by Universal Icons for Load Game New by Alice Design for New Game Go back by Salvia Santos for Resume Multiplayer by Roy Charles Options By Thengakola Package by shashank singh","title":"Main menu"},{"location":"Credits/#sound-credits","text":"Sounds are from FreeSound.org unless otherwise noted and are either Creative Commons or Public Domain unless otherwise noted Soft two-fingered snap By EathanMarkson as 'click' for most clicks Pencil1 By stijn as 'paper' for opening and closing the tech picker SawInOut01 By kingof_thelab for construction picking? Chain Snare #1 By lovesbody as 'fortify' Level up By Marregheriti as 'upgrade' for upgrading units levelup By Seidhepriest as 'chimes' for special actions (free tech, build city, hurry wonder etc.) Coin By TheDJoe93 as 'coin' for purchasing tiles and constructions fast simple chop 1 By dave.dev as 'whoosh' for moving units around, also in edited form to produce the 'swap units' sound. Military kick By Dodgy C as 'promote' for unit promotions Tank reload By KieranKeegan as 'setup' for siege unit setup Scribble_short By waldram as 'policy' for adopting policies Hit Impact by Mrguff as 'throw' for catapult & trebuchet attacks Slingshot fly by 2 by saturdaysoundguy as 'arrow' for arrow attacks Metal hit slide by orginaljun as 'nonmetalhit' for pre-metal melee sounds klick_anlauf By jascha as 'metalhit' for metal melee sounds Horse's whinny By Kubuzz as 'horse' for cavalry attack sounds machine gun 001 - loop By pgi as 'machinegun' for machine gun attack sound uzzi_full_single By Deganoth as 'shot' for bullet attacks Grenade Launcher 2 By Daniel Simon as city bombard sound (CC Attribution 3.0 license) Woosh by Mark DiAngelo as 'slider' sound (CC Attribution 3.0 license) Tornado-Siren-II by Delilah as part of 'nuke' sound (CC Attribution 3.0 license) Explosion-Ultra-Bass by Mark DiAngelo as part of 'nuke' sound (CC Attribution 3.0 license) Short Choir by Breviceps as 'choir' for free great person pick Death Robot! Robotic scream by vultraz168 for Giant Death Robot Attack (CC0 1.0 Universal license) ceremonial cannon fire by DylanSmithSound for cannon artillery fire by Tomashevsky for artillery 20mm cannons by Piotr123 for ship guns \"bombing\" is made by the Unciv team using Audacity from lancaster bomber by confusion_music - aircraft Artillery Explosion (Close) (Mixed) by EFlexMusic - impact SFX Hit drop/bomb effect 5 by old_waveplay - bass \"jetgun\" for Jet Fighter attack is made by the Unciv team using Audacity from Fighter Jet Aircraft Fly by (synthesised) by Headphaze Machine Gun 001 - triple shot by pgi Excerpt from Tanks Shooting by qubodup for tankshot \"torpedo\" is made by the Unciv team using Audacity from Torpedo launch underwater by jobro Artillery Explosion (Close) (Mixed) by EFlexMusic elephant 44 by y89312 for Naruesan's Elephant sound Excerpt from Missile Strike by BaDoink for guided missile Excerpt from FireBurning_v2.wav by pcaeldries for 'remove heresy' action of inquisitor ( License )","title":"Sound credits"},{"location":"Credits/#music","text":"The following music is from https://filmmusic.io \" Thatched Villagers \" by Kevin MacLeod (https://incompetech.com)","title":"Music"},{"location":"Game%20Making%20Tips/","text":"Tips and tricks for making a LibGDX game Here are a bunch of things I've learned from by brief excursion into the world of game making. Some of our will be obvious to you, some will not. Use Kotlin Unciv started its life as a Unity project in C#, was shifted to Java and LibGDX, and finally to Kotlin. I regret every minute that I spent writing events in Java, this is probably the most significant change that your application could see. Use Scene2d Unless you plan on creating images on the fly, you'll probably be using prerendered assets. Placing them manually is akin to manually positioning html tags, instead of using html heirarchy and css to guide positions. So too is Scene2d - as a placement framework. it's relatively simple to understand, especially when you... Ignore Horizontal and Vertical groups - use Table I personally found that table has all the functionality of the above, and more. Each class has a different syntax too, so I found it much simpler to just stick with Table for everything. Table does just about EVERYTHING! It's insanely amazing! If your game is getting slow, use the Android profiler in Android Studio The top-down CPU chart is the best code profiler I've ever seen, use it to your advantage! Cache everything Caching is a trade-off between purer, state-agnostic code and higher performance. Coming from a PC background, I automatically assume that anything less than O(n^2) is less than a milisecond and therefore, not a cachinhg candidate. This is not so in mobile development. This becomes especially relevant when you need to save and load game data which has lots of connected parts - you have to avoid circular references, and you want to minimise the save size, but you need to reconstruct the missing links when loading. Minimize String operations All the tip and tricks you've heard to minimize String operations? Use them! String constants should be consts, use StringBuilders (or just ArrayLists of strings that you later .joinToString()) Sequences everywhere! One thing I did not expect to be such an issue is intermediate lists when sorting and mapping. But apparently, the memory allocation for these tasks is Serious Business. So whenever possible, take your list and .asSequence() it before actiating list operations - this results in huge savings of both time and memory! The only time you shouldn't be doing this, though, is when you want to cache the specific values for future use - sequences will go through the whole process every time you iterate on them, so just .toList() them when you've gotten the final results! General tips for making an Open Source game Lower the entry bar - for both programmers and players I think that most Open Source games suffer from this problem - those that are in are way in, but those that are out and want to join have to learn the ecosystem. Documentation is a big issue here, but so are detailed instructions - and I mean \"Spoonfeeding\". Treat new developers as if they've never used Git before - it's possible they haven't! Explain how to dowload the sourecode, the tools, how to get the game running locally, how to make changes and how to submit them. Same think with new players - getting the game up and running should be AS SIMPLE AS HUMANLY POSSIBLE - you want people to play your game, don't you? This includes: Source-To-Executable automation - I use Travis Play stores and the like Internal game tutorials - your players will NEVER BE SATISFIED with this last point, but at least do what you candidate Community, Community, Community! I, personally, underestimated this point for about a year after launch. I communicated with players through the Google Play Store and Github issues, and that seemed to be enough. It was only after repeated urgings from players that I opened a Discord server - and that gradually lead to a massive change! You see, it's not ABOUT programmer-to-player interaction. There will always be a small number of core devs relative to the large playerbase. The key to the community is the player-to-player interaction. Explaining things, questions, ideas, things that players bounc off each other, not only make the amorphous community a better pllace, but actually lead to a better game! Another think to remember is that there's a larger community around you - the Open Source community, the Linux community, etc. There are lots of people who will play your game only because it's open source, and it also means they don't have as many options. For example... Being the best 4X game means competing with the biggest names out there Being the best 4X game for Linux means many less competitors, but All The Cool Kids (tm) are multiplatforming nowadays so you're still outperformed. Being the best Open Source 4X game means about 5 competitors, and no money is involved either so the average entry is not as polished. Being the best Open Source 4X game for Android... means having so few competitors that it's totally doable. Everything is marketing. Your game's name, the icon, screenshots, everythig a player sees about your game is marketing. Icons and bylines are especially important, since they're the first things your players will probably see. I saw an almost 50% (!) by changing the icon, after seveeral experiments, which Google Play lets you conduct very easily. Translations are part of your source code This may be slightly contraversial, so I'll explain. We went though a number of iterations regarding how to save translations until we arrived at the current format. The important parts are: Game translation files should be AUTO GENERATED. This allows you to add new objects into the game with impunity, knowing that corresponding lines will be auto-added to the translations. Translations for each language should be stored separately - this allows concurrent modification of several independant languages with no risk of conflict Translations should be PR'd in! This allows other speakers to question or change the proposed translations, and allows you to run tests on your translations. If you require a specific format, this is invaluable as it means that bad translations will be rejected at the door. Open source problems require open (source?) solutions TL;DR, consider using APIs that are free, even if they're not Open Source. Multiplayer requires syncing game files beween clients, even when one of them is not currently online. The 'correct' way to solve this would probably be to have an online DB and a service which handles user requests. Since this is an Open Source game, I'm working on a 0$ budget, so we just store all the files in Dropbox and upload/download there. Is this secure? No, but does it need to be? You need to think of the cost vs the value. Same thing with Mods. Steam is big and secure so it handles its mods itself. We are small and open, so we just allow to download from Github, which lets us use all of Github's built in functions (user management, readmes, stars, versioning...) at no extra cost. And unlike the Dropbox usage, which is basically abuse, Github is built for thiss kind of thing! This is exactly the kind of use case they were thinking of to start with! The Reckoning There comes a time in every project where the cool stuff is done. All the cutting-edge awesomeness and algorithmic playdough is done, and now all (hah) it needs is polish. You know who loves polish? Players! Sure, there are some that say \"a good game is good even if it's basic\" but they have standards for what a basic game should have as well. And the numbers don't lie. Polished games sell themselves better, and so are played more. You know who doesn't love polish? DEVELOPERS. When your game is relatively simple, then the options for polish are more limited, but the more complex the game, the more polish-venues there are. And it can be an ABSOLUTE GRIND. Another weird use-case, another ingame option, \"better performance\" (I must have spent dozens of hours on different performance related actions) And the worst thing is, that everyone notices when it's missing, but no one notices when it's there. A hundred versions of polish - literally - and the average player may notice only a slight change. And then comes the moment when you ask yourself, why bother? What are we even doing here? For me, the answers are as follows: A. To build something truly great, you have to keep going way beyond when it stops being fun. B. There's a community of people that like what you're doing and want there to be more of it :) C. You know you want to keep coding, and what, you think you're going to start another project and it'll work out as well? You've tried that multiple times, and let's face it the chance of you making a second game that goes so well is really small unless you invest in it as much time as you have in this, and yeah, then you'll be back in this position again. And that's basically the loop I've been in for the last hundred versions or so! Solve bugs, fix edge cases, improve AI, accept PRs. Lots of mod-related changes, both to stop the game breaking when people do things in mods that they shouldn't and to allow them more freedom in making them. I don't think I'll ever really continue to finish G&K, I'm DEFINITELY not planning on implementing BNW mechanics which frankly I think are...not great. That's where I am right now. Kind of done with the game, but considering that I thought that half a year ago and releases are still releasing roughly every week, also kind of not.","title":"Tips and tricks for making a LibGDX game"},{"location":"Game%20Making%20Tips/#tips-and-tricks-for-making-a-libgdx-game","text":"Here are a bunch of things I've learned from by brief excursion into the world of game making. Some of our will be obvious to you, some will not.","title":"Tips and tricks for making a LibGDX game"},{"location":"Game%20Making%20Tips/#use-kotlin","text":"Unciv started its life as a Unity project in C#, was shifted to Java and LibGDX, and finally to Kotlin. I regret every minute that I spent writing events in Java, this is probably the most significant change that your application could see.","title":"Use Kotlin"},{"location":"Game%20Making%20Tips/#use-scene2d","text":"Unless you plan on creating images on the fly, you'll probably be using prerendered assets. Placing them manually is akin to manually positioning html tags, instead of using html heirarchy and css to guide positions. So too is Scene2d - as a placement framework. it's relatively simple to understand, especially when you...","title":"Use Scene2d"},{"location":"Game%20Making%20Tips/#ignore-horizontal-and-vertical-groups-use-table","text":"I personally found that table has all the functionality of the above, and more. Each class has a different syntax too, so I found it much simpler to just stick with Table for everything. Table does just about EVERYTHING! It's insanely amazing!","title":"Ignore Horizontal and Vertical groups - use Table"},{"location":"Game%20Making%20Tips/#if-your-game-is-getting-slow-use-the-android-profiler-in-android-studio","text":"The top-down CPU chart is the best code profiler I've ever seen, use it to your advantage!","title":"If your game is getting slow, use the Android profiler in Android Studio"},{"location":"Game%20Making%20Tips/#cache-everything","text":"Caching is a trade-off between purer, state-agnostic code and higher performance. Coming from a PC background, I automatically assume that anything less than O(n^2) is less than a milisecond and therefore, not a cachinhg candidate. This is not so in mobile development. This becomes especially relevant when you need to save and load game data which has lots of connected parts - you have to avoid circular references, and you want to minimise the save size, but you need to reconstruct the missing links when loading.","title":"Cache everything"},{"location":"Game%20Making%20Tips/#minimize-string-operations","text":"All the tip and tricks you've heard to minimize String operations? Use them! String constants should be consts, use StringBuilders (or just ArrayLists of strings that you later .joinToString())","title":"Minimize String operations"},{"location":"Game%20Making%20Tips/#sequences-everywhere","text":"One thing I did not expect to be such an issue is intermediate lists when sorting and mapping. But apparently, the memory allocation for these tasks is Serious Business. So whenever possible, take your list and .asSequence() it before actiating list operations - this results in huge savings of both time and memory! The only time you shouldn't be doing this, though, is when you want to cache the specific values for future use - sequences will go through the whole process every time you iterate on them, so just .toList() them when you've gotten the final results!","title":"Sequences everywhere!"},{"location":"Game%20Making%20Tips/#general-tips-for-making-an-open-source-game","text":"","title":"General tips for making an Open Source game"},{"location":"Game%20Making%20Tips/#lower-the-entry-bar-for-both-programmers-and-players","text":"I think that most Open Source games suffer from this problem - those that are in are way in, but those that are out and want to join have to learn the ecosystem. Documentation is a big issue here, but so are detailed instructions - and I mean \"Spoonfeeding\". Treat new developers as if they've never used Git before - it's possible they haven't! Explain how to dowload the sourecode, the tools, how to get the game running locally, how to make changes and how to submit them. Same think with new players - getting the game up and running should be AS SIMPLE AS HUMANLY POSSIBLE - you want people to play your game, don't you? This includes: Source-To-Executable automation - I use Travis Play stores and the like Internal game tutorials - your players will NEVER BE SATISFIED with this last point, but at least do what you candidate","title":"Lower the entry bar - for both programmers and players"},{"location":"Game%20Making%20Tips/#community-community-community","text":"I, personally, underestimated this point for about a year after launch. I communicated with players through the Google Play Store and Github issues, and that seemed to be enough. It was only after repeated urgings from players that I opened a Discord server - and that gradually lead to a massive change! You see, it's not ABOUT programmer-to-player interaction. There will always be a small number of core devs relative to the large playerbase. The key to the community is the player-to-player interaction. Explaining things, questions, ideas, things that players bounc off each other, not only make the amorphous community a better pllace, but actually lead to a better game! Another think to remember is that there's a larger community around you - the Open Source community, the Linux community, etc. There are lots of people who will play your game only because it's open source, and it also means they don't have as many options. For example... Being the best 4X game means competing with the biggest names out there Being the best 4X game for Linux means many less competitors, but All The Cool Kids (tm) are multiplatforming nowadays so you're still outperformed. Being the best Open Source 4X game means about 5 competitors, and no money is involved either so the average entry is not as polished. Being the best Open Source 4X game for Android... means having so few competitors that it's totally doable.","title":"Community, Community, Community!"},{"location":"Game%20Making%20Tips/#everything-is-marketing","text":"Your game's name, the icon, screenshots, everythig a player sees about your game is marketing. Icons and bylines are especially important, since they're the first things your players will probably see. I saw an almost 50% (!) by changing the icon, after seveeral experiments, which Google Play lets you conduct very easily.","title":"Everything is marketing."},{"location":"Game%20Making%20Tips/#translations-are-part-of-your-source-code","text":"This may be slightly contraversial, so I'll explain. We went though a number of iterations regarding how to save translations until we arrived at the current format. The important parts are: Game translation files should be AUTO GENERATED. This allows you to add new objects into the game with impunity, knowing that corresponding lines will be auto-added to the translations. Translations for each language should be stored separately - this allows concurrent modification of several independant languages with no risk of conflict Translations should be PR'd in! This allows other speakers to question or change the proposed translations, and allows you to run tests on your translations. If you require a specific format, this is invaluable as it means that bad translations will be rejected at the door.","title":"Translations are part of your source code"},{"location":"Game%20Making%20Tips/#open-source-problems-require-open-source-solutions","text":"TL;DR, consider using APIs that are free, even if they're not Open Source. Multiplayer requires syncing game files beween clients, even when one of them is not currently online. The 'correct' way to solve this would probably be to have an online DB and a service which handles user requests. Since this is an Open Source game, I'm working on a 0$ budget, so we just store all the files in Dropbox and upload/download there. Is this secure? No, but does it need to be? You need to think of the cost vs the value. Same thing with Mods. Steam is big and secure so it handles its mods itself. We are small and open, so we just allow to download from Github, which lets us use all of Github's built in functions (user management, readmes, stars, versioning...) at no extra cost. And unlike the Dropbox usage, which is basically abuse, Github is built for thiss kind of thing! This is exactly the kind of use case they were thinking of to start with!","title":"Open source problems require open (source?) solutions"},{"location":"Game%20Making%20Tips/#the-reckoning","text":"There comes a time in every project where the cool stuff is done. All the cutting-edge awesomeness and algorithmic playdough is done, and now all (hah) it needs is polish. You know who loves polish? Players! Sure, there are some that say \"a good game is good even if it's basic\" but they have standards for what a basic game should have as well. And the numbers don't lie. Polished games sell themselves better, and so are played more. You know who doesn't love polish? DEVELOPERS. When your game is relatively simple, then the options for polish are more limited, but the more complex the game, the more polish-venues there are. And it can be an ABSOLUTE GRIND. Another weird use-case, another ingame option, \"better performance\" (I must have spent dozens of hours on different performance related actions) And the worst thing is, that everyone notices when it's missing, but no one notices when it's there. A hundred versions of polish - literally - and the average player may notice only a slight change. And then comes the moment when you ask yourself, why bother? What are we even doing here? For me, the answers are as follows: A. To build something truly great, you have to keep going way beyond when it stops being fun. B. There's a community of people that like what you're doing and want there to be more of it :) C. You know you want to keep coding, and what, you think you're going to start another project and it'll work out as well? You've tried that multiple times, and let's face it the chance of you making a second game that goes so well is really small unless you invest in it as much time as you have in this, and yeah, then you'll be back in this position again. And that's basically the loop I've been in for the last hundred versions or so! Solve bugs, fix edge cases, improve AI, accept PRs. Lots of mod-related changes, both to stop the game breaking when people do things in mods that they shouldn't and to allow them more freedom in making them. I don't think I'll ever really continue to finish G&K, I'm DEFINITELY not planning on implementing BNW mechanics which frankly I think are...not great. That's where I am right now. Kind of done with the game, but considering that I thought that half a year ago and releases are still releasing roughly every week, also kind of not.","title":"The Reckoning"},{"location":"unique%20parameters/","text":"This page contains an overview of all different parameters used in uniques and what values can be filled into them. Each of the different parameter types is described below, including all possible values for them. These are split into two categories: - descriptions: e.g., \"the name of any unit\" - Text that looks like this . This last one must be used exactly the same Note that all of these are case-sensitive! action An action that a unit can preform. Currently, there are only two actions part of this: - Spread Religion - Remove Foreign religions from your own cities amount This indicates a whole number, possibly with a + or - sign, such as 2 , +13 , or -3 . baseTerrain The name of any terrain that is a base terrain according to the json file. baseUnitFilter Unit filters can be divided up into two parts: baseUnitFilter s and mapUnitFilter s. The former is tested against the unit as it appears in the json. This means it doesn't have an owning civ or tile it stands on, just its base properties. The latter is tested against the unit as it appears on the map, including its nation, tile, health and all other properties. The following are allowed to be used: - unit name - unit type - e.g. Melee, Ranged, WaterSubmarine, etc. - Land , Water , Air - land units , water units , air units - non-air for non-air non-missile units - Military , military units - Civilian , civilian units - All - Melee - Ranged - Nuclear Weapon - Great Person , Great - Embarked - Any exact unique the unit has - Any exact unique the unit type has - Any combination of the above (will match only if all match). The format is {filter1} {filter2} and can match any number of filters. For example: [{Military} {Water}] units, [{non-air} {Armor}] units, etc. No space or other text is allowed between the [ and the first { . belief The name of any belief beliefType Pantheon , Follower , Founder or Enhancer . buildingFilter Allows to only activate a unique for certain buildings. Allowed options are: All Buildings , Building Wonders , Wonders National Wonder World Wonder -- All wonders that are not national wonders building name The name of the building it replaces (so for example uniques for libraries will apply to paper makers as well) an exact unique the building has (e.g.: spaceship part ) Culture , Gold , etc. if the building is stat-related for that stat. Stat-related buildings are defined as one of the following: Provides that stat directly (e.g. +1 Culture) Provides a percentage bonus for that stat (e.g. +10% Production) Provides that stat as a bonus for resources (e.g. +1 Food from every Wheat) Provides that stat per some amount of population (e.g. +1 Science for every 2 population [cityFilter]) buildingName The name of any one building cityFilter cityFilters allow us to choose the range of cities affected by this unique: in this city in all cities in other cities in all coastal cities in capital in all non-occupied cities - all cities that are not puppets and don't have extra unhappiness from being recently conquered in all cities with a world wonder in all cities connected to capital in all cities with a garrison in non-enemy foreign cities - In all cities owned by civs other than you that you are not at war with in foreign cities in annexed cities in holy cities in City-State cities in cities following this religion - Should only be used in pantheon/follower uniques for religions in all cities in which the majority religion is a major religion in all cities in which the majority religion is a enhanced religion combatantFilter This indicates a combatant, which can either be a unit or a city (when bombarding). Must either be City or a mapUnitFilter . constructionFilter A filter for used when testing the current construction of a city. All values of baseUnitFilter and buildingFilter are allowed. costOrStrength Cost or Strength era The name of any era foundingOrEnhancing founding or enhancing great person The name of any great person improvementFilter For filtering a specific improvement. Allowed values are: - improvement name (Note that \"Road\" and \"Railroad\" do work as improvementFilters, but not as tileFilters at the moment.) - All - Great Improvements , Great - All Road - for Roads & Railroads improvementName The name of any improvement mapUnitFilter This indicates a unit as placed on the map. Compare with baseUnitFilter . It can be any value noted in baseUnitFilter or one of the following: - Wounded , wounded units - City-State - Barbarians , Barbarian - Again, any combination of the above is also allowed, e.g. [{Wounded} {Water}] units. plunderableStat All the following stats can be plundered: Gold , Science , Culture , Faith policy The name of any policy promotion The name of any promotion regionType Used for dividing the world into regions in each of which a single player is placed at the start of the game. Allowed values are Hybrid and the name of any terrain that has one of the following two uniques: - A Region is formed with at least [amount]% [simpleTerrain] tiles, with priority [amount] - A Region is formed with at least [amount]% [simpleTerrain] tiles and [simpleTerrain] tiles, with priority [amount] resource The name of any resource simpleTerrain Used by NaturalWonderGenerator to place natural wonders Allowed values are: - Land - Water - Elevated - The name of any terrain specialist The name of any specialist stats This indicates a text comprised of specific stats and is slightly more complex. Each stats is comprised of several stat changes, each in the form of +{amount} {stat} , where 'stat' is one of the seven major stats mentioned above. For example: +1 Science . These can be strung together with \", \" between them, for example: +2 Production, +3 Food . stat This is one of the 7 major stats in the game - Gold , Science , Production , Food , Happiness , Culture and Faith . Note that the stat names need to be capitalized! tech The name of any tech terrainFilter This indicates the terrain on a single tile. The following values are allowed: A filter names a specific json attribute (by name): Base terrain Terrain features Base terrain uniques Terrain feature uniques Resource Natural wonder Or the filter is a constant string choosing a derived test: All Water , Land Coastal (at least one direct neighbor is a coast) River (as in all 'river on tile' contexts, it means 'adjacent to a river on at least one side') Open terrain , Rough terrain (note all terrain not having the rough unique is counted as open) Friendly Land - land belonging to you, or other civs with open borders to you Foreign Land - any land that isn't friendly land Enemy land - any land belonging to a civ you are at war with Water resource , Strategic resource , Luxury resource , Bonus resource Natural Wonder (as opposed to above which means testing for a specific Natural Wonder by name, this tests for any of them) Please note all of these are case-sensitive . Also note: Resource filters depend on whether a viewing civ is known in the context where the filter runs. Water and specific tests require a viewing civ, and if the resource needs a tech to be visible, that tech to be researched by the viewing civ. The other resource category tests can succeed without a known viewing civ only for resources not requiring any tech. So - test your mod! So for instance, the unique \"[stats] from [tileFilter] tiles [cityFilter]\" can match several cases: terrainQuality Used to indicate for what use the terrain should be viewed when dividing the world into regions, in each of which a single player is placed at the start of the game. Allowed values are: - improvement name (Note that \"Road\" and \"Railroad\" do work as improvementFilters, but not as tileFilters at the moment.) - \"All\" - \"Great Improvements\", \"Great\" - \"All Road\" - for Roads & Railroads tileFilter Anything that can be used either in an improvementFilter or in a tileFilter can be used here victoryType The name of any victory type: - Neutral - Cultural - Diplomatic - Domination - Scientific - Time","title":"Unique parameters"},{"location":"unique%20parameters/#action","text":"An action that a unit can preform. Currently, there are only two actions part of this: - Spread Religion - Remove Foreign religions from your own cities","title":"action"},{"location":"unique%20parameters/#amount","text":"This indicates a whole number, possibly with a + or - sign, such as 2 , +13 , or -3 .","title":"amount"},{"location":"unique%20parameters/#baseterrain","text":"The name of any terrain that is a base terrain according to the json file.","title":"baseTerrain"},{"location":"unique%20parameters/#baseunitfilter","text":"Unit filters can be divided up into two parts: baseUnitFilter s and mapUnitFilter s. The former is tested against the unit as it appears in the json. This means it doesn't have an owning civ or tile it stands on, just its base properties. The latter is tested against the unit as it appears on the map, including its nation, tile, health and all other properties. The following are allowed to be used: - unit name - unit type - e.g. Melee, Ranged, WaterSubmarine, etc. - Land , Water , Air - land units , water units , air units - non-air for non-air non-missile units - Military , military units - Civilian , civilian units - All - Melee - Ranged - Nuclear Weapon - Great Person , Great - Embarked - Any exact unique the unit has - Any exact unique the unit type has - Any combination of the above (will match only if all match). The format is {filter1} {filter2} and can match any number of filters. For example: [{Military} {Water}] units, [{non-air} {Armor}] units, etc. No space or other text is allowed between the [ and the first { .","title":"baseUnitFilter"},{"location":"unique%20parameters/#belief","text":"The name of any belief","title":"belief"},{"location":"unique%20parameters/#belieftype","text":"Pantheon , Follower , Founder or Enhancer .","title":"beliefType"},{"location":"unique%20parameters/#buildingfilter","text":"Allows to only activate a unique for certain buildings. Allowed options are: All Buildings , Building Wonders , Wonders National Wonder World Wonder -- All wonders that are not national wonders building name The name of the building it replaces (so for example uniques for libraries will apply to paper makers as well) an exact unique the building has (e.g.: spaceship part ) Culture , Gold , etc. if the building is stat-related for that stat. Stat-related buildings are defined as one of the following: Provides that stat directly (e.g. +1 Culture) Provides a percentage bonus for that stat (e.g. +10% Production) Provides that stat as a bonus for resources (e.g. +1 Food from every Wheat) Provides that stat per some amount of population (e.g. +1 Science for every 2 population [cityFilter])","title":"buildingFilter"},{"location":"unique%20parameters/#buildingname","text":"The name of any one building","title":"buildingName"},{"location":"unique%20parameters/#cityfilter","text":"cityFilters allow us to choose the range of cities affected by this unique: in this city in all cities in other cities in all coastal cities in capital in all non-occupied cities - all cities that are not puppets and don't have extra unhappiness from being recently conquered in all cities with a world wonder in all cities connected to capital in all cities with a garrison in non-enemy foreign cities - In all cities owned by civs other than you that you are not at war with in foreign cities in annexed cities in holy cities in City-State cities in cities following this religion - Should only be used in pantheon/follower uniques for religions in all cities in which the majority religion is a major religion in all cities in which the majority religion is a enhanced religion","title":"cityFilter"},{"location":"unique%20parameters/#combatantfilter","text":"This indicates a combatant, which can either be a unit or a city (when bombarding). Must either be City or a mapUnitFilter .","title":"combatantFilter"},{"location":"unique%20parameters/#constructionfilter","text":"A filter for used when testing the current construction of a city. All values of baseUnitFilter and buildingFilter are allowed.","title":"constructionFilter"},{"location":"unique%20parameters/#costorstrength","text":"Cost or Strength","title":"costOrStrength"},{"location":"unique%20parameters/#era","text":"The name of any era","title":"era"},{"location":"unique%20parameters/#foundingorenhancing","text":"founding or enhancing","title":"foundingOrEnhancing"},{"location":"unique%20parameters/#great-person","text":"The name of any great person","title":"great person"},{"location":"unique%20parameters/#improvementfilter","text":"For filtering a specific improvement. Allowed values are: - improvement name (Note that \"Road\" and \"Railroad\" do work as improvementFilters, but not as tileFilters at the moment.) - All - Great Improvements , Great - All Road - for Roads & Railroads","title":"improvementFilter"},{"location":"unique%20parameters/#improvementname","text":"The name of any improvement","title":"improvementName"},{"location":"unique%20parameters/#mapunitfilter","text":"This indicates a unit as placed on the map. Compare with baseUnitFilter . It can be any value noted in baseUnitFilter or one of the following: - Wounded , wounded units - City-State - Barbarians , Barbarian - Again, any combination of the above is also allowed, e.g. [{Wounded} {Water}] units.","title":"mapUnitFilter"},{"location":"unique%20parameters/#plunderablestat","text":"All the following stats can be plundered: Gold , Science , Culture , Faith","title":"plunderableStat"},{"location":"unique%20parameters/#policy","text":"The name of any policy","title":"policy"},{"location":"unique%20parameters/#promotion","text":"The name of any promotion","title":"promotion"},{"location":"unique%20parameters/#regiontype","text":"Used for dividing the world into regions in each of which a single player is placed at the start of the game. Allowed values are Hybrid and the name of any terrain that has one of the following two uniques: - A Region is formed with at least [amount]% [simpleTerrain] tiles, with priority [amount] - A Region is formed with at least [amount]% [simpleTerrain] tiles and [simpleTerrain] tiles, with priority [amount]","title":"regionType"},{"location":"unique%20parameters/#resource","text":"The name of any resource","title":"resource"},{"location":"unique%20parameters/#simpleterrain","text":"Used by NaturalWonderGenerator to place natural wonders Allowed values are: - Land - Water - Elevated - The name of any terrain","title":"simpleTerrain"},{"location":"unique%20parameters/#specialist","text":"The name of any specialist","title":"specialist"},{"location":"unique%20parameters/#stats","text":"This indicates a text comprised of specific stats and is slightly more complex. Each stats is comprised of several stat changes, each in the form of +{amount} {stat} , where 'stat' is one of the seven major stats mentioned above. For example: +1 Science . These can be strung together with \", \" between them, for example: +2 Production, +3 Food .","title":"stats"},{"location":"unique%20parameters/#stat","text":"This is one of the 7 major stats in the game - Gold , Science , Production , Food , Happiness , Culture and Faith . Note that the stat names need to be capitalized!","title":"stat"},{"location":"unique%20parameters/#tech","text":"The name of any tech","title":"tech"},{"location":"unique%20parameters/#terrainfilter","text":"This indicates the terrain on a single tile. The following values are allowed: A filter names a specific json attribute (by name): Base terrain Terrain features Base terrain uniques Terrain feature uniques Resource Natural wonder Or the filter is a constant string choosing a derived test: All Water , Land Coastal (at least one direct neighbor is a coast) River (as in all 'river on tile' contexts, it means 'adjacent to a river on at least one side') Open terrain , Rough terrain (note all terrain not having the rough unique is counted as open) Friendly Land - land belonging to you, or other civs with open borders to you Foreign Land - any land that isn't friendly land Enemy land - any land belonging to a civ you are at war with Water resource , Strategic resource , Luxury resource , Bonus resource Natural Wonder (as opposed to above which means testing for a specific Natural Wonder by name, this tests for any of them) Please note all of these are case-sensitive . Also note: Resource filters depend on whether a viewing civ is known in the context where the filter runs. Water and specific tests require a viewing civ, and if the resource needs a tech to be visible, that tech to be researched by the viewing civ. The other resource category tests can succeed without a known viewing civ only for resources not requiring any tech. So - test your mod! So for instance, the unique \"[stats] from [tileFilter] tiles [cityFilter]\" can match several cases:","title":"terrainFilter"},{"location":"unique%20parameters/#terrainquality","text":"Used to indicate for what use the terrain should be viewed when dividing the world into regions, in each of which a single player is placed at the start of the game. Allowed values are: - improvement name (Note that \"Road\" and \"Railroad\" do work as improvementFilters, but not as tileFilters at the moment.) - \"All\" - \"Great Improvements\", \"Great\" - \"All Road\" - for Roads & Railroads","title":"terrainQuality"},{"location":"unique%20parameters/#tilefilter","text":"Anything that can be used either in an improvementFilter or in a tileFilter can be used here","title":"tileFilter"},{"location":"unique%20parameters/#victorytype","text":"The name of any victory type: - Neutral - Cultural - Diplomatic - Domination - Scientific - Time","title":"victoryType"},{"location":"uniques/","text":"Table of Contents Triggerable uniques Global uniques Nation uniques Tech uniques FollowerBelief uniques Building uniques Unit uniques Promotion uniques Terrain uniques Improvement uniques Resource uniques Ruins uniques CityState uniques Conditional uniques Deprecated uniques Triggerable uniques \ud83d\udd37 Free [baseUnitFilter] appears Example: \"Free [Melee] appears\" Applicable to: Triggerable \ud83d\udd37 [amount] free [baseUnitFilter] units appear Example: \"[20] free [Melee] units appear\" Applicable to: Triggerable \ud83d\udd37 Free Social Policy Applicable to: Triggerable \ud83d\udd37 [amount] Free Social Policies Example: \"[20] Free Social Policies\" Applicable to: Triggerable \ud83d\udd37 Empire enters golden age Applicable to: Triggerable \ud83d\udd37 Free Great Person Applicable to: Triggerable \ud83d\udd37 [amount] population [cityFilter] Example: \"[20] population [in all cities]\" Applicable to: Triggerable \ud83d\udd37 Free Technology Applicable to: Triggerable \ud83d\udd37 [amount] Free Technologies Example: \"[20] Free Technologies\" Applicable to: Triggerable \ud83d\udd37 Reveals the entire map Applicable to: Triggerable \ud83d\udd37 Triggers voting for the Diplomatic Victory Applicable to: Triggerable \ud83d\udd37 This Unit gains the [promotion] promotion Example: \"This Unit gains the [Shock I] promotion\" Applicable to: Triggerable \ud83d\udd37 [mapUnitFilter] units gain the [promotion] promotion Example: \"[Wounded] units gain the [Shock I] promotion\" Applicable to: Triggerable \ud83d\udd37 Provides the cheapest [stat] building in your first [amount] cities for free Example: \"Provides the cheapest [Culture] building in your first [20] cities for free\" Applicable to: Triggerable \ud83d\udd37 Provides a [buildingName] in your first [amount] cities for free Example: \"Provides a [Library] in your first [20] cities for free\" Applicable to: Triggerable \ud83d\udd37 Will not be displayed in Civilopedia Applicable to: Triggerable, Global, Nation, Era, Tech, Policy, FounderBelief, FollowerBelief, Building, Wonder, Unit, UnitType, Promotion, Terrain, Improvement, Resource, Ruins, CityState, ModOptions, Conditional Global uniques \ud83d\udd37 [stats] Example: \"[+1 Gold, +2 Production]\" Applicable to: Global, FollowerBelief, Improvement \ud83d\udd37 [stats] [cityFilter] Example: \"[+1 Gold, +2 Production] [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [stats] from every specialist [cityFilter] Example: \"[+1 Gold, +2 Production] from every specialist [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [stats] per [amount] population [cityFilter] Example: \"[+1 Gold, +2 Production] per [20] population [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [stats] in cities with [amount] or more population Example: \"[+1 Gold, +2 Production] in cities with [20] or more population\" Applicable to: Global, FollowerBelief \ud83d\udd37 [stats] in cities on [terrainFilter] tiles Example: \"[+1 Gold, +2 Production] in cities on [Forest] tiles\" Applicable to: Global, FollowerBelief \ud83d\udd37 [stats] from all [buildingFilter] buildings Example: \"[+1 Gold, +2 Production] from all [Culture] buildings\" Applicable to: Global, FollowerBelief \ud83d\udd37 [stats] whenever a Great Person is expended Example: \"[+1 Gold, +2 Production] whenever a Great Person is expended\" Applicable to: Global \ud83d\udd37 [stats] from [tileFilter] tiles [cityFilter] Example: \"[+1 Gold, +2 Production] from [Farm] tiles [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [stats] from [tileFilter] tiles without [tileFilter] [cityFilter] Example: \"[+1 Gold, +2 Production] from [Farm] tiles without [Farm] [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [stats] from every [tileFilter/specialist/buildingFilter] Example: \"[+1 Gold, +2 Production] from every [tileFilter/specialist/buildingFilter]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [stats] from each Trade Route Example: \"[+1 Gold, +2 Production] from each Trade Route\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% [stat] Example: \"[20]% [Culture]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% [stat] [cityFilter] Example: \"[20]% [Culture] [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% [stat] from every [tileFilter/specialist/buildingName] Example: \"[20]% [Culture] from every [tileFilter/specialist/buildingName]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% Yield from every [tileFilter] Example: \"[20]% Yield from every [Farm]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% [stat] from City-States Example: \"[20]% [Culture] from City-States\" Applicable to: Global \ud83d\udd37 Gold from all trade routes +25% Applicable to: Global \ud83d\udd37 Nullifies [stat] [cityFilter] Example: \"Nullifies [Culture] [in all cities]\" Applicable to: Global \ud83d\udd37 Nullifies Growth [cityFilter] Example: \"Nullifies Growth [in all cities]\" Applicable to: Global \ud83d\udd37 [amount]% Production when constructing [buildingFilter] wonders [cityFilter] Example: \"[20]% Production when constructing [Culture] wonders [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% Production when constructing [buildingFilter] buildings [cityFilter] Example: \"[20]% Production when constructing [Culture] buildings [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% Production when constructing [baseUnitFilter] units [cityFilter] Example: \"[20]% Production when constructing [Melee] units [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% Production towards any buildings that already exist in the Capital Example: \"[20]% Production towards any buildings that already exist in the Capital\" Applicable to: Global, FollowerBelief \ud83d\udd37 Tile yields from Natural Wonders doubled Applicable to: Global \ud83d\udd37 Military Units gifted from City-States start with [amount] XP Example: \"Military Units gifted from City-States start with [20] XP\" Applicable to: Global \ud83d\udd37 Militaristic City-States grant units [amount] times as fast when you are at war with a common nation Example: \"Militaristic City-States grant units [20] times as fast when you are at war with a common nation\" Applicable to: Global \ud83d\udd37 Gifts of Gold to City-States generate [amount]% more Influence Example: \"Gifts of Gold to City-States generate [20]% more Influence\" Applicable to: Global \ud83d\udd37 Can spend Gold to annex or puppet a City-State that has been your ally for [amount] turns. Example: \"Can spend Gold to annex or puppet a City-State that has been your ally for [20] turns.\" Applicable to: Global \ud83d\udd37 City-State territory always counts as friendly territory Applicable to: Global \ud83d\udd37 Allied City-States will occasionally gift Great People Applicable to: Global \ud83d\udd37 [amount]% City-State Influence degradation Example: \"[20]% City-State Influence degradation\" Applicable to: Global \ud83d\udd37 Resting point for Influence with City-States is increased by [amount] Example: \"Resting point for Influence with City-States is increased by [20]\" Applicable to: Global \ud83d\udd37 Allied City-States provide [stat] equal to [amount]% of what they produce for themselves Example: \"Allied City-States provide [Culture] equal to [20]% of what they produce for themselves\" Applicable to: Global \ud83d\udd37 [amount]% resources gifted by City-States Example: \"[20]% resources gifted by City-States\" Applicable to: Global \ud83d\udd37 [amount]% Happiness from luxury resources gifted by City-States Example: \"[20]% Happiness from luxury resources gifted by City-States\" Applicable to: Global \ud83d\udd37 City-State Influence recovers at twice the normal rate Applicable to: Global \ud83d\udd37 [amount] units cost no maintenance Example: \"[20] units cost no maintenance\" Applicable to: Global \ud83d\udd37 Cannot build [baseUnitFilter] units Example: \"Cannot build [Melee] units\" Applicable to: Global \ud83d\udd37 [amount]% growth [cityFilter] Example: \"[20]% growth [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% Food is carried over after population increases [cityFilter] Example: \"[20]% Food is carried over after population increases [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 Gain a free [buildingName] [cityFilter] Example: \"Gain a free [Library] [in all cities]\" Applicable to: Global \ud83d\udd37 [amount]% Great Person generation [cityFilter] Example: \"[20]% Great Person generation [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% great person generation [cityFilter] Example: \"[20]% great person generation [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 May choose [amount] additional [beliefType] beliefs when [foundingOrEnhancing] a religion Example: \"May choose [20] additional [Follower] beliefs when [founding] a religion\" Applicable to: Global \ud83d\udd37 May choose [amount] additional belief(s) of any type when [foundingOrEnhancing] a religion Example: \"May choose [20] additional belief(s) of any type when [founding] a religion\" Applicable to: Global \ud83d\udd37 [amount]% unhappiness from population [cityFilter] Example: \"[20]% unhappiness from population [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% unhappiness from specialists [cityFilter] Example: \"[20]% unhappiness from specialists [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% Food consumption by specialists [cityFilter] Example: \"[20]% Food consumption by specialists [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 Provides 1 happiness per 2 additional social policies adopted Applicable to: Global \ud83d\udd37 [amount]% of excess happiness converted to [stat] Example: \"[20]% of excess happiness converted to [Culture]\" Applicable to: Global \ud83d\udd37 [amount]% Culture cost of natural border growth [cityFilter] Example: \"[20]% Culture cost of natural border growth [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% Gold cost of acquiring tiles [cityFilter] Example: \"[20]% Gold cost of acquiring tiles [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] at an increasing price ([amount]) Example: \"May buy [Melee] units for [20] [Culture] [in all cities] at an increasing price ([20])\" Applicable to: Global, FollowerBelief \ud83d\udd37 May buy [buildingFilter] buildings for [amount] [stat] [cityFilter] at an increasing price ([amount]) Example: \"May buy [Culture] buildings for [20] [Culture] [in all cities] at an increasing price ([20])\" Applicable to: Global, FollowerBelief \ud83d\udd37 May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] Example: \"May buy [Melee] units for [20] [Culture] [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 May buy [buildingFilter] buildings for [amount] [stat] [cityFilter] Example: \"May buy [Culture] buildings for [20] [Culture] [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 May buy [baseUnitFilter] units with [stat] [cityFilter] Example: \"May buy [Melee] units with [Culture] [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 May buy [buildingFilter] buildings with [stat] [cityFilter] Example: \"May buy [Culture] buildings with [Culture] [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 May buy [baseUnitFilter] units with [stat] for [amount] times their normal Production cost Example: \"May buy [Melee] units with [Culture] for [20] times their normal Production cost\" Applicable to: Global, FollowerBelief \ud83d\udd37 May buy [buildingFilter] buildings with [stat] for [amount] times their normal Production cost Example: \"May buy [Culture] buildings with [Culture] for [20] times their normal Production cost\" Applicable to: Global, FollowerBelief \ud83d\udd37 Enables conversion of city production to gold Applicable to: Global \ud83d\udd37 Enables conversion of city production to science Applicable to: Global \ud83d\udd37 [stat] cost of purchasing items in cities [amount]% Example: \"[Culture] cost of purchasing items in cities [20]%\" Applicable to: Global, FollowerBelief \ud83d\udd37 [stat] cost of purchasing [buildingFilter] buildings [amount]% Example: \"[Culture] cost of purchasing [Culture] buildings [20]%\" Applicable to: Global, FollowerBelief \ud83d\udd37 [stat] cost of purchasing [baseUnitFilter] units [amount]% Example: \"[Culture] cost of purchasing [Melee] units [20]%\" Applicable to: Global, FollowerBelief \ud83d\udd37 Improves movement speed on roads Applicable to: Global \ud83d\udd37 Roads connect tiles across rivers Applicable to: Global \ud83d\udd37 [amount]% maintenance on road & railroads Example: \"[20]% maintenance on road & railroads\" Applicable to: Global \ud83d\udd37 [amount]% maintenance cost for buildings [cityFilter] Example: \"[20]% maintenance cost for buildings [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 Receive a free Great Person at the end of every [comment] (every 394 years), after researching [tech]. Each bonus person can only be chosen once. Example: \"Receive a free Great Person at the end of every [comment] (every 394 years), after researching [Agriculture]. Each bonus person can only be chosen once.\" Applicable to: Global \ud83d\udd37 Once The Long Count activates, the year on the world screen displays as the traditional Mayan Long Count. Applicable to: Global \ud83d\udd37 Retain [amount]% of the happiness from a luxury after the last copy has been traded away Example: \"Retain [20]% of the happiness from a luxury after the last copy has been traded away\" Applicable to: Global \ud83d\udd37 [amount] Happiness from each type of luxury resource Example: \"[20] Happiness from each type of luxury resource\" Applicable to: Global \ud83d\udd37 Each city founded increases culture cost of policies [amount]% less than normal Example: \"Each city founded increases culture cost of policies [20]% less than normal\" Applicable to: Global \ud83d\udd37 [amount]% Culture cost of adopting new Policies Example: \"[20]% Culture cost of adopting new Policies\" Applicable to: Global \ud83d\udd37 Quantity of strategic resources produced by the empire +[amount]% Example: \"Quantity of strategic resources produced by the empire +[20]%\" Applicable to: Global \ud83d\udd37 Double quantity of [resource] produced Example: \"Double quantity of [Iron] produced\" Applicable to: Global \ud83d\udd37 Double Happiness from Natural Wonders Applicable to: Global \ud83d\udd37 Enables construction of Spaceship parts Applicable to: Global \ud83d\udd37 Enemy land units must spend 1 extra movement point when inside your territory (obsolete upon Dynamite) Applicable to: Global \ud83d\udd37 Production to science conversion in cities increased by 33% Applicable to: Global \ud83d\udd37 Notified of new Barbarian encampments Applicable to: Global \ud83d\udd37 \"Borrows\" city names from other civilizations in the game Applicable to: Global \ud83d\udd37 Units fight as though they were at full strength even when damaged Applicable to: Global \ud83d\udd37 100 Gold for discovering a Natural Wonder (bonus enhanced to 500 Gold if first to discover it) Applicable to: Global \ud83d\udd37 Unhappiness from number of Cities doubled Applicable to: Global \ud83d\udd37 Great General provides double combat bonus Applicable to: Global \ud83d\udd37 Receive a tech boost when scientific buildings/wonders are built in capital Applicable to: Global \ud83d\udd37 May not generate great prophet equivalents naturally Applicable to: Global \ud83d\udd37 67% chance to earn 25 Gold and recruit a Barbarian unit from a conquered encampment Applicable to: Global \ud83d\udd37 50% chance of capturing defeated Barbarian naval units and earning 25 Gold Applicable to: Global \ud83d\udd37 Receive triple Gold from Barbarian encampments and pillaging Cities Applicable to: Global \ud83d\udd37 Enables Open Borders agreements Applicable to: Global \ud83d\udd37 Enables Research agreements Applicable to: Global \ud83d\udd37 Science gained from research agreements [amount]% Example: \"Science gained from research agreements [20]%\" Applicable to: Global \ud83d\udd37 Triggers victory Applicable to: Global \ud83d\udd37 Triggers a Cultural Victory upon completion Applicable to: Global \ud83d\udd37 [amount]% City Strength from defensive buildings Example: \"[20]% City Strength from defensive buildings\" Applicable to: Global \ud83d\udd37 [amount]% tile improvement construction time Example: \"[20]% tile improvement construction time\" Applicable to: Global \ud83d\udd37 [amount]% Gold from Great Merchant trade missions Example: \"[20]% Gold from Great Merchant trade missions\" Applicable to: Global \ud83d\udd37 [mapUnitFilter] Units adjacent to this city heal [amount] HP per turn when healing Example: \"[Wounded] Units adjacent to this city heal [20] HP per turn when healing\" Applicable to: Global, FollowerBelief \ud83d\udd37 [amount]% Golden Age length Example: \"[20]% Golden Age length\" Applicable to: Global \ud83d\udd37 [amount]% Strength for cities Example: \"[20]% Strength for cities\" Applicable to: Global, FollowerBelief \ud83d\udd37 New [baseUnitFilter] units start with [amount] Experience [cityFilter] Example: \"New [Melee] units start with [20] Experience [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 All newly-trained [baseUnitFilter] units [cityFilter] receive the [promotion] promotion Example: \"All newly-trained [Melee] units [in all cities] receive the [Shock I] promotion\" Applicable to: Global, FollowerBelief \ud83d\udd37 [baseUnitFilter] units built [cityFilter] can [action] [amount] extra times Example: \"[Melee] units built [in all cities] can [action] [20] extra times\" Applicable to: Global, FollowerBelief \ud83d\udd37 Enables embarkation for land units Applicable to: Global \ud83d\udd37 Enables embarked units to enter ocean tiles Applicable to: Global \ud83d\udd37 Population loss from nuclear attacks [amount]% [cityFilter] Example: \"Population loss from nuclear attacks [20]% [in all cities]\" Applicable to: Global \ud83d\udd37 [amount]% Natural religion spread [cityFilter] Example: \"[20]% Natural religion spread [in all cities]\" Applicable to: Global, FollowerBelief \ud83d\udd37 Religion naturally spreads to cities [amount] tiles away Example: \"Religion naturally spreads to cities [20] tiles away\" Applicable to: Global, FollowerBelief \ud83d\udd37 Can be continually researched Applicable to: Global \ud83d\udd37 [amount] Unit Supply Example: \"[20] Unit Supply\" Applicable to: Global \ud83d\udd37 [amount] Unit Supply per [amount] population [cityFilter] Example: \"[20] Unit Supply per [20] population [in all cities]\" Applicable to: Global \ud83d\udd37 [amount] Unit Supply per city Example: \"[20] Unit Supply per city\" Applicable to: Global \ud83d\udd37 Units in cities cost no Maintenance Applicable to: Global \ud83d\udd37 Rebel units may spawn Applicable to: Global \ud83d\udd37 [amount]% Strength Example: \"[20]% Strength\" Applicable to: Global, Unit \ud83d\udd37 [amount]% Strength decreasing with distance from the capital Example: \"[20]% Strength decreasing with distance from the capital\" Applicable to: Global, Unit \ud83d\udd37 [amount]% to Flank Attack bonuses Example: \"[20]% to Flank Attack bonuses\" Applicable to: Global, Unit \ud83d\udd37 +30% Strength when fighting City-State units and cities Applicable to: Global \ud83d\udd37 [amount] Movement Example: \"[20] Movement\" Applicable to: Global, Unit \ud83d\udd37 [amount] Sight Example: \"[20] Sight\" Applicable to: Global, Unit, Terrain \ud83d\udd37 [amount] Range Example: \"[20] Range\" Applicable to: Global, Unit \ud83d\udd37 [amount] HP when healing Example: \"[20] HP when healing\" Applicable to: Global, Unit \ud83d\udd37 [amount]% Spread Religion Strength Example: \"[20]% Spread Religion Strength\" Applicable to: Global, Unit \ud83d\udd37 No defensive terrain bonus Applicable to: Global, Unit \ud83d\udd37 No defensive terrain penalty Applicable to: Global, Unit \ud83d\udd37 No movement cost to pillage Applicable to: Global, Unit \ud83d\udd37 May heal outside of friendly territory Applicable to: Global, Unit \ud83d\udd37 All healing effects doubled Applicable to: Global, Unit \ud83d\udd37 Heals [amount] damage if it kills a unit Example: \"Heals [20] damage if it kills a unit\" Applicable to: Global, Unit \ud83d\udd37 Can only heal by pillaging Applicable to: Global, Unit \ud83d\udd37 Normal vision when embarked Applicable to: Global, Unit \ud83d\udd37 Defense bonus when embarked Applicable to: Global, Unit \ud83d\udd37 Embarked units can defend themselves Applicable to: Global \ud83d\udd37 [amount]% maintenance costs Example: \"[20]% maintenance costs\" Applicable to: Global, Unit \ud83d\udd37 [amount]% Gold cost of upgrading Example: \"[20]% Gold cost of upgrading\" Applicable to: Global, Unit \ud83d\udd37 [greatPerson] is earned [amount]% faster Example: \"[greatPerson] is earned [20]% faster\" Applicable to: Global, Unit \ud83d\udd37 Earn [amount]% of the damage done to [mapUnitFilter] units as [plunderableStat] Example: \"Earn [20]% of the damage done to [Wounded] units as [Gold]\" Applicable to: Global, Unit \ud83d\udd37 Upon capturing a city, receive [amount] times its [stat] production as [plunderableStat] immediately Example: \"Upon capturing a city, receive [20] times its [Culture] production as [Gold] immediately\" Applicable to: Global, Unit \ud83d\udd37 Earn [amount]% of killed [mapUnitFilter] unit's [costOrStrength] as [plunderableStat] Example: \"Earn [20]% of killed [Wounded] unit's [Cost] as [Gold]\" Applicable to: Global, Unit \ud83d\udd37 [amount] XP gained from combat Example: \"[20] XP gained from combat\" Applicable to: Global, Unit \ud83d\udd37 [amount]% XP gained from combat Example: \"[20]% XP gained from combat\" Applicable to: Global, Unit \ud83d\udd37 This Unit upgrades for free Applicable to: Global Nation uniques \ud83d\udd37 Will not be chosen for new games Applicable to: Nation \ud83d\udd37 Starts with [tech] Example: \"Starts with [Agriculture]\" Applicable to: Nation Tech uniques \ud83d\udd37 Starting tech Applicable to: Tech \ud83d\udd37 Only available Applicable to: Tech, Policy, Building, Unit, Promotion, Improvement FollowerBelief uniques \ud83d\udd37 [amount]% [stat] from every follower, up to [amount]% Example: \"[20]% [Culture] from every follower, up to [20]%\" Applicable to: FollowerBelief \ud83d\udd37 Earn [amount]% of [mapUnitFilter] unit's [costOrStrength] as [plunderableStat] when killed within 4 tiles of a city following this religion Example: \"Earn [20]% of [Wounded] unit's [Cost] as [Gold] when killed within 4 tiles of a city following this religion\" Applicable to: FollowerBelief Building uniques \ud83d\udd37 Consumes [amount] [resource] Example: \"Consumes [20] [Iron]\" Applicable to: Building, Unit, Improvement \ud83d\udd37 Provides [amount] [resource] Example: \"Provides [20] [Iron]\" Applicable to: Building, Improvement \ud83d\udd37 Unbuildable Applicable to: Building, Unit \ud83d\udd37 Cannot be purchased Applicable to: Building, Unit \ud83d\udd37 Can be purchased with [stat] [cityFilter] Example: \"Can be purchased with [Culture] [in all cities]\" Applicable to: Building, Unit \ud83d\udd37 Can be purchased for [amount] [stat] [cityFilter] Example: \"Can be purchased for [20] [Culture] [in all cities]\" Applicable to: Building, Unit \ud83d\udd37 Limited to [amount] per Civilization Example: \"Limited to [20] per Civilization\" Applicable to: Building, Unit \ud83d\udd37 Hidden until [amount] social policy branches have been completed Example: \"Hidden until [20] social policy branches have been completed\" Applicable to: Building, Unit \ud83d\udd37 Excess Food converted to Production when under construction Applicable to: Building, Unit \ud83d\udd37 Requires at least [amount] population Example: \"Requires at least [20] population\" Applicable to: Building, Unit \ud83d\udd37 Cost increases by [amount] per owned city Example: \"Cost increases by [20] per owned city\" Applicable to: Building \ud83d\udd37 Requires a [buildingName] in all cities Example: \"Requires a [Library] in all cities\" Applicable to: Building \ud83d\udd37 Requires a [buildingName] in at least [amount] cities Example: \"Requires a [Library] in at least [20] cities\" Applicable to: Building \ud83d\udd37 Must be on [terrainFilter] Example: \"Must be on [Forest]\" Applicable to: Building \ud83d\udd37 Must not be on [terrainFilter] Example: \"Must not be on [Forest]\" Applicable to: Building \ud83d\udd37 Must be next to [terrainFilter] Example: \"Must be next to [Forest]\" Applicable to: Building, Improvement \ud83d\udd37 Must not be next to [terrainFilter] Example: \"Must not be next to [Forest]\" Applicable to: Building \ud83d\udd37 Unsellable Applicable to: Building \ud83d\udd37 Obsolete with [tech] Example: \"Obsolete with [Agriculture]\" Applicable to: Building, Improvement, Resource \ud83d\udd37 Indicates the capital city Applicable to: Building \ud83d\udd37 Provides 1 extra copy of each improved luxury resource near this City Applicable to: Building \ud83d\udd37 Destroyed when the city is captured Applicable to: Building \ud83d\udd37 Never destroyed when the city is captured Applicable to: Building \ud83d\udd37 Doubles Gold given to enemy if city is captured Applicable to: Building \ud83d\udd37 Remove extra unhappiness from annexed cities Applicable to: Building \ud83d\udd37 Spaceship part Applicable to: Building, Unit \ud83d\udd37 Hidden when religion is disabled Applicable to: Building, Unit, Ruins \ud83d\udd37 Hidden when [victoryType] Victory is disabled Example: \"Hidden when [Domination] Victory is disabled\" Applicable to: Building, Unit Unit uniques \ud83d\udd37 Founds a new city Applicable to: Unit \ud83d\udd37 Can construct [improvementName] Example: \"Can construct [Trading Post]\" Applicable to: Unit \ud83d\udd37 Can build [improvementFilter/terrainFilter] improvements on tiles Example: \"Can build [improvementFilter/terrainFilter] improvements on tiles\" Applicable to: Unit \ud83d\udd37 May create improvements on water resources Applicable to: Unit \ud83d\udd37 May found a religion Applicable to: Unit \ud83d\udd37 May enhance a religion Applicable to: Unit \ud83d\udd37 Can only attack [combatantFilter] units Example: \"Can only attack [City] units\" Applicable to: Unit \ud83d\udd37 Can only attack [tileFilter] tiles Example: \"Can only attack [Farm] tiles\" Applicable to: Unit \ud83d\udd37 Cannot attack Applicable to: Unit \ud83d\udd37 Must set up to ranged attack Applicable to: Unit \ud83d\udd37 Self-destructs when attacking Applicable to: Unit \ud83d\udd37 Blast radius [amount] Example: \"Blast radius [20]\" Applicable to: Unit \ud83d\udd37 Ranged attacks may be performed over obstacles Applicable to: Unit \ud83d\udd37 Uncapturable Applicable to: Unit \ud83d\udd37 May withdraw before melee ([amount]%) Example: \"May withdraw before melee ([20]%)\" Applicable to: Unit \ud83d\udd37 Unable to capture cities Applicable to: Unit \ud83d\udd37 Can move after attacking Applicable to: Unit \ud83d\udd37 Can move immediately once bought Applicable to: Unit \ud83d\udd37 Unit will heal every turn, even if it performs an action Applicable to: Unit \ud83d\udd37 All adjacent units heal [amount] HP when healing Example: \"All adjacent units heal [20] HP when healing\" Applicable to: Unit \ud83d\udd37 Eliminates combat penalty for attacking across a coast Applicable to: Unit \ud83d\udd37 6 tiles in every direction always visible Applicable to: Unit \ud83d\udd37 Can carry [amount] [mapUnitFilter] units Example: \"Can carry [20] [Wounded] units\" Applicable to: Unit \ud83d\udd37 Can carry [amount] extra [mapUnitFilter] units Example: \"Can carry [20] extra [Wounded] units\" Applicable to: Unit \ud83d\udd37 Cannot be carried by [mapUnitFilter] units Example: \"Cannot be carried by [Wounded] units\" Applicable to: Unit \ud83d\udd37 May capture killed [mapUnitFilter] units Example: \"May capture killed [Wounded] units\" Applicable to: Unit \ud83d\udd37 Invisible to others Applicable to: Unit \ud83d\udd37 Invisible to non-adjacent units Applicable to: Unit \ud83d\udd37 Can see invisible [mapUnitFilter] units Example: \"Can see invisible [Wounded] units\" Applicable to: Unit \ud83d\udd37 May upgrade to [baseUnitFilter] through ruins-like effects Example: \"May upgrade to [Melee] through ruins-like effects\" Applicable to: Unit \ud83d\udd37 Double movement in [terrainFilter] Example: \"Double movement in [Forest]\" Applicable to: Unit \ud83d\udd37 All tiles cost 1 movement Applicable to: Unit \ud83d\udd37 Can pass through impassable tiles Applicable to: Unit \ud83d\udd37 Ignores terrain cost Applicable to: Unit \ud83d\udd37 Ignores Zone of Control Applicable to: Unit \ud83d\udd37 Rough terrain penalty Applicable to: Unit \ud83d\udd37 Can enter ice tiles Applicable to: Unit \ud83d\udd37 Cannot enter ocean tiles Applicable to: Unit \ud83d\udd37 May enter foreign tiles without open borders Applicable to: Unit \ud83d\udd37 May enter foreign tiles without open borders, but loses [amount] religious strength each turn it ends there Example: \"May enter foreign tiles without open borders, but loses [20] religious strength each turn it ends there\" Applicable to: Unit \ud83d\udd37 Never appears as a Barbarian unit Applicable to: Unit \ud83d\udd37 Religious Unit Applicable to: Unit \ud83d\udd37 Can be added to [comment] in the Capital Example: \"Can be added to [comment] in the Capital\" Applicable to: Unit Promotion uniques \ud83d\udd37 Heal this unit by [amount] HP Example: \"Heal this unit by [20] HP\" Applicable to: Promotion Terrain uniques \ud83d\udd37 Must be adjacent to [amount] [simpleTerrain] tiles Example: \"Must be adjacent to [20] [Elevated] tiles\" Applicable to: Terrain \ud83d\udd37 Must be adjacent to [amount] to [amount] [simpleTerrain] tiles Example: \"Must be adjacent to [20] to [20] [Elevated] tiles\" Applicable to: Terrain \ud83d\udd37 Must not be on [amount] largest landmasses Example: \"Must not be on [20] largest landmasses\" Applicable to: Terrain \ud83d\udd37 Must be on [amount] largest landmasses Example: \"Must be on [20] largest landmasses\" Applicable to: Terrain \ud83d\udd37 Occurs on latitudes from [amount] to [amount] percent of distance equator to pole Example: \"Occurs on latitudes from [20] to [20] percent of distance equator to pole\" Applicable to: Terrain \ud83d\udd37 Occurs in groups of [amount] to [amount] tiles Example: \"Occurs in groups of [20] to [20] tiles\" Applicable to: Terrain \ud83d\udd37 Neighboring tiles will convert to [baseTerrain] Example: \"Neighboring tiles will convert to [Grassland]\" Applicable to: Terrain \ud83d\udd37 Neighboring tiles except [baseTerrain] will convert to [baseTerrain] Example: \"Neighboring tiles except [Grassland] will convert to [Grassland]\" Applicable to: Terrain \ud83d\udd37 Grants 500 Gold to the first civilization to discover it Applicable to: Terrain \ud83d\udd37 Units ending their turn on this terrain take [amount] damage Example: \"Units ending their turn on this terrain take [20] damage\" Applicable to: Terrain \ud83d\udd37 Grants [promotion] ([comment]) to adjacent [mapUnitFilter] units for the rest of the game Example: \"Grants [Shock I] ([comment]) to adjacent [Wounded] units for the rest of the game\" Applicable to: Terrain \ud83d\udd37 [amount] Strength for cities built on this terrain Example: \"[20] Strength for cities built on this terrain\" Applicable to: Terrain \ud83d\udd37 Provides a one-time Production bonus to the closest city when cut down Applicable to: Terrain \ud83d\udd37 Tile provides yield without assigned population Applicable to: Terrain, Improvement \ud83d\udd37 Nullifies all other stats this tile provides Applicable to: Terrain \ud83d\udd37 Only [improvementFilter] improvements may be built on this tile Example: \"Only [All Road] improvements may be built on this tile\" Applicable to: Terrain \ud83d\udd37 Blocks line-of-sight from tiles at same elevation Applicable to: Terrain \ud83d\udd37 Has an elevation of [amount] for visibility calculations Example: \"Has an elevation of [20] for visibility calculations\" Applicable to: Terrain \ud83d\udd37 Always Fertility [amount] for Map Generation Example: \"Always Fertility [20] for Map Generation\" Applicable to: Terrain \ud83d\udd37 [amount] to Fertility for Map Generation Example: \"[20] to Fertility for Map Generation\" Applicable to: Terrain \ud83d\udd37 A Region is formed with at least [amount]% [simpleTerrain] tiles, with priority [amount] Example: \"A Region is formed with at least [20]% [Elevated] tiles, with priority [20]\" Applicable to: Terrain \ud83d\udd37 A Region is formed with at least [amount]% [simpleTerrain] tiles and [simpleTerrain] tiles, with priority [amount] Example: \"A Region is formed with at least [20]% [Elevated] tiles and [Elevated] tiles, with priority [20]\" Applicable to: Terrain \ud83d\udd37 A Region can not contain more [simpleTerrain] tiles than [simpleTerrain] tiles Example: \"A Region can not contain more [Elevated] tiles than [Elevated] tiles\" Applicable to: Terrain \ud83d\udd37 Base Terrain on this tile is not counted for Region determination Applicable to: Terrain \ud83d\udd37 Starts in regions of this type receive an extra [resource] Example: \"Starts in regions of this type receive an extra [Iron]\" Applicable to: Terrain \ud83d\udd37 Never receives any resources Applicable to: Terrain \ud83d\udd37 Becomes [terrainName] when adjacent to [terrainFilter] Example: \"Becomes [terrainName] when adjacent to [Forest]\" Applicable to: Terrain \ud83d\udd37 Considered [terrainQuality] when determining start locations Example: \"Considered [Undesirable] when determining start locations\" Applicable to: Terrain \ud83d\udd37 Doesn't generate naturally Applicable to: Terrain, Resource \ud83d\udd37 Occurs at temperature between [amount] and [amount] and humidity between [amount] and [amount] Example: \"Occurs at temperature between [20] and [20] and humidity between [20] and [20]\" Applicable to: Terrain \ud83d\udd37 Occurs in chains at high elevations Applicable to: Terrain \ud83d\udd37 Occurs in groups around high elevations Applicable to: Terrain \ud83d\udd37 Every [amount] tiles with this terrain will receive a major deposit of a strategic resource. Example: \"Every [20] tiles with this terrain will receive a major deposit of a strategic resource.\" Applicable to: Terrain \ud83d\udd37 Rare feature Applicable to: Terrain \ud83d\udd37 Resistant to nukes Applicable to: Terrain \ud83d\udd37 Can be destroyed by nukes Applicable to: Terrain \ud83d\udd37 Fresh water Applicable to: Terrain \ud83d\udd37 Rough terrain Applicable to: Terrain Improvement uniques \ud83d\udd37 Can also be built on tiles adjacent to fresh water Applicable to: Improvement \ud83d\udd37 [stats] from [tileFilter] tiles Example: \"[+1 Gold, +2 Production] from [Farm] tiles\" Applicable to: Improvement \ud83d\udd37 [stats] for each adjacent [tileFilter] Example: \"[+1 Gold, +2 Production] for each adjacent [Farm]\" Applicable to: Improvement \ud83d\udd37 Can be built outside your borders Applicable to: Improvement \ud83d\udd37 Can be built just outside your borders Applicable to: Improvement \ud83d\udd37 Cannot be built on [tileFilter] tiles Example: \"Cannot be built on [Farm] tiles\" Applicable to: Improvement \ud83d\udd37 Does not need removal of [tileFilter] Example: \"Does not need removal of [Farm]\" Applicable to: Improvement \ud83d\udd37 Gives a defensive bonus of [amount]% Example: \"Gives a defensive bonus of [20]%\" Applicable to: Improvement \ud83d\udd37 Costs [amount] gold per turn when in your territory Example: \"Costs [20] gold per turn when in your territory\" Applicable to: Improvement \ud83d\udd37 Adjacent enemy units ending their turn take [amount] damage Example: \"Adjacent enemy units ending their turn take [20] damage\" Applicable to: Improvement \ud83d\udd37 Great Improvement Applicable to: Improvement \ud83d\udd37 Provides a random bonus when entered Applicable to: Improvement \ud83d\udd37 Unpillagable Applicable to: Improvement \ud83d\udd37 Indestructible Applicable to: Improvement \ud83d\udd37 Irremovable Applicable to: Improvement Resource uniques \ud83d\udd37 Generated with weight [amount] Example: \"Generated with weight [20]\" Applicable to: Resource \ud83d\udd37 Minor deposits generated with weight [amount] Example: \"Minor deposits generated with weight [20]\" Applicable to: Resource \ud83d\udd37 Generated near City States with weight [amount] Example: \"Generated near City States with weight [20]\" Applicable to: Resource \ud83d\udd37 Special placement during map generation Applicable to: Resource \ud83d\udd37 Generated on every [amount] tiles Example: \"Generated on every [20] tiles\" Applicable to: Resource \ud83d\udd37 Guaranteed with Strategic Balance resource option Applicable to: Resource \ud83d\udd37 Deposits in [tileFilter] tiles always provide [amount] resources Example: \"Deposits in [Farm] tiles always provide [20] resources\" Applicable to: Resource \ud83d\udd37 Can only be created by Mercantile City-States Applicable to: Resource Ruins uniques \ud83d\udd37 Free [baseUnitFilter] found in the ruins Example: \"Free [Melee] found in the ruins\" Applicable to: Ruins \ud83d\udd37 [amount] population in a random city Example: \"[20] population in a random city\" Applicable to: Ruins \ud83d\udd37 [amount] free random researchable Tech(s) from the [era] Example: \"[20] free random researchable Tech(s) from the [Ancient era]\" Applicable to: Ruins \ud83d\udd37 Gain [amount] [stat] Example: \"Gain [20] [Culture]\" Applicable to: Ruins \ud83d\udd37 Gain [amount]-[amount] [stat] Example: \"Gain [20]-[20] [Culture]\" Applicable to: Ruins \ud83d\udd37 Gain enough Faith for a Pantheon Applicable to: Ruins \ud83d\udd37 Gain enough Faith for [amount]% of a Great Prophet Example: \"Gain enough Faith for [20]% of a Great Prophet\" Applicable to: Ruins \ud83d\udd37 Reveal up to [amount/'all'] [tileFilter] within a [amount] tile radius Example: \"Reveal up to [amount/'all'] [Farm] within a [20] tile radius\" Applicable to: Ruins \ud83d\udd37 From a randomly chosen tile [amount] tiles away from the ruins, reveal tiles up to [amount] tiles away with [amount]% chance Example: \"From a randomly chosen tile [20] tiles away from the ruins, reveal tiles up to [20] tiles away with [20]% chance\" Applicable to: Ruins \ud83d\udd37 This Unit gains [amount] XP Example: \"This Unit gains [20] XP\" Applicable to: Ruins \ud83d\udd37 This Unit upgrades for free including special upgrades Applicable to: Ruins \ud83d\udd37 Only available after [amount] turns Example: \"Only available after [20] turns\" Applicable to: Ruins \ud83d\udd37 Hidden before founding a Pantheon Applicable to: Ruins \ud83d\udd37 Hidden after founding a Pantheon Applicable to: Ruins \ud83d\udd37 Hidden after generating a Great Prophet Applicable to: Ruins CityState uniques \ud83d\udd37 Provides [stats] per turn Example: \"Provides [+1 Gold, +2 Production] per turn\" Applicable to: CityState \ud83d\udd37 Provides [stats] [cityFilter] per turn Example: \"Provides [+1 Gold, +2 Production] [in all cities] per turn\" Applicable to: CityState \ud83d\udd37 Provides [amount] Happiness Example: \"Provides [20] Happiness\" Applicable to: CityState \ud83d\udd37 Provides military units every \u2248[amount] turns Example: \"Provides military units every \u2248[20] turns\" Applicable to: CityState \ud83d\udd37 Provides a unique luxury Applicable to: CityState Conditional uniques \ud83d\udd37 Applicable to: Conditional \ud83d\udd37 Applicable to: Conditional \ud83d\udd37 Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Applicable to: Conditional \ud83d\udd37 Applicable to: Conditional \ud83d\udd37 Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional \ud83d\udd37 Example: \" \" Applicable to: Conditional Deprecated uniques \"[stats] from every Wonder\" - Deprecated as of 3.19.1, replace with \"[stats] from every [Wonder]\" \"[stats] from every [buildingFilter] in cities where this religion has at least [amount] followers\" - Deprecated as of 3.19.3, replace with \"[stats] from every [buildingFilter] \" \"+25% Production towards any buildings that already exist in the Capital\" - Deprecated as of 3.19.3, replace with \"[+25]% Production towards any buildings that already exist in the Capital\" \"[amount]% of food is carried over after population increases\" - Deprecated as of 3.19.2, replace with \"[amount]% Food is carried over after population increases [in this city]\" \"[amount]% of food is carried over [cityFilter] after population increases\" - Deprecated as of 3.19.2, replace with \"[amount]% Food is carried over after population increases [cityFilter]\" \"[amount]% Culture cost of natural border growth [cityFilter]\" - Deprecated as of 3.19.2, replace with \"[amount]% Culture cost of natural border growth [cityFilter]\" \"-[amount]% Culture cost of acquiring tiles [cityFilter]\" - Deprecated as of 3.19.1, replace with \"[-amount]% Culture cost of natural border growth [cityFilter]\" \"[amount]% cost of natural border growth\" - Deprecated as of 3.19.1, replace with \"[amount]% Culture cost of natural border growth [in all cities]\" \"-[amount]% Gold cost of acquiring tiles [cityFilter]\" - Deprecated as of 3.19.1, replace with \"[-amount]% Gold cost of acquiring tiles [cityFilter]\" \"[stat] cost of purchasing [baseUnitFilter] units in cities [amount]%\" - Deprecated as of 3.19.3, replace with \"[stat] cost of purchasing [baseUnitFilter] units [amount]%\" \"+[amount]% attacking strength for cities with garrisoned units\" - Deprecated as of 3.19.1, replace with \"[+amount]% Strength for cities \" \"Can embark and move over Coasts and Oceans immediately\" - Deprecated as of 3.19.9, replace with \"Enables embarkation for land units \", \"Enables embarked units to enter ocean tiles \" \"Population loss from nuclear attacks -[amount]%\" - Deprecated as of 3.19.2, replace with \"Population loss from nuclear attacks [-amount]% [in this city]\" \"[amount]% Natural religion spread [cityFilter] with [tech/policy]\" - Deprecated as of 3.19.3, replace with \"[amount]% Natural religion spread [cityFilter] \" OR \"[amount]% Natural religion spread [cityFilter] \" \"[amount] HP when healing in [tileFilter] tiles\" - Deprecated as of 3.19.4, replace with \"[amount] HP when healing \" \"Melee units pay no movement cost to pillage\" - Deprecated as of 3.18.17, replace with \"No movement cost to pillage \" \"Heal adjacent units for an additional 15 HP per turn\" - Deprecated as of 3.19.3, replace with \"All adjacent units heal [+15] HP when healing\" \"+[amount]% attack strength to all [mapUnitFilter] units for [amount2] turns\" - Deprecated as of 3.19.8, replace with \"[+amount]% Strength \" \"Golden Age length increased by [amount]%\" - Deprecated as of 3.18.17, replace with \"[+amount]% Golden Age length\" \"+[amount]% Defensive Strength for cities\" - Deprecated as of 3.18.17, replace with \"[+amount]% Strength for cities \" \"[amount]% Attacking Strength for cities\" - Deprecated as of 3.18.17, replace with \"[+amount]% Strength for cities \" \"[amount]% Strength for [mapUnitFilter] units which have another [mapUnitFilter] unit in an adjacent tile\" - Deprecated as of 3.18.17, replace with \"[amount]% Strength \" \"Gold cost of upgrading [baseUnitFilter] units reduced by [amount]%\" - Deprecated as of 3.18.17, replace with \"[-amount]% Gold cost of upgrading \" \"Double gold from Great Merchant trade missions\" - Deprecated as of 3.18.17, replace with \"[+100]% Gold from Great Merchant trade missions\" \"Defensive buildings in all cities are 25% more effective\" - Deprecated as of 3.18.17, replace with \"[+25]% City Strength from defensive buildings\" \"Maintenance on roads & railroads reduced by [amount]%\" - Deprecated as of 3.18.17, replace with \"[-amount]% maintenance on road & railroads\" \"-[amount]% maintenance cost for buildings [cityFilter]\" - Deprecated as of 3.18.17, replace with \"[-amount]% maintenance cost for buildings [cityFilter]\" \"+[amount] happiness from each type of luxury resource\" - Deprecated as of 3.18.17, replace with \"[+amount] Happiness from each type of luxury resource\" \"Culture cost of adopting new Policies reduced by [amount]%\" - Deprecated as of 3.18.17, replace with \"[-amount]% Culture cost of adopting new Policies\" \"[amount]% Culture cost of adopting new policies\" - Deprecated as of 3.19.1, replace with \"[amount]% Culture cost of adopting new Policies\" \"Quantity of Resources gifted by City-States increased by [amount]%\" - Deprecated as of 3.18.17, replace with \"[+amount]% resources gifted by City-States\" \"City-State Influence degrades [amount]% slower\" - Deprecated as of 3.18.17, replace with \"[-amount]% City-State Influence degradation\" \"Happiness from Luxury Resources gifted by City-States increased by [amount]%\" - Deprecated as of 3.18.17, replace with \"[+amount]% Happiness from luxury resources gifted by City-States\" \"+[amount]% [stat] from every [tileFilter/specialist/buildingName]\" - Deprecated as of 3.18.17, replace with \"[+amount]% [stat] from every [tileFilter/specialist/buildingName]\" \"+[amount]% yield from every [tileFilter]\" - Deprecated as of 3.18.17, replace with \"[+amount]% Yield from every [tileFilter]\" \"[stats] per turn from cities before [tech/policy]\" - Deprecated as of 3.18.14, replace with \"[stats] [in all cities] \" OR \"[stats] [in all cities] \" \"[mapUnitFilter] units gain [amount]% more Experience from combat\" - Deprecated as of 3.18.12, replace with \"[amount]% XP gained from combat \" \"[amount]% maintenance costs for [mapUnitFilter] units\" - Deprecated as of 3.18.14, replace with \"[amount]% maintenance costs \" \"50% of excess happiness added to culture towards policies\" - Deprecated as of 3.18.2, replace with \"[50]% of excess happiness converted to [Culture]\" \"-[amount]% food consumption by specialists [cityFilter]\" - Deprecated as of 3.18.2, replace with \"[-amount]% Food consumption by specialists [cityFilter]\" \"May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] starting from the [era] at an increasing price ([amount])\" - Deprecated as of 3.17.9, removed as of 3.19.3, replace with \"May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] at an increasing price ([amount]) \" \"Provides a free [buildingName] [cityFilter]\" - Deprecated as of 3.17.7 - removed 3.18.19, replace with \"Gain a free [buildingName] [cityFilter]\" \"+[amount]% [stat] [cityFilter]\" - Deprecated as of 3.17.10 - removed 3.18.18, replace with \"[+amount]% [stat] [cityFilter]\" \"+[amount]% [stat] in all cities\" - Deprecated as of 3.17.10 - removed 3.18.18, replace with \"[+amount]% [stat] [in all cities]\" \"[amount]% [stat] while the empire is happy\" - Deprecated as of 3.17.1 - removed 3.18.18, replace with \"[amount]% [stat] [in all cities] \" \"Immediately creates the cheapest available cultural building in each of your first [amount] cities for free\" - Deprecated as of 3.16.15 - removed 3.18.4, replace with \"Provides the cheapest [stat] building in your first [amount] cities for free\" \"Immediately creates a [buildingName] in each of your first [amount] cities for free\" - Deprecated as of 3.16.15 - removed 3.18.4, replace with \"Provides a [buildingName] in your first [amount] cities for free\" \"[mapUnitFilter] units deal +[amount]% damage\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+amount]% Strength \" \"+10% Strength for all units during Golden Age\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+10]% Strength \" \"[amount]% Strength for [mapUnitFilter] units in [tileFilter]\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount]% Strength \" \"+15% Combat Strength for all units when attacking Cities\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+15]% Strength \" \"+[amount] Movement for all [mapUnitFilter] units\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+amount] Movement \" \"+1 Movement for all units during Golden Age\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+1] Movement \" \"[amount] Sight for all [mapUnitFilter] units\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount] Sight \" \"[amount]% Spread Religion Strength for [mapUnitFilter] units\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount]% Spread Religion Strength \" \"+[amount]% Production when constructing [baseUnitFilter] units [cityFilter]\" - Deprecated as of 3.17.10 - removed 3.18.5, replace with \"[+amount]% Production when constructing [baseUnitFilter] units [cityFilter]\" \"+[amount]% Production when constructing [stat] buildings\" - Deprecated as of 3.17.10 - removed 3.18.5, replace with \"[+amount]% Production when constructing [stat] buildings [in all cities]\" \"+[amount]% Production when constructing [constructionFilter]\" - Deprecated as of 3.17.10 - removed 3.18.5, replace with \"[+amount]% Production when constructing [constructionFilter] buildings [in all cities]\" \"+[amount]% Production when constructing a [buildingName]\" - Deprecated as of 3.17.10 - removed 3.18.5, replace with \"[amount]% Production when constructing [buildingName] buildings [in all cities]\" \"+[amount]% Production when constructing [constructionFilter] [cityFilter]\" - Deprecated as of 3.17.10 - removed 3.18.5, replace with \"[amount]% Production when constructing [constructionFilter] buildings [cityFilter]\" \"Increases embarked movement +1\" - Deprecated As of 3.16.11 - removed 3.17.11, replace with \"[+1] Movement \" \"+1 Movement for all embarked units\" - Deprecated As of 3.16.11 - removed 3.17.11, replace with \"[+1] Movement \" \"Unhappiness from population decreased by [amount]%\" - Deprecated As of 3.16.11 - removed 3.17.11, replace with \"[-amount]% unhappiness from population [in all cities]\" \"Unhappiness from population decreased by [amount]% [cityFilter]\" - Deprecated As of 3.16.11 - removed 3.17.11, replace with \"[-amount]% unhappiness from population [cityFilter]\" \"+[amount]% growth [cityFilter]\" - Deprecated As of 3.16.14 - removed 3.17.11, replace with \"[+amount]% growth [cityFilter]\" \"+[amount]% growth [cityFilter] when not at war\" - Deprecated As of 3.16.14 - removed 3.17.11, replace with \"[+amount]% growth [cityFilter] \" \"-[amount]% [mapUnitFilter] unit maintenance costs\" - Deprecated As of 3.16.16 - removed as of 3.17.11, replace with \"[-amount]% maintenance costs \" \"-[amount]% unit upkeep costs\" - Deprecated As of 3.16.16 - removed 3.17.11, replace with \"[amount]% maintenance costs \" \"[stats] from every specialist\" - Deprecated As of 3.16.16 - removed 3.17.11, replace with \"[stats] from every specialist [in all cities]\" \"[stats] if this city has at least [amount] specialists\" - Deprecated As of 3.16.16 - removed 3.17.11, replace with \"[stats] \" \"+1 happiness from each type of luxury resource\" - Deprecated Extremely old - used for auto-updates only, replace with \"[+1] Happiness from each type of luxury resource\" \"-33% unit upkeep costs\" - Deprecated Extremely old - used for auto-updates only, replace with \"[-33]% maintenance costs \" \"-50% food consumption by specialists\" - Deprecated Extremely old - used for auto-updates only, replace with \"[-50]% Food consumption by specialists [in all cities]\" \"+50% attacking strength for cities with garrisoned units\" - Deprecated Extremely old - used for auto-updates only, replace with \"[+50]% Strength for cities \" \"Incompatible with [policy/tech/promotion]\" - Deprecated as of 3.19.8, replace with \"Only available \" OR \"Only available \" OR \"Only available \" \"Not displayed as an available construction without [buildingName/tech/resource/policy]\" - Deprecated as of 3.19.8, replace with \"Only available \" OR \"Only available \" OR \"Only available \" OR \"Only available \" \"Unlocked with [buildingName/tech/era/policy]\" - Deprecated as of 3.19.12, replace with \"Only available \" OR \"Only available \" OR \"Only available \" OR \"Only available \" \"Requires [buildingName/tech/era/policy]\" - Deprecated as of 3.19.12, replace with \"Only available \" OR \"Only available \" OR \"Only available \" OR \"Only available \" \"Cannot be built with [buildingName]\" - Deprecated as of 3.19.9, replace with \"Only available \" \"Requires a [buildingName] in this city\" - Deprecated as of 3.19.9, replace with \"Only available \" \"[stats] with [resource]\" - Deprecated as of 3.19.7, replace with \"[stats] \" \"Not displayed as an available construction unless [buildingName] is built\" - Deprecated as of 3.16.11, replace with \"Not displayed as an available construction without [buildingName]\" \"[stats] once [tech] is discovered\" - Deprecated as of 3.17.10 - removed 3.18.19, replace with \"[stats] \" \"Eliminates combat penalty for attacking from the sea\" - Deprecated as of 3.19.8, replace with \"Eliminates combat penalty for attacking across a coast\" \"[amount]% Bonus XP gain\" - Deprecated as of 3.18.12, replace with \"[amount]% XP gained from combat\" \"Cannot enter ocean tiles until Astronomy\" - Deprecated as of 3.18.6, replace with \"Cannot enter ocean tiles \" \"+[amount]% Strength when attacking\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+amount]% Strength \" \"+[amount]% Strength when defending\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+amount]% Strength \" \"[amount]% Strength when defending vs [mapUnitFilter] units\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount]% Strength \" \"+[amount]% defence in [tileFilter] tiles\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount]% Strength \" \"+[amount]% Strength in [tileFilter]\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount]% Strength \" \"[amount] Visibility Range\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount] Sight\" \"Limited Visibility\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[-1] Sight\" \"Double movement in coast\" - Deprecated As of 3.17.1 - removed 3.17.13, replace with \"Double movement in [Coast]\" \"Double movement rate through Forest and Jungle\" - Deprecated As of 3.17.1 - removed 3.17.13, replace with \"Double movement in [terrainFilter]\" \"Double movement in Snow, Tundra and Hills\" - Deprecated As of 3.17.1 - removed 3.17.13, replace with \"Double movement in [terrainFilter]\" \"+[amount]% Strength\" - Deprecated As of 3.17.3 - removed 3.17.13, replace with \"[+amount]% Strength\" \"-[amount]% Strength\" - Deprecated As of 3.17.3 - removed 3.17.13, replace with \"[-amount]% Strength\" \"+[amount]% Strength vs [combatantFilter]\" - Deprecated As of 3.17.3 - removed 3.17.13, replace with \"[+amount]% Strength \" OR \"[+amount]% Strength \" \"-[amount]% Strength vs [combatantFilter]\" - Deprecated As of 3.17.3 - removed 3.17.13, replace with \"[-amount]% Strength \" OR \"[+amount]% Strength \" \"+[amount]% Combat Strength\" - Deprecated As of 3.17.3 - removed 3.17.13, replace with \"[+amount]% Strength\" \"+1 Visibility Range\" - Deprecated Extremely old - used for auto-updates only, replace with \"[+1] Sight\" \"+[amount] Visibility Range\" - Deprecated Extremely old - used for auto-updates only, replace with \"[+amount] Sight\" \"+[amount] Sight for all [mapUnitFilter] units\" - Deprecated Extremely old - used for auto-updates only, replace with \"[+amount] Sight \" \"+2 Visibility Range\" - Deprecated Extremely old - used for auto-updates only, replace with \"[+2] Sight\" \"Can build improvements on tiles\" - Deprecated Extremely old - used for auto-updates only, replace with \"Can build [Land] improvements on tiles\" \"Science gained from research agreements +50%\" - Deprecated Extremely old - used for auto-updates only, replace with \"Science gained from research agreements [+50]%\" \"Deal [amount] damage to adjacent enemy units\" - Deprecated as of 3.18.17, replace with \"Adjacent enemy units ending their turn take [amount] damage\" \"Cannot be built on [tileFilter] tiles until [tech] is discovered\" - Deprecated as of 3.18.5, replace with \"Cannot be built on [tileFilter] tiles \" \"[stats] on [tileFilter] tiles once [tech] is discovered\" - Deprecated as of 3.17.10 - removed 3.18.19, replace with \"[stats] from [tileFilter] tiles \" \"Deal 30 damage to adjacent enemy units\" - Deprecated as of 3.17.10 - removed 3.18.19, replace with \"Adjacent enemy units ending their turn take [30] damage\"","title":"Uniques"},{"location":"uniques/#table-of-contents","text":"Triggerable uniques Global uniques Nation uniques Tech uniques FollowerBelief uniques Building uniques Unit uniques Promotion uniques Terrain uniques Improvement uniques Resource uniques Ruins uniques CityState uniques Conditional uniques Deprecated uniques","title":"Table of Contents"},{"location":"uniques/#triggerable-uniques","text":"","title":"Triggerable uniques"},{"location":"uniques/#free-baseunitfilter-appears","text":"Example: \"Free [Melee] appears\" Applicable to: Triggerable","title":"🔷 Free [baseUnitFilter] appears"},{"location":"uniques/#amount-free-baseunitfilter-units-appear","text":"Example: \"[20] free [Melee] units appear\" Applicable to: Triggerable","title":"🔷 [amount] free [baseUnitFilter] units appear"},{"location":"uniques/#free-social-policy","text":"Applicable to: Triggerable","title":"🔷 Free Social Policy"},{"location":"uniques/#amount-free-social-policies","text":"Example: \"[20] Free Social Policies\" Applicable to: Triggerable","title":"🔷 [amount] Free Social Policies"},{"location":"uniques/#empire-enters-golden-age","text":"Applicable to: Triggerable","title":"🔷 Empire enters golden age"},{"location":"uniques/#free-great-person","text":"Applicable to: Triggerable","title":"🔷 Free Great Person"},{"location":"uniques/#amount-population-cityfilter","text":"Example: \"[20] population [in all cities]\" Applicable to: Triggerable","title":"🔷 [amount] population [cityFilter]"},{"location":"uniques/#free-technology","text":"Applicable to: Triggerable","title":"🔷 Free Technology"},{"location":"uniques/#amount-free-technologies","text":"Example: \"[20] Free Technologies\" Applicable to: Triggerable","title":"🔷 [amount] Free Technologies"},{"location":"uniques/#reveals-the-entire-map","text":"Applicable to: Triggerable","title":"🔷 Reveals the entire map"},{"location":"uniques/#triggers-voting-for-the-diplomatic-victory","text":"Applicable to: Triggerable","title":"🔷 Triggers voting for the Diplomatic Victory"},{"location":"uniques/#this-unit-gains-the-promotion-promotion","text":"Example: \"This Unit gains the [Shock I] promotion\" Applicable to: Triggerable","title":"🔷 This Unit gains the [promotion] promotion"},{"location":"uniques/#mapunitfilter-units-gain-the-promotion-promotion","text":"Example: \"[Wounded] units gain the [Shock I] promotion\" Applicable to: Triggerable","title":"🔷 [mapUnitFilter] units gain the [promotion] promotion"},{"location":"uniques/#provides-the-cheapest-stat-building-in-your-first-amount-cities-for-free","text":"Example: \"Provides the cheapest [Culture] building in your first [20] cities for free\" Applicable to: Triggerable","title":"🔷 Provides the cheapest [stat] building in your first [amount] cities for free"},{"location":"uniques/#provides-a-buildingname-in-your-first-amount-cities-for-free","text":"Example: \"Provides a [Library] in your first [20] cities for free\" Applicable to: Triggerable","title":"🔷 Provides a [buildingName] in your first [amount] cities for free"},{"location":"uniques/#will-not-be-displayed-in-civilopedia","text":"Applicable to: Triggerable, Global, Nation, Era, Tech, Policy, FounderBelief, FollowerBelief, Building, Wonder, Unit, UnitType, Promotion, Terrain, Improvement, Resource, Ruins, CityState, ModOptions, Conditional","title":"🔷 Will not be displayed in Civilopedia"},{"location":"uniques/#global-uniques","text":"","title":"Global uniques"},{"location":"uniques/#stats","text":"Example: \"[+1 Gold, +2 Production]\" Applicable to: Global, FollowerBelief, Improvement","title":"🔷 [stats]"},{"location":"uniques/#stats-cityfilter","text":"Example: \"[+1 Gold, +2 Production] [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [stats] [cityFilter]"},{"location":"uniques/#stats-from-every-specialist-cityfilter","text":"Example: \"[+1 Gold, +2 Production] from every specialist [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [stats] from every specialist [cityFilter]"},{"location":"uniques/#stats-per-amount-population-cityfilter","text":"Example: \"[+1 Gold, +2 Production] per [20] population [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [stats] per [amount] population [cityFilter]"},{"location":"uniques/#stats-in-cities-with-amount-or-more-population","text":"Example: \"[+1 Gold, +2 Production] in cities with [20] or more population\" Applicable to: Global, FollowerBelief","title":"🔷 [stats] in cities with [amount] or more population"},{"location":"uniques/#stats-in-cities-on-terrainfilter-tiles","text":"Example: \"[+1 Gold, +2 Production] in cities on [Forest] tiles\" Applicable to: Global, FollowerBelief","title":"🔷 [stats] in cities on [terrainFilter] tiles"},{"location":"uniques/#stats-from-all-buildingfilter-buildings","text":"Example: \"[+1 Gold, +2 Production] from all [Culture] buildings\" Applicable to: Global, FollowerBelief","title":"🔷 [stats] from all [buildingFilter] buildings"},{"location":"uniques/#stats-whenever-a-great-person-is-expended","text":"Example: \"[+1 Gold, +2 Production] whenever a Great Person is expended\" Applicable to: Global","title":"🔷 [stats] whenever a Great Person is expended"},{"location":"uniques/#stats-from-tilefilter-tiles-cityfilter","text":"Example: \"[+1 Gold, +2 Production] from [Farm] tiles [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [stats] from [tileFilter] tiles [cityFilter]"},{"location":"uniques/#stats-from-tilefilter-tiles-without-tilefilter-cityfilter","text":"Example: \"[+1 Gold, +2 Production] from [Farm] tiles without [Farm] [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [stats] from [tileFilter] tiles without [tileFilter] [cityFilter]"},{"location":"uniques/#stats-from-every-tilefilterspecialistbuildingfilter","text":"Example: \"[+1 Gold, +2 Production] from every [tileFilter/specialist/buildingFilter]\" Applicable to: Global, FollowerBelief","title":"🔷 [stats] from every [tileFilter/specialist/buildingFilter]"},{"location":"uniques/#stats-from-each-trade-route","text":"Example: \"[+1 Gold, +2 Production] from each Trade Route\" Applicable to: Global, FollowerBelief","title":"🔷 [stats] from each Trade Route"},{"location":"uniques/#amount-stat","text":"Example: \"[20]% [Culture]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% [stat]"},{"location":"uniques/#amount-stat-cityfilter","text":"Example: \"[20]% [Culture] [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% [stat] [cityFilter]"},{"location":"uniques/#amount-stat-from-every-tilefilterspecialistbuildingname","text":"Example: \"[20]% [Culture] from every [tileFilter/specialist/buildingName]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% [stat] from every [tileFilter/specialist/buildingName]"},{"location":"uniques/#amount-yield-from-every-tilefilter","text":"Example: \"[20]% Yield from every [Farm]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% Yield from every [tileFilter]"},{"location":"uniques/#amount-stat-from-city-states","text":"Example: \"[20]% [Culture] from City-States\" Applicable to: Global","title":"🔷 [amount]% [stat] from City-States"},{"location":"uniques/#gold-from-all-trade-routes-25","text":"Applicable to: Global","title":"🔷 Gold from all trade routes +25%"},{"location":"uniques/#nullifies-stat-cityfilter","text":"Example: \"Nullifies [Culture] [in all cities]\" Applicable to: Global","title":"🔷 Nullifies [stat] [cityFilter]"},{"location":"uniques/#nullifies-growth-cityfilter","text":"Example: \"Nullifies Growth [in all cities]\" Applicable to: Global","title":"🔷 Nullifies Growth [cityFilter]"},{"location":"uniques/#amount-production-when-constructing-buildingfilter-wonders-cityfilter","text":"Example: \"[20]% Production when constructing [Culture] wonders [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% Production when constructing [buildingFilter] wonders [cityFilter]"},{"location":"uniques/#amount-production-when-constructing-buildingfilter-buildings-cityfilter","text":"Example: \"[20]% Production when constructing [Culture] buildings [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% Production when constructing [buildingFilter] buildings [cityFilter]"},{"location":"uniques/#amount-production-when-constructing-baseunitfilter-units-cityfilter","text":"Example: \"[20]% Production when constructing [Melee] units [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% Production when constructing [baseUnitFilter] units [cityFilter]"},{"location":"uniques/#amount-production-towards-any-buildings-that-already-exist-in-the-capital","text":"Example: \"[20]% Production towards any buildings that already exist in the Capital\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% Production towards any buildings that already exist in the Capital"},{"location":"uniques/#tile-yields-from-natural-wonders-doubled","text":"Applicable to: Global","title":"🔷 Tile yields from Natural Wonders doubled"},{"location":"uniques/#military-units-gifted-from-city-states-start-with-amount-xp","text":"Example: \"Military Units gifted from City-States start with [20] XP\" Applicable to: Global","title":"🔷 Military Units gifted from City-States start with [amount] XP"},{"location":"uniques/#militaristic-city-states-grant-units-amount-times-as-fast-when-you-are-at-war-with-a-common-nation","text":"Example: \"Militaristic City-States grant units [20] times as fast when you are at war with a common nation\" Applicable to: Global","title":"🔷 Militaristic City-States grant units [amount] times as fast when you are at war with a common nation"},{"location":"uniques/#gifts-of-gold-to-city-states-generate-amount-more-influence","text":"Example: \"Gifts of Gold to City-States generate [20]% more Influence\" Applicable to: Global","title":"🔷 Gifts of Gold to City-States generate [amount]% more Influence"},{"location":"uniques/#can-spend-gold-to-annex-or-puppet-a-city-state-that-has-been-your-ally-for-amount-turns","text":"Example: \"Can spend Gold to annex or puppet a City-State that has been your ally for [20] turns.\" Applicable to: Global","title":"🔷 Can spend Gold to annex or puppet a City-State that has been your ally for [amount] turns."},{"location":"uniques/#city-state-territory-always-counts-as-friendly-territory","text":"Applicable to: Global","title":"🔷 City-State territory always counts as friendly territory"},{"location":"uniques/#allied-city-states-will-occasionally-gift-great-people","text":"Applicable to: Global","title":"🔷 Allied City-States will occasionally gift Great People"},{"location":"uniques/#amount-city-state-influence-degradation","text":"Example: \"[20]% City-State Influence degradation\" Applicable to: Global","title":"🔷 [amount]% City-State Influence degradation"},{"location":"uniques/#resting-point-for-influence-with-city-states-is-increased-by-amount","text":"Example: \"Resting point for Influence with City-States is increased by [20]\" Applicable to: Global","title":"🔷 Resting point for Influence with City-States is increased by [amount]"},{"location":"uniques/#allied-city-states-provide-stat-equal-to-amount-of-what-they-produce-for-themselves","text":"Example: \"Allied City-States provide [Culture] equal to [20]% of what they produce for themselves\" Applicable to: Global","title":"🔷 Allied City-States provide [stat] equal to [amount]% of what they produce for themselves"},{"location":"uniques/#amount-resources-gifted-by-city-states","text":"Example: \"[20]% resources gifted by City-States\" Applicable to: Global","title":"🔷 [amount]% resources gifted by City-States"},{"location":"uniques/#amount-happiness-from-luxury-resources-gifted-by-city-states","text":"Example: \"[20]% Happiness from luxury resources gifted by City-States\" Applicable to: Global","title":"🔷 [amount]% Happiness from luxury resources gifted by City-States"},{"location":"uniques/#city-state-influence-recovers-at-twice-the-normal-rate","text":"Applicable to: Global","title":"🔷 City-State Influence recovers at twice the normal rate"},{"location":"uniques/#amount-units-cost-no-maintenance","text":"Example: \"[20] units cost no maintenance\" Applicable to: Global","title":"🔷 [amount] units cost no maintenance"},{"location":"uniques/#cannot-build-baseunitfilter-units","text":"Example: \"Cannot build [Melee] units\" Applicable to: Global","title":"🔷 Cannot build [baseUnitFilter] units"},{"location":"uniques/#amount-growth-cityfilter","text":"Example: \"[20]% growth [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% growth [cityFilter]"},{"location":"uniques/#amount-food-is-carried-over-after-population-increases-cityfilter","text":"Example: \"[20]% Food is carried over after population increases [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% Food is carried over after population increases [cityFilter]"},{"location":"uniques/#gain-a-free-buildingname-cityfilter","text":"Example: \"Gain a free [Library] [in all cities]\" Applicable to: Global","title":"🔷 Gain a free [buildingName] [cityFilter]"},{"location":"uniques/#amount-great-person-generation-cityfilter","text":"Example: \"[20]% Great Person generation [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% Great Person generation [cityFilter]"},{"location":"uniques/#amount-great-person-generation-cityfilter_1","text":"Example: \"[20]% great person generation [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% great person generation [cityFilter]"},{"location":"uniques/#may-choose-amount-additional-belieftype-beliefs-when-foundingorenhancing-a-religion","text":"Example: \"May choose [20] additional [Follower] beliefs when [founding] a religion\" Applicable to: Global","title":"🔷 May choose [amount] additional [beliefType] beliefs when [foundingOrEnhancing] a religion"},{"location":"uniques/#may-choose-amount-additional-beliefs-of-any-type-when-foundingorenhancing-a-religion","text":"Example: \"May choose [20] additional belief(s) of any type when [founding] a religion\" Applicable to: Global","title":"🔷 May choose [amount] additional belief(s) of any type when [foundingOrEnhancing] a religion"},{"location":"uniques/#amount-unhappiness-from-population-cityfilter","text":"Example: \"[20]% unhappiness from population [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% unhappiness from population [cityFilter]"},{"location":"uniques/#amount-unhappiness-from-specialists-cityfilter","text":"Example: \"[20]% unhappiness from specialists [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% unhappiness from specialists [cityFilter]"},{"location":"uniques/#amount-food-consumption-by-specialists-cityfilter","text":"Example: \"[20]% Food consumption by specialists [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% Food consumption by specialists [cityFilter]"},{"location":"uniques/#provides-1-happiness-per-2-additional-social-policies-adopted","text":"Applicable to: Global","title":"🔷 Provides 1 happiness per 2 additional social policies adopted"},{"location":"uniques/#amount-of-excess-happiness-converted-to-stat","text":"Example: \"[20]% of excess happiness converted to [Culture]\" Applicable to: Global","title":"🔷 [amount]% of excess happiness converted to [stat]"},{"location":"uniques/#amount-culture-cost-of-natural-border-growth-cityfilter","text":"Example: \"[20]% Culture cost of natural border growth [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% Culture cost of natural border growth [cityFilter]"},{"location":"uniques/#amount-gold-cost-of-acquiring-tiles-cityfilter","text":"Example: \"[20]% Gold cost of acquiring tiles [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% Gold cost of acquiring tiles [cityFilter]"},{"location":"uniques/#may-buy-baseunitfilter-units-for-amount-stat-cityfilter-at-an-increasing-price-amount","text":"Example: \"May buy [Melee] units for [20] [Culture] [in all cities] at an increasing price ([20])\" Applicable to: Global, FollowerBelief","title":"🔷 May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] at an increasing price ([amount])"},{"location":"uniques/#may-buy-buildingfilter-buildings-for-amount-stat-cityfilter-at-an-increasing-price-amount","text":"Example: \"May buy [Culture] buildings for [20] [Culture] [in all cities] at an increasing price ([20])\" Applicable to: Global, FollowerBelief","title":"🔷 May buy [buildingFilter] buildings for [amount] [stat] [cityFilter] at an increasing price ([amount])"},{"location":"uniques/#may-buy-baseunitfilter-units-for-amount-stat-cityfilter","text":"Example: \"May buy [Melee] units for [20] [Culture] [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 May buy [baseUnitFilter] units for [amount] [stat] [cityFilter]"},{"location":"uniques/#may-buy-buildingfilter-buildings-for-amount-stat-cityfilter","text":"Example: \"May buy [Culture] buildings for [20] [Culture] [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 May buy [buildingFilter] buildings for [amount] [stat] [cityFilter]"},{"location":"uniques/#may-buy-baseunitfilter-units-with-stat-cityfilter","text":"Example: \"May buy [Melee] units with [Culture] [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 May buy [baseUnitFilter] units with [stat] [cityFilter]"},{"location":"uniques/#may-buy-buildingfilter-buildings-with-stat-cityfilter","text":"Example: \"May buy [Culture] buildings with [Culture] [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 May buy [buildingFilter] buildings with [stat] [cityFilter]"},{"location":"uniques/#may-buy-baseunitfilter-units-with-stat-for-amount-times-their-normal-production-cost","text":"Example: \"May buy [Melee] units with [Culture] for [20] times their normal Production cost\" Applicable to: Global, FollowerBelief","title":"🔷 May buy [baseUnitFilter] units with [stat] for [amount] times their normal Production cost"},{"location":"uniques/#may-buy-buildingfilter-buildings-with-stat-for-amount-times-their-normal-production-cost","text":"Example: \"May buy [Culture] buildings with [Culture] for [20] times their normal Production cost\" Applicable to: Global, FollowerBelief","title":"🔷 May buy [buildingFilter] buildings with [stat] for [amount] times their normal Production cost"},{"location":"uniques/#enables-conversion-of-city-production-to-gold","text":"Applicable to: Global","title":"🔷 Enables conversion of city production to gold"},{"location":"uniques/#enables-conversion-of-city-production-to-science","text":"Applicable to: Global","title":"🔷 Enables conversion of city production to science"},{"location":"uniques/#stat-cost-of-purchasing-items-in-cities-amount","text":"Example: \"[Culture] cost of purchasing items in cities [20]%\" Applicable to: Global, FollowerBelief","title":"🔷 [stat] cost of purchasing items in cities [amount]%"},{"location":"uniques/#stat-cost-of-purchasing-buildingfilter-buildings-amount","text":"Example: \"[Culture] cost of purchasing [Culture] buildings [20]%\" Applicable to: Global, FollowerBelief","title":"🔷 [stat] cost of purchasing [buildingFilter] buildings [amount]%"},{"location":"uniques/#stat-cost-of-purchasing-baseunitfilter-units-amount","text":"Example: \"[Culture] cost of purchasing [Melee] units [20]%\" Applicable to: Global, FollowerBelief","title":"🔷 [stat] cost of purchasing [baseUnitFilter] units [amount]%"},{"location":"uniques/#improves-movement-speed-on-roads","text":"Applicable to: Global","title":"🔷 Improves movement speed on roads"},{"location":"uniques/#roads-connect-tiles-across-rivers","text":"Applicable to: Global","title":"🔷 Roads connect tiles across rivers"},{"location":"uniques/#amount-maintenance-on-road-railroads","text":"Example: \"[20]% maintenance on road & railroads\" Applicable to: Global","title":"🔷 [amount]% maintenance on road & railroads"},{"location":"uniques/#amount-maintenance-cost-for-buildings-cityfilter","text":"Example: \"[20]% maintenance cost for buildings [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% maintenance cost for buildings [cityFilter]"},{"location":"uniques/#receive-a-free-great-person-at-the-end-of-every-comment-every-394-years-after-researching-tech-each-bonus-person-can-only-be-chosen-once","text":"Example: \"Receive a free Great Person at the end of every [comment] (every 394 years), after researching [Agriculture]. Each bonus person can only be chosen once.\" Applicable to: Global","title":"🔷 Receive a free Great Person at the end of every [comment] (every 394 years), after researching [tech]. Each bonus person can only be chosen once."},{"location":"uniques/#once-the-long-count-activates-the-year-on-the-world-screen-displays-as-the-traditional-mayan-long-count","text":"Applicable to: Global","title":"🔷 Once The Long Count activates, the year on the world screen displays as the traditional Mayan Long Count."},{"location":"uniques/#retain-amount-of-the-happiness-from-a-luxury-after-the-last-copy-has-been-traded-away","text":"Example: \"Retain [20]% of the happiness from a luxury after the last copy has been traded away\" Applicable to: Global","title":"🔷 Retain [amount]% of the happiness from a luxury after the last copy has been traded away"},{"location":"uniques/#amount-happiness-from-each-type-of-luxury-resource","text":"Example: \"[20] Happiness from each type of luxury resource\" Applicable to: Global","title":"🔷 [amount] Happiness from each type of luxury resource"},{"location":"uniques/#each-city-founded-increases-culture-cost-of-policies-amount-less-than-normal","text":"Example: \"Each city founded increases culture cost of policies [20]% less than normal\" Applicable to: Global","title":"🔷 Each city founded increases culture cost of policies [amount]% less than normal"},{"location":"uniques/#amount-culture-cost-of-adopting-new-policies","text":"Example: \"[20]% Culture cost of adopting new Policies\" Applicable to: Global","title":"🔷 [amount]% Culture cost of adopting new Policies"},{"location":"uniques/#quantity-of-strategic-resources-produced-by-the-empire-amount","text":"Example: \"Quantity of strategic resources produced by the empire +[20]%\" Applicable to: Global","title":"🔷 Quantity of strategic resources produced by the empire +[amount]%"},{"location":"uniques/#double-quantity-of-resource-produced","text":"Example: \"Double quantity of [Iron] produced\" Applicable to: Global","title":"🔷 Double quantity of [resource] produced"},{"location":"uniques/#double-happiness-from-natural-wonders","text":"Applicable to: Global","title":"🔷 Double Happiness from Natural Wonders"},{"location":"uniques/#enables-construction-of-spaceship-parts","text":"Applicable to: Global","title":"🔷 Enables construction of Spaceship parts"},{"location":"uniques/#enemy-land-units-must-spend-1-extra-movement-point-when-inside-your-territory-obsolete-upon-dynamite","text":"Applicable to: Global","title":"🔷 Enemy land units must spend 1 extra movement point when inside your territory (obsolete upon Dynamite)"},{"location":"uniques/#production-to-science-conversion-in-cities-increased-by-33","text":"Applicable to: Global","title":"🔷 Production to science conversion in cities increased by 33%"},{"location":"uniques/#notified-of-new-barbarian-encampments","text":"Applicable to: Global","title":"🔷 Notified of new Barbarian encampments"},{"location":"uniques/#borrows-city-names-from-other-civilizations-in-the-game","text":"Applicable to: Global","title":"🔷 \"Borrows\" city names from other civilizations in the game"},{"location":"uniques/#units-fight-as-though-they-were-at-full-strength-even-when-damaged","text":"Applicable to: Global","title":"🔷 Units fight as though they were at full strength even when damaged"},{"location":"uniques/#100-gold-for-discovering-a-natural-wonder-bonus-enhanced-to-500-gold-if-first-to-discover-it","text":"Applicable to: Global","title":"🔷 100 Gold for discovering a Natural Wonder (bonus enhanced to 500 Gold if first to discover it)"},{"location":"uniques/#unhappiness-from-number-of-cities-doubled","text":"Applicable to: Global","title":"🔷 Unhappiness from number of Cities doubled"},{"location":"uniques/#great-general-provides-double-combat-bonus","text":"Applicable to: Global","title":"🔷 Great General provides double combat bonus"},{"location":"uniques/#receive-a-tech-boost-when-scientific-buildingswonders-are-built-in-capital","text":"Applicable to: Global","title":"🔷 Receive a tech boost when scientific buildings/wonders are built in capital"},{"location":"uniques/#may-not-generate-great-prophet-equivalents-naturally","text":"Applicable to: Global","title":"🔷 May not generate great prophet equivalents naturally"},{"location":"uniques/#67-chance-to-earn-25-gold-and-recruit-a-barbarian-unit-from-a-conquered-encampment","text":"Applicable to: Global","title":"🔷 67% chance to earn 25 Gold and recruit a Barbarian unit from a conquered encampment"},{"location":"uniques/#50-chance-of-capturing-defeated-barbarian-naval-units-and-earning-25-gold","text":"Applicable to: Global","title":"🔷 50% chance of capturing defeated Barbarian naval units and earning 25 Gold"},{"location":"uniques/#receive-triple-gold-from-barbarian-encampments-and-pillaging-cities","text":"Applicable to: Global","title":"🔷 Receive triple Gold from Barbarian encampments and pillaging Cities"},{"location":"uniques/#enables-open-borders-agreements","text":"Applicable to: Global","title":"🔷 Enables Open Borders agreements"},{"location":"uniques/#enables-research-agreements","text":"Applicable to: Global","title":"🔷 Enables Research agreements"},{"location":"uniques/#science-gained-from-research-agreements-amount","text":"Example: \"Science gained from research agreements [20]%\" Applicable to: Global","title":"🔷 Science gained from research agreements [amount]%"},{"location":"uniques/#triggers-victory","text":"Applicable to: Global","title":"🔷 Triggers victory"},{"location":"uniques/#triggers-a-cultural-victory-upon-completion","text":"Applicable to: Global","title":"🔷 Triggers a Cultural Victory upon completion"},{"location":"uniques/#amount-city-strength-from-defensive-buildings","text":"Example: \"[20]% City Strength from defensive buildings\" Applicable to: Global","title":"🔷 [amount]% City Strength from defensive buildings"},{"location":"uniques/#amount-tile-improvement-construction-time","text":"Example: \"[20]% tile improvement construction time\" Applicable to: Global","title":"🔷 [amount]% tile improvement construction time"},{"location":"uniques/#amount-gold-from-great-merchant-trade-missions","text":"Example: \"[20]% Gold from Great Merchant trade missions\" Applicable to: Global","title":"🔷 [amount]% Gold from Great Merchant trade missions"},{"location":"uniques/#mapunitfilter-units-adjacent-to-this-city-heal-amount-hp-per-turn-when-healing","text":"Example: \"[Wounded] Units adjacent to this city heal [20] HP per turn when healing\" Applicable to: Global, FollowerBelief","title":"🔷 [mapUnitFilter] Units adjacent to this city heal [amount] HP per turn when healing"},{"location":"uniques/#amount-golden-age-length","text":"Example: \"[20]% Golden Age length\" Applicable to: Global","title":"🔷 [amount]% Golden Age length"},{"location":"uniques/#amount-strength-for-cities","text":"Example: \"[20]% Strength for cities\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% Strength for cities"},{"location":"uniques/#new-baseunitfilter-units-start-with-amount-experience-cityfilter","text":"Example: \"New [Melee] units start with [20] Experience [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 New [baseUnitFilter] units start with [amount] Experience [cityFilter]"},{"location":"uniques/#all-newly-trained-baseunitfilter-units-cityfilter-receive-the-promotion-promotion","text":"Example: \"All newly-trained [Melee] units [in all cities] receive the [Shock I] promotion\" Applicable to: Global, FollowerBelief","title":"🔷 All newly-trained [baseUnitFilter] units [cityFilter] receive the [promotion] promotion"},{"location":"uniques/#baseunitfilter-units-built-cityfilter-can-action-amount-extra-times","text":"Example: \"[Melee] units built [in all cities] can [action] [20] extra times\" Applicable to: Global, FollowerBelief","title":"🔷 [baseUnitFilter] units built [cityFilter] can [action] [amount] extra times"},{"location":"uniques/#enables-embarkation-for-land-units","text":"Applicable to: Global","title":"🔷 Enables embarkation for land units"},{"location":"uniques/#enables-embarked-units-to-enter-ocean-tiles","text":"Applicable to: Global","title":"🔷 Enables embarked units to enter ocean tiles"},{"location":"uniques/#population-loss-from-nuclear-attacks-amount-cityfilter","text":"Example: \"Population loss from nuclear attacks [20]% [in all cities]\" Applicable to: Global","title":"🔷 Population loss from nuclear attacks [amount]% [cityFilter]"},{"location":"uniques/#amount-natural-religion-spread-cityfilter","text":"Example: \"[20]% Natural religion spread [in all cities]\" Applicable to: Global, FollowerBelief","title":"🔷 [amount]% Natural religion spread [cityFilter]"},{"location":"uniques/#religion-naturally-spreads-to-cities-amount-tiles-away","text":"Example: \"Religion naturally spreads to cities [20] tiles away\" Applicable to: Global, FollowerBelief","title":"🔷 Religion naturally spreads to cities [amount] tiles away"},{"location":"uniques/#can-be-continually-researched","text":"Applicable to: Global","title":"🔷 Can be continually researched"},{"location":"uniques/#amount-unit-supply","text":"Example: \"[20] Unit Supply\" Applicable to: Global","title":"🔷 [amount] Unit Supply"},{"location":"uniques/#amount-unit-supply-per-amount-population-cityfilter","text":"Example: \"[20] Unit Supply per [20] population [in all cities]\" Applicable to: Global","title":"🔷 [amount] Unit Supply per [amount] population [cityFilter]"},{"location":"uniques/#amount-unit-supply-per-city","text":"Example: \"[20] Unit Supply per city\" Applicable to: Global","title":"🔷 [amount] Unit Supply per city"},{"location":"uniques/#units-in-cities-cost-no-maintenance","text":"Applicable to: Global","title":"🔷 Units in cities cost no Maintenance"},{"location":"uniques/#rebel-units-may-spawn","text":"Applicable to: Global","title":"🔷 Rebel units may spawn"},{"location":"uniques/#amount-strength","text":"Example: \"[20]% Strength\" Applicable to: Global, Unit","title":"🔷 [amount]% Strength"},{"location":"uniques/#amount-strength-decreasing-with-distance-from-the-capital","text":"Example: \"[20]% Strength decreasing with distance from the capital\" Applicable to: Global, Unit","title":"🔷 [amount]% Strength decreasing with distance from the capital"},{"location":"uniques/#amount-to-flank-attack-bonuses","text":"Example: \"[20]% to Flank Attack bonuses\" Applicable to: Global, Unit","title":"🔷 [amount]% to Flank Attack bonuses"},{"location":"uniques/#30-strength-when-fighting-city-state-units-and-cities","text":"Applicable to: Global","title":"🔷 +30% Strength when fighting City-State units and cities"},{"location":"uniques/#amount-movement","text":"Example: \"[20] Movement\" Applicable to: Global, Unit","title":"🔷 [amount] Movement"},{"location":"uniques/#amount-sight","text":"Example: \"[20] Sight\" Applicable to: Global, Unit, Terrain","title":"🔷 [amount] Sight"},{"location":"uniques/#amount-range","text":"Example: \"[20] Range\" Applicable to: Global, Unit","title":"🔷 [amount] Range"},{"location":"uniques/#amount-hp-when-healing","text":"Example: \"[20] HP when healing\" Applicable to: Global, Unit","title":"🔷 [amount] HP when healing"},{"location":"uniques/#amount-spread-religion-strength","text":"Example: \"[20]% Spread Religion Strength\" Applicable to: Global, Unit","title":"🔷 [amount]% Spread Religion Strength"},{"location":"uniques/#no-defensive-terrain-bonus","text":"Applicable to: Global, Unit","title":"🔷 No defensive terrain bonus"},{"location":"uniques/#no-defensive-terrain-penalty","text":"Applicable to: Global, Unit","title":"🔷 No defensive terrain penalty"},{"location":"uniques/#no-movement-cost-to-pillage","text":"Applicable to: Global, Unit","title":"🔷 No movement cost to pillage"},{"location":"uniques/#may-heal-outside-of-friendly-territory","text":"Applicable to: Global, Unit","title":"🔷 May heal outside of friendly territory"},{"location":"uniques/#all-healing-effects-doubled","text":"Applicable to: Global, Unit","title":"🔷 All healing effects doubled"},{"location":"uniques/#heals-amount-damage-if-it-kills-a-unit","text":"Example: \"Heals [20] damage if it kills a unit\" Applicable to: Global, Unit","title":"🔷 Heals [amount] damage if it kills a unit"},{"location":"uniques/#can-only-heal-by-pillaging","text":"Applicable to: Global, Unit","title":"🔷 Can only heal by pillaging"},{"location":"uniques/#normal-vision-when-embarked","text":"Applicable to: Global, Unit","title":"🔷 Normal vision when embarked"},{"location":"uniques/#defense-bonus-when-embarked","text":"Applicable to: Global, Unit","title":"🔷 Defense bonus when embarked"},{"location":"uniques/#embarked-units-can-defend-themselves","text":"Applicable to: Global","title":"🔷 Embarked units can defend themselves"},{"location":"uniques/#amount-maintenance-costs","text":"Example: \"[20]% maintenance costs\" Applicable to: Global, Unit","title":"🔷 [amount]% maintenance costs"},{"location":"uniques/#amount-gold-cost-of-upgrading","text":"Example: \"[20]% Gold cost of upgrading\" Applicable to: Global, Unit","title":"🔷 [amount]% Gold cost of upgrading"},{"location":"uniques/#greatperson-is-earned-amount-faster","text":"Example: \"[greatPerson] is earned [20]% faster\" Applicable to: Global, Unit","title":"🔷 [greatPerson] is earned [amount]% faster"},{"location":"uniques/#earn-amount-of-the-damage-done-to-mapunitfilter-units-as-plunderablestat","text":"Example: \"Earn [20]% of the damage done to [Wounded] units as [Gold]\" Applicable to: Global, Unit","title":"🔷 Earn [amount]% of the damage done to [mapUnitFilter] units as [plunderableStat]"},{"location":"uniques/#upon-capturing-a-city-receive-amount-times-its-stat-production-as-plunderablestat-immediately","text":"Example: \"Upon capturing a city, receive [20] times its [Culture] production as [Gold] immediately\" Applicable to: Global, Unit","title":"🔷 Upon capturing a city, receive [amount] times its [stat] production as [plunderableStat] immediately"},{"location":"uniques/#earn-amount-of-killed-mapunitfilter-units-costorstrength-as-plunderablestat","text":"Example: \"Earn [20]% of killed [Wounded] unit's [Cost] as [Gold]\" Applicable to: Global, Unit","title":"🔷 Earn [amount]% of killed [mapUnitFilter] unit's [costOrStrength] as [plunderableStat]"},{"location":"uniques/#amount-xp-gained-from-combat","text":"Example: \"[20] XP gained from combat\" Applicable to: Global, Unit","title":"🔷 [amount] XP gained from combat"},{"location":"uniques/#amount-xp-gained-from-combat_1","text":"Example: \"[20]% XP gained from combat\" Applicable to: Global, Unit","title":"🔷 [amount]% XP gained from combat"},{"location":"uniques/#this-unit-upgrades-for-free","text":"Applicable to: Global","title":"🔷 This Unit upgrades for free"},{"location":"uniques/#nation-uniques","text":"","title":"Nation uniques"},{"location":"uniques/#will-not-be-chosen-for-new-games","text":"Applicable to: Nation","title":"🔷 Will not be chosen for new games"},{"location":"uniques/#starts-with-tech","text":"Example: \"Starts with [Agriculture]\" Applicable to: Nation","title":"🔷 Starts with [tech]"},{"location":"uniques/#tech-uniques","text":"","title":"Tech uniques"},{"location":"uniques/#starting-tech","text":"Applicable to: Tech","title":"🔷 Starting tech"},{"location":"uniques/#only-available","text":"Applicable to: Tech, Policy, Building, Unit, Promotion, Improvement","title":"🔷 Only available"},{"location":"uniques/#followerbelief-uniques","text":"","title":"FollowerBelief uniques"},{"location":"uniques/#amount-stat-from-every-follower-up-to-amount","text":"Example: \"[20]% [Culture] from every follower, up to [20]%\" Applicable to: FollowerBelief","title":"🔷 [amount]% [stat] from every follower, up to [amount]%"},{"location":"uniques/#earn-amount-of-mapunitfilter-units-costorstrength-as-plunderablestat-when-killed-within-4-tiles-of-a-city-following-this-religion","text":"Example: \"Earn [20]% of [Wounded] unit's [Cost] as [Gold] when killed within 4 tiles of a city following this religion\" Applicable to: FollowerBelief","title":"🔷 Earn [amount]% of [mapUnitFilter] unit's [costOrStrength] as [plunderableStat] when killed within 4 tiles of a city following this religion"},{"location":"uniques/#building-uniques","text":"","title":"Building uniques"},{"location":"uniques/#consumes-amount-resource","text":"Example: \"Consumes [20] [Iron]\" Applicable to: Building, Unit, Improvement","title":"🔷 Consumes [amount] [resource]"},{"location":"uniques/#provides-amount-resource","text":"Example: \"Provides [20] [Iron]\" Applicable to: Building, Improvement","title":"🔷 Provides [amount] [resource]"},{"location":"uniques/#unbuildable","text":"Applicable to: Building, Unit","title":"🔷 Unbuildable"},{"location":"uniques/#cannot-be-purchased","text":"Applicable to: Building, Unit","title":"🔷 Cannot be purchased"},{"location":"uniques/#can-be-purchased-with-stat-cityfilter","text":"Example: \"Can be purchased with [Culture] [in all cities]\" Applicable to: Building, Unit","title":"🔷 Can be purchased with [stat] [cityFilter]"},{"location":"uniques/#can-be-purchased-for-amount-stat-cityfilter","text":"Example: \"Can be purchased for [20] [Culture] [in all cities]\" Applicable to: Building, Unit","title":"🔷 Can be purchased for [amount] [stat] [cityFilter]"},{"location":"uniques/#limited-to-amount-per-civilization","text":"Example: \"Limited to [20] per Civilization\" Applicable to: Building, Unit","title":"🔷 Limited to [amount] per Civilization"},{"location":"uniques/#hidden-until-amount-social-policy-branches-have-been-completed","text":"Example: \"Hidden until [20] social policy branches have been completed\" Applicable to: Building, Unit","title":"🔷 Hidden until [amount] social policy branches have been completed"},{"location":"uniques/#excess-food-converted-to-production-when-under-construction","text":"Applicable to: Building, Unit","title":"🔷 Excess Food converted to Production when under construction"},{"location":"uniques/#requires-at-least-amount-population","text":"Example: \"Requires at least [20] population\" Applicable to: Building, Unit","title":"🔷 Requires at least [amount] population"},{"location":"uniques/#cost-increases-by-amount-per-owned-city","text":"Example: \"Cost increases by [20] per owned city\" Applicable to: Building","title":"🔷 Cost increases by [amount] per owned city"},{"location":"uniques/#requires-a-buildingname-in-all-cities","text":"Example: \"Requires a [Library] in all cities\" Applicable to: Building","title":"🔷 Requires a [buildingName] in all cities"},{"location":"uniques/#requires-a-buildingname-in-at-least-amount-cities","text":"Example: \"Requires a [Library] in at least [20] cities\" Applicable to: Building","title":"🔷 Requires a [buildingName] in at least [amount] cities"},{"location":"uniques/#must-be-on-terrainfilter","text":"Example: \"Must be on [Forest]\" Applicable to: Building","title":"🔷 Must be on [terrainFilter]"},{"location":"uniques/#must-not-be-on-terrainfilter","text":"Example: \"Must not be on [Forest]\" Applicable to: Building","title":"🔷 Must not be on [terrainFilter]"},{"location":"uniques/#must-be-next-to-terrainfilter","text":"Example: \"Must be next to [Forest]\" Applicable to: Building, Improvement","title":"🔷 Must be next to [terrainFilter]"},{"location":"uniques/#must-not-be-next-to-terrainfilter","text":"Example: \"Must not be next to [Forest]\" Applicable to: Building","title":"🔷 Must not be next to [terrainFilter]"},{"location":"uniques/#unsellable","text":"Applicable to: Building","title":"🔷 Unsellable"},{"location":"uniques/#obsolete-with-tech","text":"Example: \"Obsolete with [Agriculture]\" Applicable to: Building, Improvement, Resource","title":"🔷 Obsolete with [tech]"},{"location":"uniques/#indicates-the-capital-city","text":"Applicable to: Building","title":"🔷 Indicates the capital city"},{"location":"uniques/#provides-1-extra-copy-of-each-improved-luxury-resource-near-this-city","text":"Applicable to: Building","title":"🔷 Provides 1 extra copy of each improved luxury resource near this City"},{"location":"uniques/#destroyed-when-the-city-is-captured","text":"Applicable to: Building","title":"🔷 Destroyed when the city is captured"},{"location":"uniques/#never-destroyed-when-the-city-is-captured","text":"Applicable to: Building","title":"🔷 Never destroyed when the city is captured"},{"location":"uniques/#doubles-gold-given-to-enemy-if-city-is-captured","text":"Applicable to: Building","title":"🔷 Doubles Gold given to enemy if city is captured"},{"location":"uniques/#remove-extra-unhappiness-from-annexed-cities","text":"Applicable to: Building","title":"🔷 Remove extra unhappiness from annexed cities"},{"location":"uniques/#spaceship-part","text":"Applicable to: Building, Unit","title":"🔷 Spaceship part"},{"location":"uniques/#hidden-when-religion-is-disabled","text":"Applicable to: Building, Unit, Ruins","title":"🔷 Hidden when religion is disabled"},{"location":"uniques/#hidden-when-victorytype-victory-is-disabled","text":"Example: \"Hidden when [Domination] Victory is disabled\" Applicable to: Building, Unit","title":"🔷 Hidden when [victoryType] Victory is disabled"},{"location":"uniques/#unit-uniques","text":"","title":"Unit uniques"},{"location":"uniques/#founds-a-new-city","text":"Applicable to: Unit","title":"🔷 Founds a new city"},{"location":"uniques/#can-construct-improvementname","text":"Example: \"Can construct [Trading Post]\" Applicable to: Unit","title":"🔷 Can construct [improvementName]"},{"location":"uniques/#can-build-improvementfilterterrainfilter-improvements-on-tiles","text":"Example: \"Can build [improvementFilter/terrainFilter] improvements on tiles\" Applicable to: Unit","title":"🔷 Can build [improvementFilter/terrainFilter] improvements on tiles"},{"location":"uniques/#may-create-improvements-on-water-resources","text":"Applicable to: Unit","title":"🔷 May create improvements on water resources"},{"location":"uniques/#may-found-a-religion","text":"Applicable to: Unit","title":"🔷 May found a religion"},{"location":"uniques/#may-enhance-a-religion","text":"Applicable to: Unit","title":"🔷 May enhance a religion"},{"location":"uniques/#can-only-attack-combatantfilter-units","text":"Example: \"Can only attack [City] units\" Applicable to: Unit","title":"🔷 Can only attack [combatantFilter] units"},{"location":"uniques/#can-only-attack-tilefilter-tiles","text":"Example: \"Can only attack [Farm] tiles\" Applicable to: Unit","title":"🔷 Can only attack [tileFilter] tiles"},{"location":"uniques/#cannot-attack","text":"Applicable to: Unit","title":"🔷 Cannot attack"},{"location":"uniques/#must-set-up-to-ranged-attack","text":"Applicable to: Unit","title":"🔷 Must set up to ranged attack"},{"location":"uniques/#self-destructs-when-attacking","text":"Applicable to: Unit","title":"🔷 Self-destructs when attacking"},{"location":"uniques/#blast-radius-amount","text":"Example: \"Blast radius [20]\" Applicable to: Unit","title":"🔷 Blast radius [amount]"},{"location":"uniques/#ranged-attacks-may-be-performed-over-obstacles","text":"Applicable to: Unit","title":"🔷 Ranged attacks may be performed over obstacles"},{"location":"uniques/#uncapturable","text":"Applicable to: Unit","title":"🔷 Uncapturable"},{"location":"uniques/#may-withdraw-before-melee-amount","text":"Example: \"May withdraw before melee ([20]%)\" Applicable to: Unit","title":"🔷 May withdraw before melee ([amount]%)"},{"location":"uniques/#unable-to-capture-cities","text":"Applicable to: Unit","title":"🔷 Unable to capture cities"},{"location":"uniques/#can-move-after-attacking","text":"Applicable to: Unit","title":"🔷 Can move after attacking"},{"location":"uniques/#can-move-immediately-once-bought","text":"Applicable to: Unit","title":"🔷 Can move immediately once bought"},{"location":"uniques/#unit-will-heal-every-turn-even-if-it-performs-an-action","text":"Applicable to: Unit","title":"🔷 Unit will heal every turn, even if it performs an action"},{"location":"uniques/#all-adjacent-units-heal-amount-hp-when-healing","text":"Example: \"All adjacent units heal [20] HP when healing\" Applicable to: Unit","title":"🔷 All adjacent units heal [amount] HP when healing"},{"location":"uniques/#eliminates-combat-penalty-for-attacking-across-a-coast","text":"Applicable to: Unit","title":"🔷 Eliminates combat penalty for attacking across a coast"},{"location":"uniques/#6-tiles-in-every-direction-always-visible","text":"Applicable to: Unit","title":"🔷 6 tiles in every direction always visible"},{"location":"uniques/#can-carry-amount-mapunitfilter-units","text":"Example: \"Can carry [20] [Wounded] units\" Applicable to: Unit","title":"🔷 Can carry [amount] [mapUnitFilter] units"},{"location":"uniques/#can-carry-amount-extra-mapunitfilter-units","text":"Example: \"Can carry [20] extra [Wounded] units\" Applicable to: Unit","title":"🔷 Can carry [amount] extra [mapUnitFilter] units"},{"location":"uniques/#cannot-be-carried-by-mapunitfilter-units","text":"Example: \"Cannot be carried by [Wounded] units\" Applicable to: Unit","title":"🔷 Cannot be carried by [mapUnitFilter] units"},{"location":"uniques/#may-capture-killed-mapunitfilter-units","text":"Example: \"May capture killed [Wounded] units\" Applicable to: Unit","title":"🔷 May capture killed [mapUnitFilter] units"},{"location":"uniques/#invisible-to-others","text":"Applicable to: Unit","title":"🔷 Invisible to others"},{"location":"uniques/#invisible-to-non-adjacent-units","text":"Applicable to: Unit","title":"🔷 Invisible to non-adjacent units"},{"location":"uniques/#can-see-invisible-mapunitfilter-units","text":"Example: \"Can see invisible [Wounded] units\" Applicable to: Unit","title":"🔷 Can see invisible [mapUnitFilter] units"},{"location":"uniques/#may-upgrade-to-baseunitfilter-through-ruins-like-effects","text":"Example: \"May upgrade to [Melee] through ruins-like effects\" Applicable to: Unit","title":"🔷 May upgrade to [baseUnitFilter] through ruins-like effects"},{"location":"uniques/#double-movement-in-terrainfilter","text":"Example: \"Double movement in [Forest]\" Applicable to: Unit","title":"🔷 Double movement in [terrainFilter]"},{"location":"uniques/#all-tiles-cost-1-movement","text":"Applicable to: Unit","title":"🔷 All tiles cost 1 movement"},{"location":"uniques/#can-pass-through-impassable-tiles","text":"Applicable to: Unit","title":"🔷 Can pass through impassable tiles"},{"location":"uniques/#ignores-terrain-cost","text":"Applicable to: Unit","title":"🔷 Ignores terrain cost"},{"location":"uniques/#ignores-zone-of-control","text":"Applicable to: Unit","title":"🔷 Ignores Zone of Control"},{"location":"uniques/#rough-terrain-penalty","text":"Applicable to: Unit","title":"🔷 Rough terrain penalty"},{"location":"uniques/#can-enter-ice-tiles","text":"Applicable to: Unit","title":"🔷 Can enter ice tiles"},{"location":"uniques/#cannot-enter-ocean-tiles","text":"Applicable to: Unit","title":"🔷 Cannot enter ocean tiles"},{"location":"uniques/#may-enter-foreign-tiles-without-open-borders","text":"Applicable to: Unit","title":"🔷 May enter foreign tiles without open borders"},{"location":"uniques/#may-enter-foreign-tiles-without-open-borders-but-loses-amount-religious-strength-each-turn-it-ends-there","text":"Example: \"May enter foreign tiles without open borders, but loses [20] religious strength each turn it ends there\" Applicable to: Unit","title":"🔷 May enter foreign tiles without open borders, but loses [amount] religious strength each turn it ends there"},{"location":"uniques/#never-appears-as-a-barbarian-unit","text":"Applicable to: Unit","title":"🔷 Never appears as a Barbarian unit"},{"location":"uniques/#religious-unit","text":"Applicable to: Unit","title":"🔷 Religious Unit"},{"location":"uniques/#can-be-added-to-comment-in-the-capital","text":"Example: \"Can be added to [comment] in the Capital\" Applicable to: Unit","title":"🔷 Can be added to [comment] in the Capital"},{"location":"uniques/#promotion-uniques","text":"","title":"Promotion uniques"},{"location":"uniques/#heal-this-unit-by-amount-hp","text":"Example: \"Heal this unit by [20] HP\" Applicable to: Promotion","title":"🔷 Heal this unit by [amount] HP"},{"location":"uniques/#terrain-uniques","text":"","title":"Terrain uniques"},{"location":"uniques/#must-be-adjacent-to-amount-simpleterrain-tiles","text":"Example: \"Must be adjacent to [20] [Elevated] tiles\" Applicable to: Terrain","title":"🔷 Must be adjacent to [amount] [simpleTerrain] tiles"},{"location":"uniques/#must-be-adjacent-to-amount-to-amount-simpleterrain-tiles","text":"Example: \"Must be adjacent to [20] to [20] [Elevated] tiles\" Applicable to: Terrain","title":"🔷 Must be adjacent to [amount] to [amount] [simpleTerrain] tiles"},{"location":"uniques/#must-not-be-on-amount-largest-landmasses","text":"Example: \"Must not be on [20] largest landmasses\" Applicable to: Terrain","title":"🔷 Must not be on [amount] largest landmasses"},{"location":"uniques/#must-be-on-amount-largest-landmasses","text":"Example: \"Must be on [20] largest landmasses\" Applicable to: Terrain","title":"🔷 Must be on [amount] largest landmasses"},{"location":"uniques/#occurs-on-latitudes-from-amount-to-amount-percent-of-distance-equator-to-pole","text":"Example: \"Occurs on latitudes from [20] to [20] percent of distance equator to pole\" Applicable to: Terrain","title":"🔷 Occurs on latitudes from [amount] to [amount] percent of distance equator to pole"},{"location":"uniques/#occurs-in-groups-of-amount-to-amount-tiles","text":"Example: \"Occurs in groups of [20] to [20] tiles\" Applicable to: Terrain","title":"🔷 Occurs in groups of [amount] to [amount] tiles"},{"location":"uniques/#neighboring-tiles-will-convert-to-baseterrain","text":"Example: \"Neighboring tiles will convert to [Grassland]\" Applicable to: Terrain","title":"🔷 Neighboring tiles will convert to [baseTerrain]"},{"location":"uniques/#neighboring-tiles-except-baseterrain-will-convert-to-baseterrain","text":"Example: \"Neighboring tiles except [Grassland] will convert to [Grassland]\" Applicable to: Terrain","title":"🔷 Neighboring tiles except [baseTerrain] will convert to [baseTerrain]"},{"location":"uniques/#grants-500-gold-to-the-first-civilization-to-discover-it","text":"Applicable to: Terrain","title":"🔷 Grants 500 Gold to the first civilization to discover it"},{"location":"uniques/#units-ending-their-turn-on-this-terrain-take-amount-damage","text":"Example: \"Units ending their turn on this terrain take [20] damage\" Applicable to: Terrain","title":"🔷 Units ending their turn on this terrain take [amount] damage"},{"location":"uniques/#grants-promotion-comment-to-adjacent-mapunitfilter-units-for-the-rest-of-the-game","text":"Example: \"Grants [Shock I] ([comment]) to adjacent [Wounded] units for the rest of the game\" Applicable to: Terrain","title":"🔷 Grants [promotion] ([comment]) to adjacent [mapUnitFilter] units for the rest of the game"},{"location":"uniques/#amount-strength-for-cities-built-on-this-terrain","text":"Example: \"[20] Strength for cities built on this terrain\" Applicable to: Terrain","title":"🔷 [amount] Strength for cities built on this terrain"},{"location":"uniques/#provides-a-one-time-production-bonus-to-the-closest-city-when-cut-down","text":"Applicable to: Terrain","title":"🔷 Provides a one-time Production bonus to the closest city when cut down"},{"location":"uniques/#tile-provides-yield-without-assigned-population","text":"Applicable to: Terrain, Improvement","title":"🔷 Tile provides yield without assigned population"},{"location":"uniques/#nullifies-all-other-stats-this-tile-provides","text":"Applicable to: Terrain","title":"🔷 Nullifies all other stats this tile provides"},{"location":"uniques/#only-improvementfilter-improvements-may-be-built-on-this-tile","text":"Example: \"Only [All Road] improvements may be built on this tile\" Applicable to: Terrain","title":"🔷 Only [improvementFilter] improvements may be built on this tile"},{"location":"uniques/#blocks-line-of-sight-from-tiles-at-same-elevation","text":"Applicable to: Terrain","title":"🔷 Blocks line-of-sight from tiles at same elevation"},{"location":"uniques/#has-an-elevation-of-amount-for-visibility-calculations","text":"Example: \"Has an elevation of [20] for visibility calculations\" Applicable to: Terrain","title":"🔷 Has an elevation of [amount] for visibility calculations"},{"location":"uniques/#always-fertility-amount-for-map-generation","text":"Example: \"Always Fertility [20] for Map Generation\" Applicable to: Terrain","title":"🔷 Always Fertility [amount] for Map Generation"},{"location":"uniques/#amount-to-fertility-for-map-generation","text":"Example: \"[20] to Fertility for Map Generation\" Applicable to: Terrain","title":"🔷 [amount] to Fertility for Map Generation"},{"location":"uniques/#a-region-is-formed-with-at-least-amount-simpleterrain-tiles-with-priority-amount","text":"Example: \"A Region is formed with at least [20]% [Elevated] tiles, with priority [20]\" Applicable to: Terrain","title":"🔷 A Region is formed with at least [amount]% [simpleTerrain] tiles, with priority [amount]"},{"location":"uniques/#a-region-is-formed-with-at-least-amount-simpleterrain-tiles-and-simpleterrain-tiles-with-priority-amount","text":"Example: \"A Region is formed with at least [20]% [Elevated] tiles and [Elevated] tiles, with priority [20]\" Applicable to: Terrain","title":"🔷 A Region is formed with at least [amount]% [simpleTerrain] tiles and [simpleTerrain] tiles, with priority [amount]"},{"location":"uniques/#a-region-can-not-contain-more-simpleterrain-tiles-than-simpleterrain-tiles","text":"Example: \"A Region can not contain more [Elevated] tiles than [Elevated] tiles\" Applicable to: Terrain","title":"🔷 A Region can not contain more [simpleTerrain] tiles than [simpleTerrain] tiles"},{"location":"uniques/#base-terrain-on-this-tile-is-not-counted-for-region-determination","text":"Applicable to: Terrain","title":"🔷 Base Terrain on this tile is not counted for Region determination"},{"location":"uniques/#starts-in-regions-of-this-type-receive-an-extra-resource","text":"Example: \"Starts in regions of this type receive an extra [Iron]\" Applicable to: Terrain","title":"🔷 Starts in regions of this type receive an extra [resource]"},{"location":"uniques/#never-receives-any-resources","text":"Applicable to: Terrain","title":"🔷 Never receives any resources"},{"location":"uniques/#becomes-terrainname-when-adjacent-to-terrainfilter","text":"Example: \"Becomes [terrainName] when adjacent to [Forest]\" Applicable to: Terrain","title":"🔷 Becomes [terrainName] when adjacent to [terrainFilter]"},{"location":"uniques/#considered-terrainquality-when-determining-start-locations","text":"Example: \"Considered [Undesirable] when determining start locations\" Applicable to: Terrain","title":"🔷 Considered [terrainQuality] when determining start locations"},{"location":"uniques/#doesnt-generate-naturally","text":"Applicable to: Terrain, Resource","title":"🔷 Doesn't generate naturally"},{"location":"uniques/#occurs-at-temperature-between-amount-and-amount-and-humidity-between-amount-and-amount","text":"Example: \"Occurs at temperature between [20] and [20] and humidity between [20] and [20]\" Applicable to: Terrain","title":"🔷 Occurs at temperature between [amount] and [amount] and humidity between [amount] and [amount]"},{"location":"uniques/#occurs-in-chains-at-high-elevations","text":"Applicable to: Terrain","title":"🔷 Occurs in chains at high elevations"},{"location":"uniques/#occurs-in-groups-around-high-elevations","text":"Applicable to: Terrain","title":"🔷 Occurs in groups around high elevations"},{"location":"uniques/#every-amount-tiles-with-this-terrain-will-receive-a-major-deposit-of-a-strategic-resource","text":"Example: \"Every [20] tiles with this terrain will receive a major deposit of a strategic resource.\" Applicable to: Terrain","title":"🔷 Every [amount] tiles with this terrain will receive a major deposit of a strategic resource."},{"location":"uniques/#rare-feature","text":"Applicable to: Terrain","title":"🔷 Rare feature"},{"location":"uniques/#resistant-to-nukes","text":"Applicable to: Terrain","title":"🔷 Resistant to nukes"},{"location":"uniques/#can-be-destroyed-by-nukes","text":"Applicable to: Terrain","title":"🔷 Can be destroyed by nukes"},{"location":"uniques/#fresh-water","text":"Applicable to: Terrain","title":"🔷 Fresh water"},{"location":"uniques/#rough-terrain","text":"Applicable to: Terrain","title":"🔷 Rough terrain"},{"location":"uniques/#improvement-uniques","text":"","title":"Improvement uniques"},{"location":"uniques/#can-also-be-built-on-tiles-adjacent-to-fresh-water","text":"Applicable to: Improvement","title":"🔷 Can also be built on tiles adjacent to fresh water"},{"location":"uniques/#stats-from-tilefilter-tiles","text":"Example: \"[+1 Gold, +2 Production] from [Farm] tiles\" Applicable to: Improvement","title":"🔷 [stats] from [tileFilter] tiles"},{"location":"uniques/#stats-for-each-adjacent-tilefilter","text":"Example: \"[+1 Gold, +2 Production] for each adjacent [Farm]\" Applicable to: Improvement","title":"🔷 [stats] for each adjacent [tileFilter]"},{"location":"uniques/#can-be-built-outside-your-borders","text":"Applicable to: Improvement","title":"🔷 Can be built outside your borders"},{"location":"uniques/#can-be-built-just-outside-your-borders","text":"Applicable to: Improvement","title":"🔷 Can be built just outside your borders"},{"location":"uniques/#cannot-be-built-on-tilefilter-tiles","text":"Example: \"Cannot be built on [Farm] tiles\" Applicable to: Improvement","title":"🔷 Cannot be built on [tileFilter] tiles"},{"location":"uniques/#does-not-need-removal-of-tilefilter","text":"Example: \"Does not need removal of [Farm]\" Applicable to: Improvement","title":"🔷 Does not need removal of [tileFilter]"},{"location":"uniques/#gives-a-defensive-bonus-of-amount","text":"Example: \"Gives a defensive bonus of [20]%\" Applicable to: Improvement","title":"🔷 Gives a defensive bonus of [amount]%"},{"location":"uniques/#costs-amount-gold-per-turn-when-in-your-territory","text":"Example: \"Costs [20] gold per turn when in your territory\" Applicable to: Improvement","title":"🔷 Costs [amount] gold per turn when in your territory"},{"location":"uniques/#adjacent-enemy-units-ending-their-turn-take-amount-damage","text":"Example: \"Adjacent enemy units ending their turn take [20] damage\" Applicable to: Improvement","title":"🔷 Adjacent enemy units ending their turn take [amount] damage"},{"location":"uniques/#great-improvement","text":"Applicable to: Improvement","title":"🔷 Great Improvement"},{"location":"uniques/#provides-a-random-bonus-when-entered","text":"Applicable to: Improvement","title":"🔷 Provides a random bonus when entered"},{"location":"uniques/#unpillagable","text":"Applicable to: Improvement","title":"🔷 Unpillagable"},{"location":"uniques/#indestructible","text":"Applicable to: Improvement","title":"🔷 Indestructible"},{"location":"uniques/#irremovable","text":"Applicable to: Improvement","title":"🔷 Irremovable"},{"location":"uniques/#resource-uniques","text":"","title":"Resource uniques"},{"location":"uniques/#generated-with-weight-amount","text":"Example: \"Generated with weight [20]\" Applicable to: Resource","title":"🔷 Generated with weight [amount]"},{"location":"uniques/#minor-deposits-generated-with-weight-amount","text":"Example: \"Minor deposits generated with weight [20]\" Applicable to: Resource","title":"🔷 Minor deposits generated with weight [amount]"},{"location":"uniques/#generated-near-city-states-with-weight-amount","text":"Example: \"Generated near City States with weight [20]\" Applicable to: Resource","title":"🔷 Generated near City States with weight [amount]"},{"location":"uniques/#special-placement-during-map-generation","text":"Applicable to: Resource","title":"🔷 Special placement during map generation"},{"location":"uniques/#generated-on-every-amount-tiles","text":"Example: \"Generated on every [20] tiles\" Applicable to: Resource","title":"🔷 Generated on every [amount] tiles"},{"location":"uniques/#guaranteed-with-strategic-balance-resource-option","text":"Applicable to: Resource","title":"🔷 Guaranteed with Strategic Balance resource option"},{"location":"uniques/#deposits-in-tilefilter-tiles-always-provide-amount-resources","text":"Example: \"Deposits in [Farm] tiles always provide [20] resources\" Applicable to: Resource","title":"🔷 Deposits in [tileFilter] tiles always provide [amount] resources"},{"location":"uniques/#can-only-be-created-by-mercantile-city-states","text":"Applicable to: Resource","title":"🔷 Can only be created by Mercantile City-States"},{"location":"uniques/#ruins-uniques","text":"","title":"Ruins uniques"},{"location":"uniques/#free-baseunitfilter-found-in-the-ruins","text":"Example: \"Free [Melee] found in the ruins\" Applicable to: Ruins","title":"🔷 Free [baseUnitFilter] found in the ruins"},{"location":"uniques/#amount-population-in-a-random-city","text":"Example: \"[20] population in a random city\" Applicable to: Ruins","title":"🔷 [amount] population in a random city"},{"location":"uniques/#amount-free-random-researchable-techs-from-the-era","text":"Example: \"[20] free random researchable Tech(s) from the [Ancient era]\" Applicable to: Ruins","title":"🔷 [amount] free random researchable Tech(s) from the [era]"},{"location":"uniques/#gain-amount-stat","text":"Example: \"Gain [20] [Culture]\" Applicable to: Ruins","title":"🔷 Gain [amount] [stat]"},{"location":"uniques/#gain-amount-amount-stat","text":"Example: \"Gain [20]-[20] [Culture]\" Applicable to: Ruins","title":"🔷 Gain [amount]-[amount] [stat]"},{"location":"uniques/#gain-enough-faith-for-a-pantheon","text":"Applicable to: Ruins","title":"🔷 Gain enough Faith for a Pantheon"},{"location":"uniques/#gain-enough-faith-for-amount-of-a-great-prophet","text":"Example: \"Gain enough Faith for [20]% of a Great Prophet\" Applicable to: Ruins","title":"🔷 Gain enough Faith for [amount]% of a Great Prophet"},{"location":"uniques/#reveal-up-to-amountall-tilefilter-within-a-amount-tile-radius","text":"Example: \"Reveal up to [amount/'all'] [Farm] within a [20] tile radius\" Applicable to: Ruins","title":"🔷 Reveal up to [amount/'all'] [tileFilter] within a [amount] tile radius"},{"location":"uniques/#from-a-randomly-chosen-tile-amount-tiles-away-from-the-ruins-reveal-tiles-up-to-amount-tiles-away-with-amount-chance","text":"Example: \"From a randomly chosen tile [20] tiles away from the ruins, reveal tiles up to [20] tiles away with [20]% chance\" Applicable to: Ruins","title":"🔷 From a randomly chosen tile [amount] tiles away from the ruins, reveal tiles up to [amount] tiles away with [amount]% chance"},{"location":"uniques/#this-unit-gains-amount-xp","text":"Example: \"This Unit gains [20] XP\" Applicable to: Ruins","title":"🔷 This Unit gains [amount] XP"},{"location":"uniques/#this-unit-upgrades-for-free-including-special-upgrades","text":"Applicable to: Ruins","title":"🔷 This Unit upgrades for free including special upgrades"},{"location":"uniques/#only-available-after-amount-turns","text":"Example: \"Only available after [20] turns\" Applicable to: Ruins","title":"🔷 Only available after [amount] turns"},{"location":"uniques/#hidden-before-founding-a-pantheon","text":"Applicable to: Ruins","title":"🔷 Hidden before founding a Pantheon"},{"location":"uniques/#hidden-after-founding-a-pantheon","text":"Applicable to: Ruins","title":"🔷 Hidden after founding a Pantheon"},{"location":"uniques/#hidden-after-generating-a-great-prophet","text":"Applicable to: Ruins","title":"🔷 Hidden after generating a Great Prophet"},{"location":"uniques/#citystate-uniques","text":"","title":"CityState uniques"},{"location":"uniques/#provides-stats-per-turn","text":"Example: \"Provides [+1 Gold, +2 Production] per turn\" Applicable to: CityState","title":"🔷 Provides [stats] per turn"},{"location":"uniques/#provides-stats-cityfilter-per-turn","text":"Example: \"Provides [+1 Gold, +2 Production] [in all cities] per turn\" Applicable to: CityState","title":"🔷 Provides [stats] [cityFilter] per turn"},{"location":"uniques/#provides-amount-happiness","text":"Example: \"Provides [20] Happiness\" Applicable to: CityState","title":"🔷 Provides [amount] Happiness"},{"location":"uniques/#provides-military-units-every-amount-turns","text":"Example: \"Provides military units every \u2248[20] turns\" Applicable to: CityState","title":"🔷 Provides military units every \u2248[amount] turns"},{"location":"uniques/#provides-a-unique-luxury","text":"Applicable to: CityState","title":"🔷 Provides a unique luxury"},{"location":"uniques/#conditional-uniques","text":"","title":"Conditional uniques"},{"location":"uniques/#_1","text":"Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_2","text":"Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_3","text":"Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_4","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_5","text":"Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_6","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_7","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_8","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_9","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_10","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_11","text":"Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_12","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_13","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_14","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_15","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_16","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_17","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_18","text":"Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_19","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_20","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_21","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_22","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_23","text":"Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_24","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_25","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_26","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_27","text":"Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_28","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_29","text":"Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_30","text":"Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_31","text":"Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_32","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_33","text":"Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_34","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_35","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_36","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_37","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_38","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_39","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_40","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_41","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_42","text":"Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_43","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#_44","text":"Example: \" \" Applicable to: Conditional","title":"🔷 "},{"location":"uniques/#deprecated-uniques","text":"\"[stats] from every Wonder\" - Deprecated as of 3.19.1, replace with \"[stats] from every [Wonder]\" \"[stats] from every [buildingFilter] in cities where this religion has at least [amount] followers\" - Deprecated as of 3.19.3, replace with \"[stats] from every [buildingFilter] \" \"+25% Production towards any buildings that already exist in the Capital\" - Deprecated as of 3.19.3, replace with \"[+25]% Production towards any buildings that already exist in the Capital\" \"[amount]% of food is carried over after population increases\" - Deprecated as of 3.19.2, replace with \"[amount]% Food is carried over after population increases [in this city]\" \"[amount]% of food is carried over [cityFilter] after population increases\" - Deprecated as of 3.19.2, replace with \"[amount]% Food is carried over after population increases [cityFilter]\" \"[amount]% Culture cost of natural border growth [cityFilter]\" - Deprecated as of 3.19.2, replace with \"[amount]% Culture cost of natural border growth [cityFilter]\" \"-[amount]% Culture cost of acquiring tiles [cityFilter]\" - Deprecated as of 3.19.1, replace with \"[-amount]% Culture cost of natural border growth [cityFilter]\" \"[amount]% cost of natural border growth\" - Deprecated as of 3.19.1, replace with \"[amount]% Culture cost of natural border growth [in all cities]\" \"-[amount]% Gold cost of acquiring tiles [cityFilter]\" - Deprecated as of 3.19.1, replace with \"[-amount]% Gold cost of acquiring tiles [cityFilter]\" \"[stat] cost of purchasing [baseUnitFilter] units in cities [amount]%\" - Deprecated as of 3.19.3, replace with \"[stat] cost of purchasing [baseUnitFilter] units [amount]%\" \"+[amount]% attacking strength for cities with garrisoned units\" - Deprecated as of 3.19.1, replace with \"[+amount]% Strength for cities \" \"Can embark and move over Coasts and Oceans immediately\" - Deprecated as of 3.19.9, replace with \"Enables embarkation for land units \", \"Enables embarked units to enter ocean tiles \" \"Population loss from nuclear attacks -[amount]%\" - Deprecated as of 3.19.2, replace with \"Population loss from nuclear attacks [-amount]% [in this city]\" \"[amount]% Natural religion spread [cityFilter] with [tech/policy]\" - Deprecated as of 3.19.3, replace with \"[amount]% Natural religion spread [cityFilter] \" OR \"[amount]% Natural religion spread [cityFilter] \" \"[amount] HP when healing in [tileFilter] tiles\" - Deprecated as of 3.19.4, replace with \"[amount] HP when healing \" \"Melee units pay no movement cost to pillage\" - Deprecated as of 3.18.17, replace with \"No movement cost to pillage \" \"Heal adjacent units for an additional 15 HP per turn\" - Deprecated as of 3.19.3, replace with \"All adjacent units heal [+15] HP when healing\" \"+[amount]% attack strength to all [mapUnitFilter] units for [amount2] turns\" - Deprecated as of 3.19.8, replace with \"[+amount]% Strength \" \"Golden Age length increased by [amount]%\" - Deprecated as of 3.18.17, replace with \"[+amount]% Golden Age length\" \"+[amount]% Defensive Strength for cities\" - Deprecated as of 3.18.17, replace with \"[+amount]% Strength for cities \" \"[amount]% Attacking Strength for cities\" - Deprecated as of 3.18.17, replace with \"[+amount]% Strength for cities \" \"[amount]% Strength for [mapUnitFilter] units which have another [mapUnitFilter] unit in an adjacent tile\" - Deprecated as of 3.18.17, replace with \"[amount]% Strength \" \"Gold cost of upgrading [baseUnitFilter] units reduced by [amount]%\" - Deprecated as of 3.18.17, replace with \"[-amount]% Gold cost of upgrading \" \"Double gold from Great Merchant trade missions\" - Deprecated as of 3.18.17, replace with \"[+100]% Gold from Great Merchant trade missions\" \"Defensive buildings in all cities are 25% more effective\" - Deprecated as of 3.18.17, replace with \"[+25]% City Strength from defensive buildings\" \"Maintenance on roads & railroads reduced by [amount]%\" - Deprecated as of 3.18.17, replace with \"[-amount]% maintenance on road & railroads\" \"-[amount]% maintenance cost for buildings [cityFilter]\" - Deprecated as of 3.18.17, replace with \"[-amount]% maintenance cost for buildings [cityFilter]\" \"+[amount] happiness from each type of luxury resource\" - Deprecated as of 3.18.17, replace with \"[+amount] Happiness from each type of luxury resource\" \"Culture cost of adopting new Policies reduced by [amount]%\" - Deprecated as of 3.18.17, replace with \"[-amount]% Culture cost of adopting new Policies\" \"[amount]% Culture cost of adopting new policies\" - Deprecated as of 3.19.1, replace with \"[amount]% Culture cost of adopting new Policies\" \"Quantity of Resources gifted by City-States increased by [amount]%\" - Deprecated as of 3.18.17, replace with \"[+amount]% resources gifted by City-States\" \"City-State Influence degrades [amount]% slower\" - Deprecated as of 3.18.17, replace with \"[-amount]% City-State Influence degradation\" \"Happiness from Luxury Resources gifted by City-States increased by [amount]%\" - Deprecated as of 3.18.17, replace with \"[+amount]% Happiness from luxury resources gifted by City-States\" \"+[amount]% [stat] from every [tileFilter/specialist/buildingName]\" - Deprecated as of 3.18.17, replace with \"[+amount]% [stat] from every [tileFilter/specialist/buildingName]\" \"+[amount]% yield from every [tileFilter]\" - Deprecated as of 3.18.17, replace with \"[+amount]% Yield from every [tileFilter]\" \"[stats] per turn from cities before [tech/policy]\" - Deprecated as of 3.18.14, replace with \"[stats] [in all cities] \" OR \"[stats] [in all cities] \" \"[mapUnitFilter] units gain [amount]% more Experience from combat\" - Deprecated as of 3.18.12, replace with \"[amount]% XP gained from combat \" \"[amount]% maintenance costs for [mapUnitFilter] units\" - Deprecated as of 3.18.14, replace with \"[amount]% maintenance costs \" \"50% of excess happiness added to culture towards policies\" - Deprecated as of 3.18.2, replace with \"[50]% of excess happiness converted to [Culture]\" \"-[amount]% food consumption by specialists [cityFilter]\" - Deprecated as of 3.18.2, replace with \"[-amount]% Food consumption by specialists [cityFilter]\" \"May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] starting from the [era] at an increasing price ([amount])\" - Deprecated as of 3.17.9, removed as of 3.19.3, replace with \"May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] at an increasing price ([amount]) \" \"Provides a free [buildingName] [cityFilter]\" - Deprecated as of 3.17.7 - removed 3.18.19, replace with \"Gain a free [buildingName] [cityFilter]\" \"+[amount]% [stat] [cityFilter]\" - Deprecated as of 3.17.10 - removed 3.18.18, replace with \"[+amount]% [stat] [cityFilter]\" \"+[amount]% [stat] in all cities\" - Deprecated as of 3.17.10 - removed 3.18.18, replace with \"[+amount]% [stat] [in all cities]\" \"[amount]% [stat] while the empire is happy\" - Deprecated as of 3.17.1 - removed 3.18.18, replace with \"[amount]% [stat] [in all cities] \" \"Immediately creates the cheapest available cultural building in each of your first [amount] cities for free\" - Deprecated as of 3.16.15 - removed 3.18.4, replace with \"Provides the cheapest [stat] building in your first [amount] cities for free\" \"Immediately creates a [buildingName] in each of your first [amount] cities for free\" - Deprecated as of 3.16.15 - removed 3.18.4, replace with \"Provides a [buildingName] in your first [amount] cities for free\" \"[mapUnitFilter] units deal +[amount]% damage\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+amount]% Strength \" \"+10% Strength for all units during Golden Age\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+10]% Strength \" \"[amount]% Strength for [mapUnitFilter] units in [tileFilter]\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount]% Strength \" \"+15% Combat Strength for all units when attacking Cities\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+15]% Strength \" \"+[amount] Movement for all [mapUnitFilter] units\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+amount] Movement \" \"+1 Movement for all units during Golden Age\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+1] Movement \" \"[amount] Sight for all [mapUnitFilter] units\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount] Sight \" \"[amount]% Spread Religion Strength for [mapUnitFilter] units\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount]% Spread Religion Strength \" \"+[amount]% Production when constructing [baseUnitFilter] units [cityFilter]\" - Deprecated as of 3.17.10 - removed 3.18.5, replace with \"[+amount]% Production when constructing [baseUnitFilter] units [cityFilter]\" \"+[amount]% Production when constructing [stat] buildings\" - Deprecated as of 3.17.10 - removed 3.18.5, replace with \"[+amount]% Production when constructing [stat] buildings [in all cities]\" \"+[amount]% Production when constructing [constructionFilter]\" - Deprecated as of 3.17.10 - removed 3.18.5, replace with \"[+amount]% Production when constructing [constructionFilter] buildings [in all cities]\" \"+[amount]% Production when constructing a [buildingName]\" - Deprecated as of 3.17.10 - removed 3.18.5, replace with \"[amount]% Production when constructing [buildingName] buildings [in all cities]\" \"+[amount]% Production when constructing [constructionFilter] [cityFilter]\" - Deprecated as of 3.17.10 - removed 3.18.5, replace with \"[amount]% Production when constructing [constructionFilter] buildings [cityFilter]\" \"Increases embarked movement +1\" - Deprecated As of 3.16.11 - removed 3.17.11, replace with \"[+1] Movement \" \"+1 Movement for all embarked units\" - Deprecated As of 3.16.11 - removed 3.17.11, replace with \"[+1] Movement \" \"Unhappiness from population decreased by [amount]%\" - Deprecated As of 3.16.11 - removed 3.17.11, replace with \"[-amount]% unhappiness from population [in all cities]\" \"Unhappiness from population decreased by [amount]% [cityFilter]\" - Deprecated As of 3.16.11 - removed 3.17.11, replace with \"[-amount]% unhappiness from population [cityFilter]\" \"+[amount]% growth [cityFilter]\" - Deprecated As of 3.16.14 - removed 3.17.11, replace with \"[+amount]% growth [cityFilter]\" \"+[amount]% growth [cityFilter] when not at war\" - Deprecated As of 3.16.14 - removed 3.17.11, replace with \"[+amount]% growth [cityFilter] \" \"-[amount]% [mapUnitFilter] unit maintenance costs\" - Deprecated As of 3.16.16 - removed as of 3.17.11, replace with \"[-amount]% maintenance costs \" \"-[amount]% unit upkeep costs\" - Deprecated As of 3.16.16 - removed 3.17.11, replace with \"[amount]% maintenance costs \" \"[stats] from every specialist\" - Deprecated As of 3.16.16 - removed 3.17.11, replace with \"[stats] from every specialist [in all cities]\" \"[stats] if this city has at least [amount] specialists\" - Deprecated As of 3.16.16 - removed 3.17.11, replace with \"[stats] \" \"+1 happiness from each type of luxury resource\" - Deprecated Extremely old - used for auto-updates only, replace with \"[+1] Happiness from each type of luxury resource\" \"-33% unit upkeep costs\" - Deprecated Extremely old - used for auto-updates only, replace with \"[-33]% maintenance costs \" \"-50% food consumption by specialists\" - Deprecated Extremely old - used for auto-updates only, replace with \"[-50]% Food consumption by specialists [in all cities]\" \"+50% attacking strength for cities with garrisoned units\" - Deprecated Extremely old - used for auto-updates only, replace with \"[+50]% Strength for cities \" \"Incompatible with [policy/tech/promotion]\" - Deprecated as of 3.19.8, replace with \"Only available \" OR \"Only available \" OR \"Only available \" \"Not displayed as an available construction without [buildingName/tech/resource/policy]\" - Deprecated as of 3.19.8, replace with \"Only available \" OR \"Only available \" OR \"Only available \" OR \"Only available \" \"Unlocked with [buildingName/tech/era/policy]\" - Deprecated as of 3.19.12, replace with \"Only available \" OR \"Only available \" OR \"Only available \" OR \"Only available \" \"Requires [buildingName/tech/era/policy]\" - Deprecated as of 3.19.12, replace with \"Only available \" OR \"Only available \" OR \"Only available \" OR \"Only available \" \"Cannot be built with [buildingName]\" - Deprecated as of 3.19.9, replace with \"Only available \" \"Requires a [buildingName] in this city\" - Deprecated as of 3.19.9, replace with \"Only available \" \"[stats] with [resource]\" - Deprecated as of 3.19.7, replace with \"[stats] \" \"Not displayed as an available construction unless [buildingName] is built\" - Deprecated as of 3.16.11, replace with \"Not displayed as an available construction without [buildingName]\" \"[stats] once [tech] is discovered\" - Deprecated as of 3.17.10 - removed 3.18.19, replace with \"[stats] \" \"Eliminates combat penalty for attacking from the sea\" - Deprecated as of 3.19.8, replace with \"Eliminates combat penalty for attacking across a coast\" \"[amount]% Bonus XP gain\" - Deprecated as of 3.18.12, replace with \"[amount]% XP gained from combat\" \"Cannot enter ocean tiles until Astronomy\" - Deprecated as of 3.18.6, replace with \"Cannot enter ocean tiles \" \"+[amount]% Strength when attacking\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+amount]% Strength \" \"+[amount]% Strength when defending\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[+amount]% Strength \" \"[amount]% Strength when defending vs [mapUnitFilter] units\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount]% Strength \" \"+[amount]% defence in [tileFilter] tiles\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount]% Strength \" \"+[amount]% Strength in [tileFilter]\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount]% Strength \" \"[amount] Visibility Range\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[amount] Sight\" \"Limited Visibility\" - Deprecated as of 3.17.5 - removed 3.18.5, replace with \"[-1] Sight\" \"Double movement in coast\" - Deprecated As of 3.17.1 - removed 3.17.13, replace with \"Double movement in [Coast]\" \"Double movement rate through Forest and Jungle\" - Deprecated As of 3.17.1 - removed 3.17.13, replace with \"Double movement in [terrainFilter]\" \"Double movement in Snow, Tundra and Hills\" - Deprecated As of 3.17.1 - removed 3.17.13, replace with \"Double movement in [terrainFilter]\" \"+[amount]% Strength\" - Deprecated As of 3.17.3 - removed 3.17.13, replace with \"[+amount]% Strength\" \"-[amount]% Strength\" - Deprecated As of 3.17.3 - removed 3.17.13, replace with \"[-amount]% Strength\" \"+[amount]% Strength vs [combatantFilter]\" - Deprecated As of 3.17.3 - removed 3.17.13, replace with \"[+amount]% Strength \" OR \"[+amount]% Strength \" \"-[amount]% Strength vs [combatantFilter]\" - Deprecated As of 3.17.3 - removed 3.17.13, replace with \"[-amount]% Strength \" OR \"[+amount]% Strength \" \"+[amount]% Combat Strength\" - Deprecated As of 3.17.3 - removed 3.17.13, replace with \"[+amount]% Strength\" \"+1 Visibility Range\" - Deprecated Extremely old - used for auto-updates only, replace with \"[+1] Sight\" \"+[amount] Visibility Range\" - Deprecated Extremely old - used for auto-updates only, replace with \"[+amount] Sight\" \"+[amount] Sight for all [mapUnitFilter] units\" - Deprecated Extremely old - used for auto-updates only, replace with \"[+amount] Sight \" \"+2 Visibility Range\" - Deprecated Extremely old - used for auto-updates only, replace with \"[+2] Sight\" \"Can build improvements on tiles\" - Deprecated Extremely old - used for auto-updates only, replace with \"Can build [Land] improvements on tiles\" \"Science gained from research agreements +50%\" - Deprecated Extremely old - used for auto-updates only, replace with \"Science gained from research agreements [+50]%\" \"Deal [amount] damage to adjacent enemy units\" - Deprecated as of 3.18.17, replace with \"Adjacent enemy units ending their turn take [amount] damage\" \"Cannot be built on [tileFilter] tiles until [tech] is discovered\" - Deprecated as of 3.18.5, replace with \"Cannot be built on [tileFilter] tiles \" \"[stats] on [tileFilter] tiles once [tech] is discovered\" - Deprecated as of 3.17.10 - removed 3.18.19, replace with \"[stats] from [tileFilter] tiles \" \"Deal 30 damage to adjacent enemy units\" - Deprecated as of 3.17.10 - removed 3.18.19, replace with \"Adjacent enemy units ending their turn take [30] damage\"","title":"Deprecated uniques"},{"location":"wiki/Audiovisual-Mods/","text":"Audiovisual Mods The 'Permanent audiovisual mod' feature Mods can override built-in graphics Mods can supply additional tilesets - see separate page Mods can supply additional graphics not included in the base game Mods can override built-in sounds Mods can supply additional music tracks Permanent audiovisual mods The following chapters describe possibilities that will work while a mod is active . It is either selected for the current game (during new game creation, cannot be changed after that for saved games), meaning all its rules and resources will be used. Or it is marked as 'Permanent audiovisual mod' in the mod manager (you must select it in the 'installed' column to get the checkbox). In that case only graphics and audio will be active, the rule changes will be ignored (if it contains any) unless the first way is also used. Override built-in graphics If a mod supplies an image with the same name and path as one included in the base game (and its atlas is up to date), and the mod is active, the mod's graphics will be used instead of the built-in one. For example, if you include a file named \"Images/OtherIcons/Link.png\" in your mod, you will be overriding the little chain links icon denoting linked lines in Civilopedia. Please note, as for adding items, your graphics should keep the size and color choices of the original, or the result may be surprising, e.g. when the game tries to tint such an image. Supply additional graphics Currently there are two kinds where the game has display capability but does not supply graphics itself, as described in the next paragraphs: Adding Wonder Splash Screens You can add wonder images to mods and they'll be displayed instead of the standard icon when a wonder is finished. The image needs to be a .png and 2:1 ratio so for example 200x100 px. Add the images to /Images/WonderImages/ . They need to be named according to the name field in Buildings.json , so for example \"Temple of Artemis.png\" or \"Stonehenge.png\" Remember, to be compatible with mobile devices, a fresh atlas needs to be generated including these. Adding Leader Portraits The base game comes without Leader Portraits, but is able to display them in greetings, Civilopedia, diplomacy screens, or the nation picker. A mod can supply these, by adding their images to /Images/LeaderIcons/ . The file name must correspond exactly with the leader name of a nation as defined in Nations.json, or they will be ignored. These work best if they are square, between 100x100 and 256x256 pixels, and include some transparent border within that area. For example, here is mod showing how to add leader portraits, which can complement the base game. Override built-in sounds This works like graphics, except no atlas is involved. E.g. you include a sounds/Click.mp3, it will play instead of the normal click sound. These files must stay short and small. A sound larger than 1MB when uncompressed may break or not play at all on mobile devices. Unciv tries to standardize on 24kHz sample rate, joint stereo, low-bitrate VBR (-128kbps) mp3. Only mp3 and ogg formats will be recognized (but an existing mp3 can be overridden with an ogg file). Supply additional music Sound files (mp3 or ogg) in a mod /music folder will be recognized and used when the mod is active. Except for context-specific music as described in the following paragraphs, tracks will play randomly from all available tracks (with a little bias to avoid close repetition of tracks). There is no overriding - a \"thatched-villagers.mp3\" in a mod will play in addition to and with the same likelihood as the file that the base game offers to download for you. There is no hard technical limit on bitrate or length, but large bandwidth requirements may lead to stuttering (The end of a \"next turn\", right before the world map is updated, and with very large maps, is the most likely to cause this). Context-sensitive music: Overview The Music Controller will generally play one track after another, with a pause (can be changed in options) between. Leave-game confirmation dialog is opened playback will fade out and pause and can resume when it is closed. There are various 'triggers' in the game code initiating a choice for a new track. The new track will, if necessary, fade out the currently playing track quickly before it starts playing. Track choice involves context provided by the trigger and a random factor, and an attempt is made to not repeat any track until at least eight others have played. Mods can provide their own music folder, and if they are active its contents will be treated exactly the same as those in the main music folder. Mods should control usage of their tracks by careful choice of file name. Mod developers can watch console output for messages logging track choice with trigger parameters or loading errors. One track is special: The Thatched Villagers (see also credits.md). The game is able to download it if the music folder is empty, and it is played when the music volume slider is used. It is also a fallback track should certain problems occur (a broken file, however, will shut down the player until another trigger happens). Context-sensitive music: List of Triggers Triggers indicate context (call it intent, mood, whatever, it doesn't matter) by optionally providing a prefix and/or suffix to match against the file name. There are a few flags as well influencing choice or behaviour - one flag function is to make prefix or suffix mandatory, meaning if no available file matches the track chooser will do nothing. Otherwise, a next track will always be chosen from the available list by sorting and then picking the first entry. Sorting is done by in order of precedence: Prefix match, Suffix match, Recently played, and a random number. Therefore, as currently no triggers have an empty prefix, files matching none of the prefixes will never play unless there are less than eight files matching the requested prefix. The current list of triggers is as follows: Description Prefix M[^M] Suffix M[^X] Flags Automatic next-track[^0] Ambient Launch game[^1] Menu Every 10th turn (player civ name) M Peace or War[^2] F[^F] New game: Select a mod (mod name) M Theme S[^S] New game: Pick a nation for a player (nation name) M Theme or Peace S[^S] Diplomacy: Select player (nation name) M Peace or War[^3] S[^S] First contact[^4] (civ name) M Theme or Peace M War declaration[^5] (civ name) M War M Civ defeated (civ name) Defeat M Golden Age (civ name) M Golden M N[^N] Wonder built (wonder name) M Built M N[^N] Tech researched (tech name) M Researched M N[^N] Map editor: Select nation start location (nation name) M Theme S[^S] N[^N] Options: Volume slider or Default track downloaded D[^D] Options: Click currently playing label[^6] M Ambient S[^S] Legend: [^N]: Not implemented [^M]: Prefix must match. If no matching file is found, the trigger will do nothing. [^X]: Suffix must match. If no matching file is found, the trigger will do nothing. [^S]: Stop after playback. No automatic next choice. [^F]: Slow fadeout of replaced track. [^D]: Always plays the default file. [^0]: Whenever a track finishes and the configured silence has elapsed, an 'Ambient' track without any context is chosen. Also triggered by 'resume' (e.g. switching to another app and back on Android) [^1]: First opening of the Main Menu (or the initial language picker). [^2]: Whether the active player is at war with anybody. [^3]: According to your relation to the picked player. [^4]: Excluding City States. [^5]: Both in the alert when another player declares War on you and declaring War yourself in Diplomacy screen. [^6]: Yes these flags are not optimal.","title":"Audiovisual Mods"},{"location":"wiki/Audiovisual-Mods/#audiovisual-mods","text":"The 'Permanent audiovisual mod' feature Mods can override built-in graphics Mods can supply additional tilesets - see separate page Mods can supply additional graphics not included in the base game Mods can override built-in sounds Mods can supply additional music tracks","title":"Audiovisual Mods"},{"location":"wiki/Audiovisual-Mods/#permanent-audiovisual-mods","text":"The following chapters describe possibilities that will work while a mod is active . It is either selected for the current game (during new game creation, cannot be changed after that for saved games), meaning all its rules and resources will be used. Or it is marked as 'Permanent audiovisual mod' in the mod manager (you must select it in the 'installed' column to get the checkbox). In that case only graphics and audio will be active, the rule changes will be ignored (if it contains any) unless the first way is also used.","title":"Permanent audiovisual mods"},{"location":"wiki/Audiovisual-Mods/#override-built-in-graphics","text":"If a mod supplies an image with the same name and path as one included in the base game (and its atlas is up to date), and the mod is active, the mod's graphics will be used instead of the built-in one. For example, if you include a file named \"Images/OtherIcons/Link.png\" in your mod, you will be overriding the little chain links icon denoting linked lines in Civilopedia. Please note, as for adding items, your graphics should keep the size and color choices of the original, or the result may be surprising, e.g. when the game tries to tint such an image.","title":"Override built-in graphics"},{"location":"wiki/Audiovisual-Mods/#supply-additional-graphics","text":"Currently there are two kinds where the game has display capability but does not supply graphics itself, as described in the next paragraphs:","title":"Supply additional graphics"},{"location":"wiki/Audiovisual-Mods/#adding-wonder-splash-screens","text":"You can add wonder images to mods and they'll be displayed instead of the standard icon when a wonder is finished. The image needs to be a .png and 2:1 ratio so for example 200x100 px. Add the images to /Images/WonderImages/ . They need to be named according to the name field in Buildings.json , so for example \"Temple of Artemis.png\" or \"Stonehenge.png\" Remember, to be compatible with mobile devices, a fresh atlas needs to be generated including these.","title":"Adding Wonder Splash Screens"},{"location":"wiki/Audiovisual-Mods/#adding-leader-portraits","text":"The base game comes without Leader Portraits, but is able to display them in greetings, Civilopedia, diplomacy screens, or the nation picker. A mod can supply these, by adding their images to /Images/LeaderIcons/ . The file name must correspond exactly with the leader name of a nation as defined in Nations.json, or they will be ignored. These work best if they are square, between 100x100 and 256x256 pixels, and include some transparent border within that area. For example, here is mod showing how to add leader portraits, which can complement the base game.","title":"Adding Leader Portraits"},{"location":"wiki/Audiovisual-Mods/#override-built-in-sounds","text":"This works like graphics, except no atlas is involved. E.g. you include a sounds/Click.mp3, it will play instead of the normal click sound. These files must stay short and small. A sound larger than 1MB when uncompressed may break or not play at all on mobile devices. Unciv tries to standardize on 24kHz sample rate, joint stereo, low-bitrate VBR (-128kbps) mp3. Only mp3 and ogg formats will be recognized (but an existing mp3 can be overridden with an ogg file).","title":"Override built-in sounds"},{"location":"wiki/Audiovisual-Mods/#supply-additional-music","text":"Sound files (mp3 or ogg) in a mod /music folder will be recognized and used when the mod is active. Except for context-specific music as described in the following paragraphs, tracks will play randomly from all available tracks (with a little bias to avoid close repetition of tracks). There is no overriding - a \"thatched-villagers.mp3\" in a mod will play in addition to and with the same likelihood as the file that the base game offers to download for you. There is no hard technical limit on bitrate or length, but large bandwidth requirements may lead to stuttering (The end of a \"next turn\", right before the world map is updated, and with very large maps, is the most likely to cause this).","title":"Supply additional music"},{"location":"wiki/Audiovisual-Mods/#context-sensitive-music-overview","text":"The Music Controller will generally play one track after another, with a pause (can be changed in options) between. Leave-game confirmation dialog is opened playback will fade out and pause and can resume when it is closed. There are various 'triggers' in the game code initiating a choice for a new track. The new track will, if necessary, fade out the currently playing track quickly before it starts playing. Track choice involves context provided by the trigger and a random factor, and an attempt is made to not repeat any track until at least eight others have played. Mods can provide their own music folder, and if they are active its contents will be treated exactly the same as those in the main music folder. Mods should control usage of their tracks by careful choice of file name. Mod developers can watch console output for messages logging track choice with trigger parameters or loading errors. One track is special: The Thatched Villagers (see also credits.md). The game is able to download it if the music folder is empty, and it is played when the music volume slider is used. It is also a fallback track should certain problems occur (a broken file, however, will shut down the player until another trigger happens).","title":"Context-sensitive music: Overview"},{"location":"wiki/Audiovisual-Mods/#context-sensitive-music-list-of-triggers","text":"Triggers indicate context (call it intent, mood, whatever, it doesn't matter) by optionally providing a prefix and/or suffix to match against the file name. There are a few flags as well influencing choice or behaviour - one flag function is to make prefix or suffix mandatory, meaning if no available file matches the track chooser will do nothing. Otherwise, a next track will always be chosen from the available list by sorting and then picking the first entry. Sorting is done by in order of precedence: Prefix match, Suffix match, Recently played, and a random number. Therefore, as currently no triggers have an empty prefix, files matching none of the prefixes will never play unless there are less than eight files matching the requested prefix. The current list of triggers is as follows: Description Prefix M[^M] Suffix M[^X] Flags Automatic next-track[^0] Ambient Launch game[^1] Menu Every 10th turn (player civ name) M Peace or War[^2] F[^F] New game: Select a mod (mod name) M Theme S[^S] New game: Pick a nation for a player (nation name) M Theme or Peace S[^S] Diplomacy: Select player (nation name) M Peace or War[^3] S[^S] First contact[^4] (civ name) M Theme or Peace M War declaration[^5] (civ name) M War M Civ defeated (civ name) Defeat M Golden Age (civ name) M Golden M N[^N] Wonder built (wonder name) M Built M N[^N] Tech researched (tech name) M Researched M N[^N] Map editor: Select nation start location (nation name) M Theme S[^S] N[^N] Options: Volume slider or Default track downloaded D[^D] Options: Click currently playing label[^6] M Ambient S[^S] Legend: [^N]: Not implemented [^M]: Prefix must match. If no matching file is found, the trigger will do nothing. [^X]: Suffix must match. If no matching file is found, the trigger will do nothing. [^S]: Stop after playback. No automatic next choice. [^F]: Slow fadeout of replaced track. [^D]: Always plays the default file. [^0]: Whenever a track finishes and the configured silence has elapsed, an 'Ambient' track without any context is chosen. Also triggered by 'resume' (e.g. switching to another app and back on Android) [^1]: First opening of the Main Menu (or the initial language picker). [^2]: Whether the active player is at war with anybody. [^3]: According to your relation to the picked player. [^4]: Excluding City States. [^5]: Both in the alert when another player declares War on you and declaring War yourself in Diplomacy screen. [^6]: Yes these flags are not optimal.","title":"Context-sensitive music: List of Triggers"},{"location":"wiki/Building-locally-without-Android-Studio/","text":"If you also have JDK 11 installed, you can compile Unciv on your own by cloning (or downloading and unzipping) the project, opening a terminal in the Unciv folder and run the following commands: Windows Running: gradlew desktop:run Building: gradlew desktop:dist Linux/Mac OS Running: ./gradlew desktop:run Building: ./gradlew desktop:dist If the terminal returns Permission denied or Command not found on Mac/Linux, run chmod +x ./gradlew first. This is a one-time procedure. If you get an error that Android SDK folder wasn't found, firstly install it by doing in terminal: sudo apt update && sudo apt install android-sdk (Debian, Ubuntu, Mint etc.) After that you should put its folder to the file local.properties by adding this line: sdk.dir = /path/to/android/sdk which can be /usr/lib/android-sdk or something other. If during the first launch it throws an error that the JDK version is wrong try this JDK installation . Gradle may take up to several minutes to download files. Be patient. After building, the output .JAR file should be in /desktop/build/libs/Unciv.jar For actual development, you'll probably need to download Android Studio and build it yourself - see Contributing :)","title":"Building locally without Android Studio"},{"location":"wiki/Building-locally-without-Android-Studio/#windows","text":"Running: gradlew desktop:run Building: gradlew desktop:dist","title":"Windows"},{"location":"wiki/Building-locally-without-Android-Studio/#linuxmac-os","text":"Running: ./gradlew desktop:run Building: ./gradlew desktop:dist If the terminal returns Permission denied or Command not found on Mac/Linux, run chmod +x ./gradlew first. This is a one-time procedure. If you get an error that Android SDK folder wasn't found, firstly install it by doing in terminal: sudo apt update && sudo apt install android-sdk (Debian, Ubuntu, Mint etc.) After that you should put its folder to the file local.properties by adding this line: sdk.dir = /path/to/android/sdk which can be /usr/lib/android-sdk or something other. If during the first launch it throws an error that the JDK version is wrong try this JDK installation . Gradle may take up to several minutes to download files. Be patient. After building, the output .JAR file should be in /desktop/build/libs/Unciv.jar For actual development, you'll probably need to download Android Studio and build it yourself - see Contributing :)","title":"Linux/Mac OS"},{"location":"wiki/Civilization-related-JSON-files/","text":"Beliefs.json Buildings.json Nations.json Policies.json Quests.json Religions.json Specialists.json Techs.json - Column structure - Tech structure Beliefs.json link to original This file contains the beliefs that can be chosen for religions in your mod. Each belief can have the following attributes: | attribute | Type | Optional or not | notes | | --------- | ---- | --------------- | ----- | | name | String | Required | Name of the belief | | type | String | Required | The type of the belief. Valid values are: \"Pantheon\", \"Follower\", \"Founder\" and \"Enhancer\". | | uniques | List of Strings | defaults to none | The unique abilities this belief adds to cities following it. May be chosen from the list of building uniques here , as well as the general uniques on that page | | civilopediaText | List | Default empty | see civilopediaText chapter | Buildings.json link to original This file should contain all the buildings and wonders you want to use in your mod. Each building can have the following attributes: | attribute | Type | Optional or not | notes | | --------- | ---- | --------------- | ----- | | name | String | required | Name of the building | | cost | Integer (\u22650) | defaults to 0 | Amount of production required to build the building | | food | Integer | defaults to 0 | Food produced by the building | | production | Integer | defaults to 0 | Production produced by the building | | gold | Integer | defaults to 0 | etc. | | happiness | Integer | defaults to 0 | | | culture | Integer | defaults to 0 | | | science | Integer | defaults to 0 | | | faith | Integer | defaults to 0 | | | maintenance | Integer (\u22650) | defaults to 0 | Maintenance cost of the building | | isWonder | Boolean | defaults to false | Whether this building is a global wonder | | isNationalWonder | Boolean | defaults to false | Whether this building is a national wonder | | requiredBuilding | String | defaults to none | A building that has to be built before this building can be built. Must be in Buildings.json | | cannotBeBuiltWith | String | defaults to none | The building [cannotBeBuiltWith] and this building cannot exist in the same city together. Should be in Buildings.json | | providesFreeBuilding | String | defaults to none | When the building is built, [providesFreeBuilding] is also automatically added to the city | | requiredTech | String | defaults to none | The tech that should be researched before this building may be built. Must be in Techs.json | | requiredResource | String | defaults to none | The resource that is consumed when building this building. Must be in TileResources.json | | requiredNearbyImprovedResources | List of Strings | defaults to none | The building can only be built if any of the resources in this list are within the borders of this city and have been improved. Each resource must be in TileResources.json | | replaces | String | defaults to none | The name of a building that should be replaced by this building. Must be in Buildings.json | | uniqueTo | String | defaults to none | If supplied, only the nation with this name can build this building. Must be in Nations.json | | xpForNewUnits | Integer | defaults to 0 | XP granted automatically to units built in this city | | cityStrength | Integer | defaults to 0 | Strength bonus the city in which this building is built receives | | cityHealth | Integer | defaults to 0 | Health bonus the city in which this building is built receives | | hurryCostModifier | Integer | defaults to 0 | When this building is bought using gold or faith, the price is increased by this much percent | | quote | String | defaults to none | If this building is a (national) wonder, this string will be shown on the completion popup | | uniques | List of Strings | defaults to none | List of unique abilities this building has. Most of these can be found here | | replacementTextForUniques | String | defaults to none | If provided, this string will be shown instead of all of the uniques | | percentStatBonus | Object | defaults to none | Percentual bonus for stats provided by the building. Valid keys are the names of stats (production, gold, science, etc.), valid values are Integers (\u22650) | | greatPersonPoints | Object | defaults to none | How many great person points for each type will be generated per turn. Valid keys are the names of great people (Great Scientist, Great Engineer, etc. .), valid values are Integers (\u22650) | | specialistSlots | Object | defaults to none | Specialist slots provided by this building. Valid keys are the names of specialists (as defined in Specialists.json ), valid values are Integers, the amount of slots provided for this specialist | | civilopediaText | List | Default empty | see civilopediaText chapter | Nations.json Link to original This file contains all the nations and city states, including Barbarians and Spectator. Attribute Type Optional? Notes name String Required leaderName String Default empty Omit only for city states! If you want LeaderPortraits, the image file names must match exactly, including case. style String Default empty Modifier appended to pixel unit image names adjective String Default empty Currently unused cityStateType Enum Default absent Distinguishes Major Civilizations from City States (Cultured, Maritime, Mercantile, Militaristic) startBias List Default empty Zero or more of: terrainFilter or \"Avoid [terrainFilter]\". Two or more will be logically \"and\"-ed, and if the filters result in no choices, the entire attribute is ignored (e.g. \"startBias\": [\"Snow\",\"Tundra\"] will never work). preferredVictoryType Enum Default Neutral Neutral, Cultural, Diplomatic, Domination or Scientific startIntroPart1 String Default empty Introductory blurb shown to Player on game start... startIntroPart2 String Default empty ... second paragraph. NO \"TBD\"!!! Leave empty to skip that alert. declaringWar String Default empty another greeting attacked String Default empty another greeting defeated String Default empty another greeting introduction String Default empty another greeting neutralHello String Default empty another greeting hateHello String Default empty another greeting tradeRequest String Default empty another greeting innerColor 3x Integer Default black R, G, B for outer ring of nation icon outerColor 3x Integer Required R, G, B for inner circle of nation icon uniqueName String Default empty Decorative name for the special characteristic of this Nation uniqueText String Default empty Replacement text for \"uniques\". If empty, uniques are listed individually. uniques List Default empty Properties of the civilization - see here cities List Default empty City names used sequentially for newly founded cities. civilopediaText List Default empty see civilopediaText chapter Policies.json Link to original This file lists the available social policies that can be \"bought\" with culture. They are organized in 'branches', each branch has an 'opener', one or more 'member' policies, and a 'finisher'. Therefore this file is organized using two levels - branch and member policy. The properties of the 'opener' are defined with the branch level, while the 'finisher' has an entry on the member level which must be named as branch name + \" Complete\", case sensitive. Each policy branch can have the following properties: | Attribute | Type | Optional? | Notes | |-----------|------|-----------|-------| | name | String | Required | | | era | String | Required | Unlocking era as defined in Eras.json | | uniques | List | Default empty | List of effects, see here | | policies | List | Default empty | List of member policies | Each member policy can have the following properties: | Attribute | Type | Optional? | Notes | |-----------|------|-----------|-------| | name | String | Required | | | row | Integer | Required | Placement in UI, each unit approximately half the icon size | | column | Integer | Required | Placement in UI, each unit approximately half the icon size | | requires | List | Default empty | List of prerequisite policy names | | uniques | List | Default empty | List of effects, see here | Quests.json Link to original This file contains the Quests that may be given to major Civilizations by City States. Attribute Type Optional? Notes name String Required Unique identifier name of the quest, it is also shown description String Required Description of the quest shown to players type Enum Default Individual Individual or Global influece Float Default 40 Influence reward gained on quest completion duration Integer Default 0 Maximum number of turns to complete the quest, 0 if there's no turn limit minimumCivs Integer Default 1 Minimum number of Civs needed to start the quest. It is meaningful only for type = Global Religions.json Link to original This is just a list of Strings specifying all predefined Religion names. Corresponding icons must exist, that's all to it. After all, they're just containers for Beliefs . Specialists.json Link to original This file should contain a list of all possible specialists that you want in your mod. Each specialist can have the following attributes: | attribute | type | optional or not | notes | | --------- | ---- | --------------- | ----- | | name | String | required | Name of the specialist | | food | Integer | defaults to 0 | Amount of food produced by this specialist | | production | Integer | defaults to 0 | Amount of production produced by this specialist | | gold | Integer | defaults to 0 | etc. | | culture | Integer | defaults to 0 | | | science | Integer | defaults to 0 | | faith | Integer | defaults to 0 | | color | List of 3 Integers | required | Color of the image for this specialist | | greatPersonPoints | Object | defaults to none | Great person points generated by this specialist. Valid keys are the names of the great person(Great Scientist, Great Merachant, etc.), valid values are Integers (\u22650) | Techs.json Link to original This file contains all the technologies. It is organized into an outer list of 'columns' which in turn contain one or more tech each. Column structure Attribute Type Optional? Notes columnNumber Integer Required Horizontal placement in the Tech Tree. era String Required References Eras.json . techCost Integer Required Default cost of the techs in this column. buildingCost Integer Required Default cost of buildings requiring this tech. wonderCost Integer Required Default cost of wonders requiring this tech. techs List of Techs Required List of techs as follows - pay attention to the nesting of {} and []. Tech structure Attribute Type Optional? Notes name String Required The name of this Technology. row Integer Defaults to 0 Vertical placement in the Tech Tree, must be unique per column. cost Integer Defaults to column techCost The amount of science required to research this tech. prerequisites List Default empty A list of the names of techs that are prerequisites of this tech. Only direct prerequisites are necessary. quote String Default empty A nice story presented to the player when they research this tech. uniques List Default empty Properties granted by the tech - see here . civilopediaText List Default empty see civilopediaText chapter .","title":"Civilization related JSON files"},{"location":"wiki/Civilization-related-JSON-files/#beliefsjson","text":"link to original This file contains the beliefs that can be chosen for religions in your mod. Each belief can have the following attributes: | attribute | Type | Optional or not | notes | | --------- | ---- | --------------- | ----- | | name | String | Required | Name of the belief | | type | String | Required | The type of the belief. Valid values are: \"Pantheon\", \"Follower\", \"Founder\" and \"Enhancer\". | | uniques | List of Strings | defaults to none | The unique abilities this belief adds to cities following it. May be chosen from the list of building uniques here , as well as the general uniques on that page | | civilopediaText | List | Default empty | see civilopediaText chapter |","title":"Beliefs.json"},{"location":"wiki/Civilization-related-JSON-files/#buildingsjson","text":"link to original This file should contain all the buildings and wonders you want to use in your mod. Each building can have the following attributes: | attribute | Type | Optional or not | notes | | --------- | ---- | --------------- | ----- | | name | String | required | Name of the building | | cost | Integer (\u22650) | defaults to 0 | Amount of production required to build the building | | food | Integer | defaults to 0 | Food produced by the building | | production | Integer | defaults to 0 | Production produced by the building | | gold | Integer | defaults to 0 | etc. | | happiness | Integer | defaults to 0 | | | culture | Integer | defaults to 0 | | | science | Integer | defaults to 0 | | | faith | Integer | defaults to 0 | | | maintenance | Integer (\u22650) | defaults to 0 | Maintenance cost of the building | | isWonder | Boolean | defaults to false | Whether this building is a global wonder | | isNationalWonder | Boolean | defaults to false | Whether this building is a national wonder | | requiredBuilding | String | defaults to none | A building that has to be built before this building can be built. Must be in Buildings.json | | cannotBeBuiltWith | String | defaults to none | The building [cannotBeBuiltWith] and this building cannot exist in the same city together. Should be in Buildings.json | | providesFreeBuilding | String | defaults to none | When the building is built, [providesFreeBuilding] is also automatically added to the city | | requiredTech | String | defaults to none | The tech that should be researched before this building may be built. Must be in Techs.json | | requiredResource | String | defaults to none | The resource that is consumed when building this building. Must be in TileResources.json | | requiredNearbyImprovedResources | List of Strings | defaults to none | The building can only be built if any of the resources in this list are within the borders of this city and have been improved. Each resource must be in TileResources.json | | replaces | String | defaults to none | The name of a building that should be replaced by this building. Must be in Buildings.json | | uniqueTo | String | defaults to none | If supplied, only the nation with this name can build this building. Must be in Nations.json | | xpForNewUnits | Integer | defaults to 0 | XP granted automatically to units built in this city | | cityStrength | Integer | defaults to 0 | Strength bonus the city in which this building is built receives | | cityHealth | Integer | defaults to 0 | Health bonus the city in which this building is built receives | | hurryCostModifier | Integer | defaults to 0 | When this building is bought using gold or faith, the price is increased by this much percent | | quote | String | defaults to none | If this building is a (national) wonder, this string will be shown on the completion popup | | uniques | List of Strings | defaults to none | List of unique abilities this building has. Most of these can be found here | | replacementTextForUniques | String | defaults to none | If provided, this string will be shown instead of all of the uniques | | percentStatBonus | Object | defaults to none | Percentual bonus for stats provided by the building. Valid keys are the names of stats (production, gold, science, etc.), valid values are Integers (\u22650) | | greatPersonPoints | Object | defaults to none | How many great person points for each type will be generated per turn. Valid keys are the names of great people (Great Scientist, Great Engineer, etc. .), valid values are Integers (\u22650) | | specialistSlots | Object | defaults to none | Specialist slots provided by this building. Valid keys are the names of specialists (as defined in Specialists.json ), valid values are Integers, the amount of slots provided for this specialist | | civilopediaText | List | Default empty | see civilopediaText chapter |","title":"Buildings.json"},{"location":"wiki/Civilization-related-JSON-files/#nationsjson","text":"Link to original This file contains all the nations and city states, including Barbarians and Spectator. Attribute Type Optional? Notes name String Required leaderName String Default empty Omit only for city states! If you want LeaderPortraits, the image file names must match exactly, including case. style String Default empty Modifier appended to pixel unit image names adjective String Default empty Currently unused cityStateType Enum Default absent Distinguishes Major Civilizations from City States (Cultured, Maritime, Mercantile, Militaristic) startBias List Default empty Zero or more of: terrainFilter or \"Avoid [terrainFilter]\". Two or more will be logically \"and\"-ed, and if the filters result in no choices, the entire attribute is ignored (e.g. \"startBias\": [\"Snow\",\"Tundra\"] will never work). preferredVictoryType Enum Default Neutral Neutral, Cultural, Diplomatic, Domination or Scientific startIntroPart1 String Default empty Introductory blurb shown to Player on game start... startIntroPart2 String Default empty ... second paragraph. NO \"TBD\"!!! Leave empty to skip that alert. declaringWar String Default empty another greeting attacked String Default empty another greeting defeated String Default empty another greeting introduction String Default empty another greeting neutralHello String Default empty another greeting hateHello String Default empty another greeting tradeRequest String Default empty another greeting innerColor 3x Integer Default black R, G, B for outer ring of nation icon outerColor 3x Integer Required R, G, B for inner circle of nation icon uniqueName String Default empty Decorative name for the special characteristic of this Nation uniqueText String Default empty Replacement text for \"uniques\". If empty, uniques are listed individually. uniques List Default empty Properties of the civilization - see here cities List Default empty City names used sequentially for newly founded cities. civilopediaText List Default empty see civilopediaText chapter","title":"Nations.json"},{"location":"wiki/Civilization-related-JSON-files/#policiesjson","text":"Link to original This file lists the available social policies that can be \"bought\" with culture. They are organized in 'branches', each branch has an 'opener', one or more 'member' policies, and a 'finisher'. Therefore this file is organized using two levels - branch and member policy. The properties of the 'opener' are defined with the branch level, while the 'finisher' has an entry on the member level which must be named as branch name + \" Complete\", case sensitive. Each policy branch can have the following properties: | Attribute | Type | Optional? | Notes | |-----------|------|-----------|-------| | name | String | Required | | | era | String | Required | Unlocking era as defined in Eras.json | | uniques | List | Default empty | List of effects, see here | | policies | List | Default empty | List of member policies | Each member policy can have the following properties: | Attribute | Type | Optional? | Notes | |-----------|------|-----------|-------| | name | String | Required | | | row | Integer | Required | Placement in UI, each unit approximately half the icon size | | column | Integer | Required | Placement in UI, each unit approximately half the icon size | | requires | List | Default empty | List of prerequisite policy names | | uniques | List | Default empty | List of effects, see here |","title":"Policies.json"},{"location":"wiki/Civilization-related-JSON-files/#questsjson","text":"Link to original This file contains the Quests that may be given to major Civilizations by City States. Attribute Type Optional? Notes name String Required Unique identifier name of the quest, it is also shown description String Required Description of the quest shown to players type Enum Default Individual Individual or Global influece Float Default 40 Influence reward gained on quest completion duration Integer Default 0 Maximum number of turns to complete the quest, 0 if there's no turn limit minimumCivs Integer Default 1 Minimum number of Civs needed to start the quest. It is meaningful only for type = Global","title":"Quests.json"},{"location":"wiki/Civilization-related-JSON-files/#religionsjson","text":"Link to original This is just a list of Strings specifying all predefined Religion names. Corresponding icons must exist, that's all to it. After all, they're just containers for Beliefs .","title":"Religions.json"},{"location":"wiki/Civilization-related-JSON-files/#specialistsjson","text":"Link to original This file should contain a list of all possible specialists that you want in your mod. Each specialist can have the following attributes: | attribute | type | optional or not | notes | | --------- | ---- | --------------- | ----- | | name | String | required | Name of the specialist | | food | Integer | defaults to 0 | Amount of food produced by this specialist | | production | Integer | defaults to 0 | Amount of production produced by this specialist | | gold | Integer | defaults to 0 | etc. | | culture | Integer | defaults to 0 | | | science | Integer | defaults to 0 | | faith | Integer | defaults to 0 | | color | List of 3 Integers | required | Color of the image for this specialist | | greatPersonPoints | Object | defaults to none | Great person points generated by this specialist. Valid keys are the names of the great person(Great Scientist, Great Merachant, etc.), valid values are Integers (\u22650) |","title":"Specialists.json"},{"location":"wiki/Civilization-related-JSON-files/#techsjson","text":"Link to original This file contains all the technologies. It is organized into an outer list of 'columns' which in turn contain one or more tech each.","title":"Techs.json"},{"location":"wiki/Civilization-related-JSON-files/#column-structure","text":"Attribute Type Optional? Notes columnNumber Integer Required Horizontal placement in the Tech Tree. era String Required References Eras.json . techCost Integer Required Default cost of the techs in this column. buildingCost Integer Required Default cost of buildings requiring this tech. wonderCost Integer Required Default cost of wonders requiring this tech. techs List of Techs Required List of techs as follows - pay attention to the nesting of {} and [].","title":"Column structure"},{"location":"wiki/Civilization-related-JSON-files/#tech-structure","text":"Attribute Type Optional? Notes name String Required The name of this Technology. row Integer Defaults to 0 Vertical placement in the Tech Tree, must be unique per column. cost Integer Defaults to column techCost The amount of science required to research this tech. prerequisites List Default empty A list of the names of techs that are prerequisites of this tech. Only direct prerequisites are necessary. quote String Default empty A nice story presented to the player when they research this tech. uniques List Default empty Properties granted by the tech - see here . civilopediaText List Default empty see civilopediaText chapter .","title":"Tech structure"},{"location":"wiki/Coding-standards/","text":"As an open-source project, there will be a lot of eyes on our code. The main purpose of having a coding standard is for the code to be as immediately readable as possible to as many potential contributors, and hence most of it focuses on defaulting to coding structures that exist in other similar languages (Java, C#) when possible. Don't use .let{} and ?: Kotlin is made greater for being strict with nullability. Don't let this fact confuse people new to it. These can be simply replaced by if(x!=null) which is much more readable. They all probably compile to the same bytecode anyway, so when in doubt - readability. for(item in list) and not list.forEach{} For loops go waaaay back, forEach doesn't. As an added bonus, I'm pretty sure that because forEach accepts a function parameter, then when debugging it won't automatically step into these lines, unlike for. Avoid premature abstraction There's no need to create an interface if there is only one implementation of that interface. Doing so obfuscates the actual code that's running and increases the Time To Relevant Code. If abstraction becomes necessary later, we can always do it later.","title":"Coding standards"},{"location":"wiki/Coding-standards/#dont-use-let-and","text":"Kotlin is made greater for being strict with nullability. Don't let this fact confuse people new to it. These can be simply replaced by if(x!=null) which is much more readable. They all probably compile to the same bytecode anyway, so when in doubt - readability.","title":"Don't use .let{} and ?:"},{"location":"wiki/Coding-standards/#foritem-in-list-and-not-listforeach","text":"For loops go waaaay back, forEach doesn't. As an added bonus, I'm pretty sure that because forEach accepts a function parameter, then when debugging it won't automatically step into these lines, unlike for.","title":"for(item in list) and not list.forEach{}"},{"location":"wiki/Coding-standards/#avoid-premature-abstraction","text":"There's no need to create an interface if there is only one implementation of that interface. Doing so obfuscates the actual code that's running and increases the Time To Relevant Code. If abstraction becomes necessary later, we can always do it later.","title":"Avoid premature abstraction"},{"location":"wiki/Creating-a-custom-tileset/","text":"How to make Unciv use your custom tileset You should read the Mods page first before proceeding In order to add a tileset mod (yes, tilesets are just another type of mod), all you need to do is add your images under Images/Tilesets/MyCoolTilesetExample and enable the mod as a permanent visual mod - the game will recognize the tileset, and allow you to pick it in the options menu. Let's look at the example \"Grassland+Jungle+Dyes+Trading post\" to learn how the game decides which images it should use for this tile: When there is a rule variant entry in the tileset config for this tile we will use the entry. Else if there is an image called \"Grassland+Jungle+Dyes+Trading post\" we will use it instead. Otherwise, we will check if there is an image called \"Grassland+Jungle\" (BaseTerrain+Terrainfeatures) and \"Dyes+Trading post\" (Resource+Improvement) and use the remainings of it. Let's say you made an image called \"Grassland+Jungle\" but none called \"Dyes+Trading post\". In the end, we will then use the images \"Grassland+Jungle\", \"Dyes\" and \"Trading post\". All these images can also use era-dependant variants if you want to change the appearance of, let's say, \"Trading post\" throughout the game. Just create images and add the suffix \"-[era name]\". E.g. \"Trading post-Classical era\", \"Trading post-Industrial era\", etc. It is advised to use the layered approach (1 and 3) often because it comes with a few advantages. Mainly: - Decreased filesize (on disk, for downloads) - Easier support for new terrains, improvements, resources, and for changing existing tiles You should keep in mind that the default rendering order is: BaseTerrain, TerrainFeatures, Resource, Improvement. Tileset config This is where tileset configs shine. You can use these to alter the way Unicv renders tiles. To create a config for your tileset you just need to create a new .json file under Jsons/Tilesets/. Just create a .txt file and rename it to MyCoolTilesetExample.json. You only have to add things if you want to change them. Else the default values will be used. This is an example of such a config file that I will explain below: \"useColorAsBaseTerrain\": \"false\", \"unexploredTileColor\": {\"r\":1,\"g\":1,\"b\":1,\"a\":1}, \"fogOfWarColor\": {\"r\":1,\"g\":0,\"b\":0,\"a\":1}, \"ruleVariants\": { \"Grassland+Forest\": [\"Grassland\",\"ForestForGrassland\"], \"Grassland+Jungle+Dyes+Trading post\": [\"Grassland\",\"JungleForGrasslandBack\",\"Dyes+Trading post\",\"JungleForGrasslandFront\"] } useColorAsBaseTerrain A boolean value (\"true\" or \"false\"). Default value: \"true\" If true all tiles will be colored in their corresponding base terrain color. This is how the \"Default\" tileset works. unexploredTileColor A color defined with normalized RGBA values. Default value: \"{\"r\":0.24705882, \"g\":0.24705882, \"b\":0.24705882, \"a\":1}\" (DarkGray) Defines the color of the unexplored tiles. fogOfWarColor A color defined with normalized RGBA values. Default value: \"{\"r\":0, \"g\":0, \"b\":0, \"a\":1}\" (Black) Defines the color of the fog of war. The color gets approximated by 60% to allow the colors of the images below to shine through. ruleVariants A dictionary mapping string to string[]. Default value: empty The ruleVariants are the most powerful part of the tileset config. With this, you can define, for a specific tile, which images and in which order these images should be used. An example is given in the code above. For the tile \"Grassland+Jungle+Dyes+Trading post\" we then use the images \"Grassland\", \"JungleForGrasslandBack\", \"Dyes+Trading post\" and \"JungleForGrasslandFront\" in that order. Nation-coloured units Unciv can colour units according to the civilization that owns them. [PR3231] This is used by providing multiple images per unit, each representing a coloured layer. The image suffixed with \"-1\" will be tinted to the civilization's inner colour, and the image suffixed with \"-2\" will be tinted to the civilization's outer colour. For example: Image Description Colour Archer.png Base image Untinted Archer-1.png Colour layer Nation inner colour Arhcer-2.png Colour layer Nation outer colour The Civ Army Color Style Sheet mod by @AdityaMH and the 5Hex Tileset by @ravignir are very good practical examples of how this can be used.","title":"How to make Unciv use your custom tileset"},{"location":"wiki/Creating-a-custom-tileset/#how-to-make-unciv-use-your-custom-tileset","text":"","title":"How to make Unciv use your custom tileset"},{"location":"wiki/Creating-a-custom-tileset/#you-should-read-the-mods-page-first-before-proceeding","text":"In order to add a tileset mod (yes, tilesets are just another type of mod), all you need to do is add your images under Images/Tilesets/MyCoolTilesetExample and enable the mod as a permanent visual mod - the game will recognize the tileset, and allow you to pick it in the options menu. Let's look at the example \"Grassland+Jungle+Dyes+Trading post\" to learn how the game decides which images it should use for this tile: When there is a rule variant entry in the tileset config for this tile we will use the entry. Else if there is an image called \"Grassland+Jungle+Dyes+Trading post\" we will use it instead. Otherwise, we will check if there is an image called \"Grassland+Jungle\" (BaseTerrain+Terrainfeatures) and \"Dyes+Trading post\" (Resource+Improvement) and use the remainings of it. Let's say you made an image called \"Grassland+Jungle\" but none called \"Dyes+Trading post\". In the end, we will then use the images \"Grassland+Jungle\", \"Dyes\" and \"Trading post\". All these images can also use era-dependant variants if you want to change the appearance of, let's say, \"Trading post\" throughout the game. Just create images and add the suffix \"-[era name]\". E.g. \"Trading post-Classical era\", \"Trading post-Industrial era\", etc. It is advised to use the layered approach (1 and 3) often because it comes with a few advantages. Mainly: - Decreased filesize (on disk, for downloads) - Easier support for new terrains, improvements, resources, and for changing existing tiles You should keep in mind that the default rendering order is: BaseTerrain, TerrainFeatures, Resource, Improvement.","title":"You should read the Mods page first before proceeding"},{"location":"wiki/Creating-a-custom-tileset/#tileset-config","text":"This is where tileset configs shine. You can use these to alter the way Unicv renders tiles. To create a config for your tileset you just need to create a new .json file under Jsons/Tilesets/. Just create a .txt file and rename it to MyCoolTilesetExample.json. You only have to add things if you want to change them. Else the default values will be used. This is an example of such a config file that I will explain below: \"useColorAsBaseTerrain\": \"false\", \"unexploredTileColor\": {\"r\":1,\"g\":1,\"b\":1,\"a\":1}, \"fogOfWarColor\": {\"r\":1,\"g\":0,\"b\":0,\"a\":1}, \"ruleVariants\": { \"Grassland+Forest\": [\"Grassland\",\"ForestForGrassland\"], \"Grassland+Jungle+Dyes+Trading post\": [\"Grassland\",\"JungleForGrasslandBack\",\"Dyes+Trading post\",\"JungleForGrasslandFront\"] }","title":"Tileset config"},{"location":"wiki/Creating-a-custom-tileset/#usecolorasbaseterrain","text":"A boolean value (\"true\" or \"false\"). Default value: \"true\" If true all tiles will be colored in their corresponding base terrain color. This is how the \"Default\" tileset works.","title":"useColorAsBaseTerrain"},{"location":"wiki/Creating-a-custom-tileset/#unexploredtilecolor","text":"A color defined with normalized RGBA values. Default value: \"{\"r\":0.24705882, \"g\":0.24705882, \"b\":0.24705882, \"a\":1}\" (DarkGray) Defines the color of the unexplored tiles.","title":"unexploredTileColor"},{"location":"wiki/Creating-a-custom-tileset/#fogofwarcolor","text":"A color defined with normalized RGBA values. Default value: \"{\"r\":0, \"g\":0, \"b\":0, \"a\":1}\" (Black) Defines the color of the fog of war. The color gets approximated by 60% to allow the colors of the images below to shine through.","title":"fogOfWarColor"},{"location":"wiki/Creating-a-custom-tileset/#rulevariants","text":"A dictionary mapping string to string[]. Default value: empty The ruleVariants are the most powerful part of the tileset config. With this, you can define, for a specific tile, which images and in which order these images should be used. An example is given in the code above. For the tile \"Grassland+Jungle+Dyes+Trading post\" we then use the images \"Grassland\", \"JungleForGrasslandBack\", \"Dyes+Trading post\" and \"JungleForGrasslandFront\" in that order.","title":"ruleVariants"},{"location":"wiki/Creating-a-custom-tileset/#nation-coloured-units","text":"Unciv can colour units according to the civilization that owns them. [PR3231] This is used by providing multiple images per unit, each representing a coloured layer. The image suffixed with \"-1\" will be tinted to the civilization's inner colour, and the image suffixed with \"-2\" will be tinted to the civilization's outer colour. For example: Image Description Colour Archer.png Base image Untinted Archer-1.png Colour layer Nation inner colour Arhcer-2.png Colour layer Nation outer colour The Civ Army Color Style Sheet mod by @AdityaMH and the 5Hex Tileset by @ravignir are very good practical examples of how this can be used.","title":"Nation-coloured units"},{"location":"wiki/Force-rating-calculation/","text":"Force rating Since the question has come up several times, here is a summary of how Force ratings are calculated. Base Unit Force Evaluation First the base unit gets a force evaluation. If the unit has a ranged attack, the starting force is the ranged strength ^ 1.45. Otherwise the starting force is strength ^ 1.5. This is multiplied by the unit's movement ^ 0.3. Nukes get +4000. Then this is multiplied by a bunch of modifiers: * 0.5 if ranged naval * 0.5 if self-destructs when attacking * Half the city attack bonus (So +25% if the unit has +50% when attacking cities) * A Quarter of attack bonuses vs things other than cities * Half the bonus \"when attacking\" * Half the bonus \"when defending\" * +25% if paradrop able * -20% if needs to set up to attack * Half the bonus from certain terrain * +20% bonus per extra attack per turn Individual Unit Force Evaluation Each individual unit has a Force equal to the Base Unit Force, * multiplied by (number of times promoted +1) ^ 0.3. * multiplied by current health as a percentage. Civ Force Ranking The civs Force Ranking is based on the sum of all their units' Force Evaluation (cities are not counted). Only half the Force of naval units is counted. This is multiplied by a gold modifier equal to the square root of current gold, as a percentage. The gold multiplier is constrained to be between 1 and 2, so the max multiplier is 2 which is reached at 10000 gold. Show Me Some Numbers Scout 13 Archer 19 Slinger 19 Dromon 23 Warrior 27 Maori Warrior 27 Brute 27 Bowman 29 Jaguar 36 Catapult 39 Composite Bowman 39 Galleass 41 Chariot Archer 42 War Elephant 44 War Chariot 45 Horse Archer 45 Trireme 46 Spearman 49 Ballista 55 Persian Immortal 56 Horseman 62 Hoplite 63 Swordsman 64 Chu-Ko-Nu 66 Quinquereme 69 African Forest Elephant 72 Battering Ram 80 Cataphract 80 Crossbowman 81 Longbowman 81 Companion Cavalry 84 Legion 86 Mohawk Warrior 86 Pikeman 87 Landsknecht 87 Trebuchet 88 Keshik 89 Frigate 100 Hwach'a 110 Longswordsman 118 Camel Archer 124 Samurai 126 Berserker 133 Knight 134 Conquistador 134 Mandekalu Cavalry 134 Caravel 134 Ship of the Line 139 Musketman 144 Cannon 151 Minuteman 154 Janissary 162 Gatling Gun 169 Musketeer 182 Tercio 182 Naresuan's Elephant 194 Lancer 204 Hakkapeliitta 204 Sipahi 218 Privateer 222 Rifleman 243 Carolean 243 Sea Beggar 244 Artillery 245 Battleship 269 Great War Bomber 290 Cavalry 300 Hussar 320 Triplane 325 Turtle Ship 327 Cossack 337 Norwegian Ski Infantry 345 Guided Missile 378 Carrier 408 Submarine 420 Bomber 425 Great War Infantry 434 Machine Gun 465 Fighter 470 Foreign Legion 477 Ironclad 486 Zero 508 Anti-Tank Gun 542 B17 551 Marine 645 Landship 703 Infantry 720 Nuclear Submarine 735 Stealth Bomber 771 Paratrooper 806 Anti-Aircraft Gun 819 Destroyer 870 Missile Cruiser 888 Rocket Artillery 930 Tank 948 Jet Fighter 988 Helicopter Gunship 992 Mechanized Infantry 1186 Panzer 1223 Mobile SAM 1376 Modern Armor 1620 Giant Death Robot 2977 Atomic Bomb 4714 Nuclear Missile 7906","title":"Force rating"},{"location":"wiki/Force-rating-calculation/#force-rating","text":"Since the question has come up several times, here is a summary of how Force ratings are calculated.","title":"Force rating"},{"location":"wiki/Force-rating-calculation/#base-unit-force-evaluation","text":"First the base unit gets a force evaluation. If the unit has a ranged attack, the starting force is the ranged strength ^ 1.45. Otherwise the starting force is strength ^ 1.5. This is multiplied by the unit's movement ^ 0.3. Nukes get +4000. Then this is multiplied by a bunch of modifiers: * 0.5 if ranged naval * 0.5 if self-destructs when attacking * Half the city attack bonus (So +25% if the unit has +50% when attacking cities) * A Quarter of attack bonuses vs things other than cities * Half the bonus \"when attacking\" * Half the bonus \"when defending\" * +25% if paradrop able * -20% if needs to set up to attack * Half the bonus from certain terrain * +20% bonus per extra attack per turn","title":"Base Unit Force Evaluation"},{"location":"wiki/Force-rating-calculation/#individual-unit-force-evaluation","text":"Each individual unit has a Force equal to the Base Unit Force, * multiplied by (number of times promoted +1) ^ 0.3. * multiplied by current health as a percentage.","title":"Individual Unit Force Evaluation"},{"location":"wiki/Force-rating-calculation/#civ-force-ranking","text":"The civs Force Ranking is based on the sum of all their units' Force Evaluation (cities are not counted). Only half the Force of naval units is counted. This is multiplied by a gold modifier equal to the square root of current gold, as a percentage. The gold multiplier is constrained to be between 1 and 2, so the max multiplier is 2 which is reached at 10000 gold.","title":"Civ Force Ranking"},{"location":"wiki/Force-rating-calculation/#show-me-some-numbers","text":"Scout 13 Archer 19 Slinger 19 Dromon 23 Warrior 27 Maori Warrior 27 Brute 27 Bowman 29 Jaguar 36 Catapult 39 Composite Bowman 39 Galleass 41 Chariot Archer 42 War Elephant 44 War Chariot 45 Horse Archer 45 Trireme 46 Spearman 49 Ballista 55 Persian Immortal 56 Horseman 62 Hoplite 63 Swordsman 64 Chu-Ko-Nu 66 Quinquereme 69 African Forest Elephant 72 Battering Ram 80 Cataphract 80 Crossbowman 81 Longbowman 81 Companion Cavalry 84 Legion 86 Mohawk Warrior 86 Pikeman 87 Landsknecht 87 Trebuchet 88 Keshik 89 Frigate 100 Hwach'a 110 Longswordsman 118 Camel Archer 124 Samurai 126 Berserker 133 Knight 134 Conquistador 134 Mandekalu Cavalry 134 Caravel 134 Ship of the Line 139 Musketman 144 Cannon 151 Minuteman 154 Janissary 162 Gatling Gun 169 Musketeer 182 Tercio 182 Naresuan's Elephant 194 Lancer 204 Hakkapeliitta 204 Sipahi 218 Privateer 222 Rifleman 243 Carolean 243 Sea Beggar 244 Artillery 245 Battleship 269 Great War Bomber 290 Cavalry 300 Hussar 320 Triplane 325 Turtle Ship 327 Cossack 337 Norwegian Ski Infantry 345 Guided Missile 378 Carrier 408 Submarine 420 Bomber 425 Great War Infantry 434 Machine Gun 465 Fighter 470 Foreign Legion 477 Ironclad 486 Zero 508 Anti-Tank Gun 542 B17 551 Marine 645 Landship 703 Infantry 720 Nuclear Submarine 735 Stealth Bomber 771 Paratrooper 806 Anti-Aircraft Gun 819 Destroyer 870 Missile Cruiser 888 Rocket Artillery 930 Tank 948 Jet Fighter 988 Helicopter Gunship 992 Mechanized Infantry 1186 Panzer 1223 Mobile SAM 1376 Modern Armor 1620 Giant Death Robot 2977 Atomic Bomb 4714 Nuclear Missile 7906","title":"Show Me Some Numbers"},{"location":"wiki/From-code-to-deployment/","text":"From code to deployment So, your code works! You've solved all the bugs and now you just need to get it out to everyone! So, how does THAT work? The process has two major parts, one is \"Getting your code in the main repository\" and the other is \"Deploying versions\" - as a developer, you'll be taking an active part in the first process, but the second process is on me =) Getting your code in the main repo First off, push your changes with Git to your own branch at https://github.com/YourUsername/Unciv.git. I hope you've been doing this during development too, but that's none of my business *sips tea* Issue a pull request from https://github.com/YourUsername/Unciv - from the Pull Requests is the simplest The Travis build will check that your proposed change builds properly and passes all tests I'll go over your pull request and will ask questions and request changes - this is not only for code quality and standard, it's mostly so you can learn how the repo works for the next change you make =) When everything looks good, I'll merge your code in and it'll enter the next release! Deploying versions When I'm ready to release a new version I: * Comment \"merge translations\" in one of the open PRs tagged as 'mergeable translation' to trigger the translation branch creation, add a \"summary\" comment to trigger summary generation, merge the PR and delete the branch (so next version translation branch starts fresh) * From my workstation - pull the latest changes and run the translation generation * Change the versionCode and versionName in the Android build.gradle so that Google Play and F-droid can recognize that it's a different release * Add an entry in the changelog.md done, WITHOUT hashtags, and less than 500 characters (that's the limit for Google play entries). The formatting needs to be exact or the text sent to Discord, the Github release etc. won't be complete. * Add a tag to the commit of the version. When the Github action sees that we've added a tag, it will run a build, and this time (because of the configuration we put in the yml file file), it will: * Pack a .jar file, which will work for every operating system with Java * Use Linux and Windows JDKs to create standalone zips for 32 and 64 bit systems, because we can't rely on the fact that users will have a JRE * Download Butler and use it to push the new versions to the itch.io page * Read the changelog.md file to get the changes for the latest version * Upload all of these files to a new release on Github, with the release notes, which will get added to the Releases page * Send an announcement on the Discord server of the version release and release notes via webhook * Pack, Sign, and Upload a new APK to the Google Play Console at 10% rollout * The F-Droid bot checks periodically if we added a new tag. When it recognizes that we did, it will update the yaml file here * When the bot next runs and sees that there's a version it doesn't have a release for, it will attempt to build the new release. The log of the build will be added here (redirects to the latest build), and the new release will eventually be available here About Google Play publishing +We start at a 10% rollout, after a day with no major problems go to 30%, and after another day to 100%. If you were counting that means that most players will get the new version after 2+ days. + +If there were problems, we halt the current rollout, fix the problems, and release a patch version, which starts at 10% again. + +Dear future me - the automation was extremely annoying guesswork to set up, so the facts you need to know are: - There is a user at the Google Cloud Platform Account Manager called Unciv_Upload_Account. There is an access key to this account, in json, stored as the Github secret GOOGLE_PLAY_SERVICE_ACCOUNT_JSON. - This user was granted ADMIN permissions to the Google Play (after much trial and error since nothing else seemed to work) under User > Users and Permissions. Under Manage > Account permissions, you can see that it has Admin. Updating the wiki Pages for the Unciv Github Wiki are kept in the main repository under /docs/wiki . The process to edit the wiki is as follows: Open a pull request in the main Unciv repository that changes files under /docs/wiki . Once the pull request is merged, an account with commit privileges on the Unciv repository leaves a comment saying \" update wiki \". This comment triggers a bot to copy all the wiki files from the main repository into the Github wiki, with a link back to the PR in its commit message for credit. Doing things this way has several distinct advantages over using the Github Wiki web interface directly: Changes can be proposed via PR and proofread or fact-checked. A proper MarkDown editor or IDE can be used to write the wiki, bringing faster editing, clickable links while editing, better live HTML preview, and automatic detection of problems like broken links. The wiki files can also be browsed at https://github.com/yairm210/Unciv/tree/master/docs/wiki. Auto-generated documentation made by the build process can be placed directly in the wiki. However, it also imposes a couple of conventions about how links should best be formatted: Link type Format Example Inter-wiki Should begin with \"./\", and include \".md\". ./Mods.md#other Code or asset file Should begin with \"/\", and be relative to the project root. /android/assets/game.png These formats will allow IDEs like Android studio to resolve these links and check for broken links, while also working on the Github code browser . The bot that updates the wiki from the main repository automatically translates them into formats that are compatible with Github Wikis, which have somewhat non-standard requirements.","title":"From code to deployment"},{"location":"wiki/From-code-to-deployment/#from-code-to-deployment","text":"So, your code works! You've solved all the bugs and now you just need to get it out to everyone! So, how does THAT work? The process has two major parts, one is \"Getting your code in the main repository\" and the other is \"Deploying versions\" - as a developer, you'll be taking an active part in the first process, but the second process is on me =)","title":"From code to deployment"},{"location":"wiki/From-code-to-deployment/#getting-your-code-in-the-main-repo","text":"First off, push your changes with Git to your own branch at https://github.com/YourUsername/Unciv.git. I hope you've been doing this during development too, but that's none of my business *sips tea* Issue a pull request from https://github.com/YourUsername/Unciv - from the Pull Requests is the simplest The Travis build will check that your proposed change builds properly and passes all tests I'll go over your pull request and will ask questions and request changes - this is not only for code quality and standard, it's mostly so you can learn how the repo works for the next change you make =) When everything looks good, I'll merge your code in and it'll enter the next release!","title":"Getting your code in the main repo"},{"location":"wiki/From-code-to-deployment/#deploying-versions","text":"When I'm ready to release a new version I: * Comment \"merge translations\" in one of the open PRs tagged as 'mergeable translation' to trigger the translation branch creation, add a \"summary\" comment to trigger summary generation, merge the PR and delete the branch (so next version translation branch starts fresh) * From my workstation - pull the latest changes and run the translation generation * Change the versionCode and versionName in the Android build.gradle so that Google Play and F-droid can recognize that it's a different release * Add an entry in the changelog.md done, WITHOUT hashtags, and less than 500 characters (that's the limit for Google play entries). The formatting needs to be exact or the text sent to Discord, the Github release etc. won't be complete. * Add a tag to the commit of the version. When the Github action sees that we've added a tag, it will run a build, and this time (because of the configuration we put in the yml file file), it will: * Pack a .jar file, which will work for every operating system with Java * Use Linux and Windows JDKs to create standalone zips for 32 and 64 bit systems, because we can't rely on the fact that users will have a JRE * Download Butler and use it to push the new versions to the itch.io page * Read the changelog.md file to get the changes for the latest version * Upload all of these files to a new release on Github, with the release notes, which will get added to the Releases page * Send an announcement on the Discord server of the version release and release notes via webhook * Pack, Sign, and Upload a new APK to the Google Play Console at 10% rollout * The F-Droid bot checks periodically if we added a new tag. When it recognizes that we did, it will update the yaml file here * When the bot next runs and sees that there's a version it doesn't have a release for, it will attempt to build the new release. The log of the build will be added here (redirects to the latest build), and the new release will eventually be available here","title":"Deploying versions"},{"location":"wiki/From-code-to-deployment/#about-google-play-publishing","text":"+We start at a 10% rollout, after a day with no major problems go to 30%, and after another day to 100%. If you were counting that means that most players will get the new version after 2+ days. + +If there were problems, we halt the current rollout, fix the problems, and release a patch version, which starts at 10% again. + +Dear future me - the automation was extremely annoying guesswork to set up, so the facts you need to know are: - There is a user at the Google Cloud Platform Account Manager called Unciv_Upload_Account. There is an access key to this account, in json, stored as the Github secret GOOGLE_PLAY_SERVICE_ACCOUNT_JSON. - This user was granted ADMIN permissions to the Google Play (after much trial and error since nothing else seemed to work) under User > Users and Permissions. Under Manage > Account permissions, you can see that it has Admin.","title":"About Google Play publishing"},{"location":"wiki/From-code-to-deployment/#updating-the-wiki","text":"Pages for the Unciv Github Wiki are kept in the main repository under /docs/wiki . The process to edit the wiki is as follows: Open a pull request in the main Unciv repository that changes files under /docs/wiki . Once the pull request is merged, an account with commit privileges on the Unciv repository leaves a comment saying \" update wiki \". This comment triggers a bot to copy all the wiki files from the main repository into the Github wiki, with a link back to the PR in its commit message for credit. Doing things this way has several distinct advantages over using the Github Wiki web interface directly: Changes can be proposed via PR and proofread or fact-checked. A proper MarkDown editor or IDE can be used to write the wiki, bringing faster editing, clickable links while editing, better live HTML preview, and automatic detection of problems like broken links. The wiki files can also be browsed at https://github.com/yairm210/Unciv/tree/master/docs/wiki. Auto-generated documentation made by the build process can be placed directly in the wiki. However, it also imposes a couple of conventions about how links should best be formatted: Link type Format Example Inter-wiki Should begin with \"./\", and include \".md\". ./Mods.md#other Code or asset file Should begin with \"/\", and be relative to the project root. /android/assets/game.png These formats will allow IDEs like Android studio to resolve these links and check for broken links, while also working on the Github code browser . The bot that updates the wiki from the main repository automatically translates them into formats that are compatible with Github Wikis, which have somewhat non-standard requirements.","title":"Updating the wiki"},{"location":"wiki/Getting-Started/","text":"This is a guide to editing, building, running and deploying Unciv from code So first things first - the initial \"No assumptions\" setup to have Unciv run from-code on your computer! Install Android Studio - it's free and awesome! Be aware that it's a long download! Install Git, it's the way for us to work together on this project. UI is optional, Android Studio has good Git tools built in :) Getting the code Create a Github account, if you don't already have one Fork the repo (click the \"Fork\" button on the top-right corner of https://github.com/yairm210/Unciv) - this will create a \"copy\" of the code on your account, at https://github.com/YourUsername/Unciv Clone your fork with git - the location will be https://github.com/YourUsername/Unciv.git, visible from the green \"Clone or download\" button at https://github.com/YourUsername/Unciv Load the project in Android Studio, Gradle will attempt the initial sync. If this is your first time with Android Studio, this may require you to accept the Android Build-tools licenses, which works differently on every device, so search for your OS-specific solution. A new install may not be able to do the initial sync - this comes in the form of Unable to find method ''void org.apache.commons.compress.archivers.zip.ZipFile.(java.nio.channels.SeekableByteChannel)'' errors when you try to sync. If you have this problem go into File > Settings > Appearance & Behavior > System Settings > Android SDK Click \"SDK Tools\" Select \"Show Package Details\" in the bottom right Choose version 30.0.3 under \"Android SDK Build-Tools \" Click \"Apply\" In Android Studio, Run > Edit configurations. Click \"+\" to add a new configuration Choose \"Application\" Set the module to Unciv.desktop , main class to com.unciv.app.desktop.DesktopLauncher and \\android\\assets\\ as the Working directory, OK to close the window If you get a ../../docs/uniques.md (No such file or directory) error that means you forgot to set the working directory! Select the Desktop configuration and click the green arrow button to run! I also recommend going to Settings > Version Control > Commit and turning off 'Before commit - perform code analysis' Unciv uses Gradle to specify dependencies and how to run. In the background, the Gradle gnomes will be off fetching the packages (a one-time effort) and, once that's done, will build the project! Congratulations! Unciv should now be running on your computer! Now we can start changing some code, and later we'll see how your changes make it into the main repository! Now would be a good time to get to know the project in general at the Project Structure overview!","title":"Getting Started"},{"location":"wiki/Home/","text":"Welcome to the Unciv wiki! If you're a developer, you'll probably want to start at the Getting Started page! If you're a translator, head over to Translating! If you're a modder, start here .","title":"Home"},{"location":"wiki/Installing-on-macOS/","text":"There is currently two ways to install UnCiv on macOS. It is recommended that you use the first method as the second one is overly complicated and the end result will be the same. Both installation methods require that you have Java 8 installed on your mac. Installing using JAR If you don't already have Java 8 installed on your mac make sure you download it from the official website . Once you have downloaded the file open it and follow the instructions on screen. Now that you have Java 8 installed it's time to download the latest UnCiv JAR. This can be done from the releases screen here on Github. Download the file called Unciv.jar. After downloading Unciv.jar open Finder on your mac and go to the location where you chose to save the file. Right-click or Control-click the file and chose Open. You will now be prompted with a window saying something similar to macOS cannot verify the developer of \"Unciv.jar\". Are you sure you want to open it? Press the Open button. Congratulations, you have now installed UnCiv. You may want to add a shortcut to the desktop to be able to open the game more easily. (Sadly UnCiv dose not auto update when installing it using this method on macOS so you will need to download the latest Unciv.jar from Github every time you want to update the game.) Installing from source For instructions on how to install UnCiv from source see Building locally without Android Studio . It is not recommended to use this method as it achieves the same result as the first method whilst being much more complicated and prone to errors along the way. (Sadly UnCiv dose not auto update when installing it using this method on macOS so you will need to follow these steps every time you want to update the game.)","title":"Installing on macOS"},{"location":"wiki/Installing-on-macOS/#installing-using-jar","text":"If you don't already have Java 8 installed on your mac make sure you download it from the official website . Once you have downloaded the file open it and follow the instructions on screen. Now that you have Java 8 installed it's time to download the latest UnCiv JAR. This can be done from the releases screen here on Github. Download the file called Unciv.jar. After downloading Unciv.jar open Finder on your mac and go to the location where you chose to save the file. Right-click or Control-click the file and chose Open. You will now be prompted with a window saying something similar to macOS cannot verify the developer of \"Unciv.jar\". Are you sure you want to open it? Press the Open button. Congratulations, you have now installed UnCiv. You may want to add a shortcut to the desktop to be able to open the game more easily. (Sadly UnCiv dose not auto update when installing it using this method on macOS so you will need to download the latest Unciv.jar from Github every time you want to update the game.)","title":"Installing using JAR"},{"location":"wiki/Installing-on-macOS/#installing-from-source","text":"For instructions on how to install UnCiv from source see Building locally without Android Studio . It is not recommended to use this method as it achieves the same result as the first method whilst being much more complicated and prone to errors along the way. (Sadly UnCiv dose not auto update when installing it using this method on macOS so you will need to follow these steps every time you want to update the game.)","title":"Installing from source"},{"location":"wiki/JSON-files-for-mods/","text":"These pages are a work in progress. Information they contain may be incomplete. The JSON files that make up mods can have many different fields, and as not all are used in the base game, this wiki page will contain the full information of each. It will also give a short explanation of the syntax of JSON files. Table of Contents General Overview of JSON files Civilization-related JSON files Beliefs.json Buildings.json Nations.json Policies.json Quests.json Religions.json Specialists.json Techs.json Map-related JSON files Terrains.json TileResources.json TileImprovements.json Ruins.json Tileset-specific json Unit-related JSON files Units.json UnitPromotions.json UnitTypes.json Miscellaneous JSON files Difficulties.json Eras.json ModOptions.json Stats Sounds Civilopedia text General Overview of JSON files Resources: json.org , ISO standard Almost all Unciv JSON files start with a \"[\" and end with a \"]\". In between these are different objects of the type you are describing, each of which is contained between a \"{\" and a \"}\". For example, a very simple units.json may look like: [ { \"name\": \"Warrior\", \"cost\": 16 }, { \"name\": \"Spearman\", \"cost\": 24, \"promotions\": [\"Shock I\", \"Drill I\"] } ] This file contains two unit objects, one for a warrior and one for a spearman. These objects have different attributes, in this case \"name\", \"cost\" and \"promotions\". All these attributes have a certain type, a String (text) for \"name\", an Integer for \"cost\" and a List of Strings for \"promotions\". There are different types of attributes: | type | notes | | --------- | ----- | | String | A word or sentence. Should be between double quotes (\") | | Integer | A number. Can be both positive or negative. Should not be between quotes | | Boolean | A value that can either be 'true' or 'false'. Should not be between quotes | | List of [type] | If multiple values could apply (such as with the promotions above), they should be put inside a list. Each element of the list should be written like a normal attribute, seperated by comma's, and enclosed between square braces. E.g.: [\"Shock I\", \"Shock II\"] or [1, 2, 3]. | | Object | The most complicated type of attribute. An object is comprised of multiple attributes, each of which again has a type. These attributes have a key (the part before the \":\") and a value (the part behind it). For an example, see below. | Example of a Buildings.json adding a new \"Cultural Library\" building which gives +50% science and +50% culture: [ { \"name\": \"Cultural Library\" \"percentStatBonus\" : {\"science\": 50, \"culture\": 50} } ] The keys in this example are \"science\" and \"culture\", and both have the value \"50\". In some sense you can see from these types that JSON files themselves are actually a list of objects, each describing a single building, unit or something else. Information on JSON files used in the game Many parts of Unciv are moddable, and for each there is a seperate json file. There is a json file for buildings, for units, for promotions units can have, for technologies, etc. The different new buildings or units you define can also have lots of different attributes, though not all are required. Below are tables documenting all the different attributes everything can have. Only the attributes which are noted to be 'required' must be provided. All others have a default value that will be used when it is omitted. The individual files are described on separate pages: Civilization-related JSON files Map-related JSON files Unit-related JSON files Miscellaneous JSON files","title":"JSON files for mods"},{"location":"wiki/JSON-files-for-mods/#table-of-contents","text":"General Overview of JSON files Civilization-related JSON files Beliefs.json Buildings.json Nations.json Policies.json Quests.json Religions.json Specialists.json Techs.json Map-related JSON files Terrains.json TileResources.json TileImprovements.json Ruins.json Tileset-specific json Unit-related JSON files Units.json UnitPromotions.json UnitTypes.json Miscellaneous JSON files Difficulties.json Eras.json ModOptions.json Stats Sounds Civilopedia text","title":"Table of Contents"},{"location":"wiki/JSON-files-for-mods/#general-overview-of-json-files","text":"Resources: json.org , ISO standard Almost all Unciv JSON files start with a \"[\" and end with a \"]\". In between these are different objects of the type you are describing, each of which is contained between a \"{\" and a \"}\". For example, a very simple units.json may look like: [ { \"name\": \"Warrior\", \"cost\": 16 }, { \"name\": \"Spearman\", \"cost\": 24, \"promotions\": [\"Shock I\", \"Drill I\"] } ] This file contains two unit objects, one for a warrior and one for a spearman. These objects have different attributes, in this case \"name\", \"cost\" and \"promotions\". All these attributes have a certain type, a String (text) for \"name\", an Integer for \"cost\" and a List of Strings for \"promotions\". There are different types of attributes: | type | notes | | --------- | ----- | | String | A word or sentence. Should be between double quotes (\") | | Integer | A number. Can be both positive or negative. Should not be between quotes | | Boolean | A value that can either be 'true' or 'false'. Should not be between quotes | | List of [type] | If multiple values could apply (such as with the promotions above), they should be put inside a list. Each element of the list should be written like a normal attribute, seperated by comma's, and enclosed between square braces. E.g.: [\"Shock I\", \"Shock II\"] or [1, 2, 3]. | | Object | The most complicated type of attribute. An object is comprised of multiple attributes, each of which again has a type. These attributes have a key (the part before the \":\") and a value (the part behind it). For an example, see below. | Example of a Buildings.json adding a new \"Cultural Library\" building which gives +50% science and +50% culture: [ { \"name\": \"Cultural Library\" \"percentStatBonus\" : {\"science\": 50, \"culture\": 50} } ] The keys in this example are \"science\" and \"culture\", and both have the value \"50\". In some sense you can see from these types that JSON files themselves are actually a list of objects, each describing a single building, unit or something else.","title":"General Overview of JSON files"},{"location":"wiki/JSON-files-for-mods/#information-on-json-files-used-in-the-game","text":"Many parts of Unciv are moddable, and for each there is a seperate json file. There is a json file for buildings, for units, for promotions units can have, for technologies, etc. The different new buildings or units you define can also have lots of different attributes, though not all are required. Below are tables documenting all the different attributes everything can have. Only the attributes which are noted to be 'required' must be provided. All others have a default value that will be used when it is omitted. The individual files are described on separate pages: Civilization-related JSON files Map-related JSON files Unit-related JSON files Miscellaneous JSON files","title":"Information on JSON files used in the game"},{"location":"wiki/Making-a-new-Civilization/","text":"Making a new Civilization So you want to add your favorite civilization? There are a few steps required, so we'll walk you through them! Fill in your Nation info Each civ has some basic information - what the civ name is, the leader's name, colors and city names. In addition, each civ has flavor text when declaring war, intoduction etc. All of these need to be filled in in Nations.json Get your Civ icon Each civ has an icon, like the wreath for Rome, for instant identification. All of these icons are white on a transparent background, and are 100x100 pixels - see icon considerations for details You'll need to put your icon in the NationIcons folder . Same as with the nation name and leader name, the unique ability should also be put in the Nations translation file for bonus points =) Congrats, your Civ is now fully playable! But apart from the flavor, they are boring gameplay-wise, so now we need to add unique abilities! Adding unique units Units in general are added in the Units.json file, with an icon in the UnitIcons folder. The icon must be 200x200 pixels, white on transparent background - see icon considerations for details Remember that these are unique units, so search for an existing unique unit to see how they replace their regular counterparts! Adding unique buildings Same as the units - info is in the Buildings.json file and icons in the BuildingIcons folder, same rules for the icons apply (200x200 pixels, icon considerations) Civ Unique Check out our list of uniques to see all the cool special effects you can add to your civilization! Icon considerations ALL icons must be legally acceptable, meaning they either come from from open sources or you act according to their licence (for Creative Commons, for instance, you have to specify the source and the creator). Icons directly from the base game belong to Firaxis, so I'm not sure we're legally allowed to use them - please use other sources! One source I use constantly is The Noun Project - everything there is Creative Commons or open, so they can all be used! Credits for icons should go in the Credits page","title":"Making a new Civilization"},{"location":"wiki/Making-a-new-Civilization/#making-a-new-civilization","text":"So you want to add your favorite civilization? There are a few steps required, so we'll walk you through them!","title":"Making a new Civilization"},{"location":"wiki/Making-a-new-Civilization/#fill-in-your-nation-info","text":"Each civ has some basic information - what the civ name is, the leader's name, colors and city names. In addition, each civ has flavor text when declaring war, intoduction etc. All of these need to be filled in in Nations.json","title":"Fill in your Nation info"},{"location":"wiki/Making-a-new-Civilization/#get-your-civ-icon","text":"Each civ has an icon, like the wreath for Rome, for instant identification. All of these icons are white on a transparent background, and are 100x100 pixels - see icon considerations for details You'll need to put your icon in the NationIcons folder . Same as with the nation name and leader name, the unique ability should also be put in the Nations translation file for bonus points =) Congrats, your Civ is now fully playable! But apart from the flavor, they are boring gameplay-wise, so now we need to add unique abilities!","title":"Get your Civ icon"},{"location":"wiki/Making-a-new-Civilization/#adding-unique-units","text":"Units in general are added in the Units.json file, with an icon in the UnitIcons folder. The icon must be 200x200 pixels, white on transparent background - see icon considerations for details Remember that these are unique units, so search for an existing unique unit to see how they replace their regular counterparts!","title":"Adding unique units"},{"location":"wiki/Making-a-new-Civilization/#adding-unique-buildings","text":"Same as the units - info is in the Buildings.json file and icons in the BuildingIcons folder, same rules for the icons apply (200x200 pixels, icon considerations)","title":"Adding unique buildings"},{"location":"wiki/Making-a-new-Civilization/#civ-unique","text":"Check out our list of uniques to see all the cool special effects you can add to your civilization!","title":"Civ Unique"},{"location":"wiki/Making-a-new-Civilization/#icon-considerations","text":"ALL icons must be legally acceptable, meaning they either come from from open sources or you act according to their licence (for Creative Commons, for instance, you have to specify the source and the creator). Icons directly from the base game belong to Firaxis, so I'm not sure we're legally allowed to use them - please use other sources! One source I use constantly is The Noun Project - everything there is Creative Commons or open, so they can all be used! Credits for icons should go in the Credits page","title":"Icon considerations"},{"location":"wiki/Map-related-JSON-files/","text":"Terrains.json TileResources.json TileImprovements.json Ruins.json Tileset-specific json Terrains.json This file lists the base terrains, terrain features and natural wonders that can appear on the map. Each terrain entry can have the following properties: | Attribute | Type | Optional? | Notes | |-----------|------|-----------|-------| | name | String | Required | | | type | Enum | Required | Land, Water, TerrainFeature, NaturalWonder | | occursOn | List | Default none | Only for terrain features and Natural Wonders: The baseTerrain it can be placed on | | turnsInto | String | Default none | Only for Natural Wonders: After placing the Natural Wonder its base terrain is changed to this | | weight | Integer | Default 10 | Only for Natural Wonders: relative weight it will be picked by the map generator | | | Float | Optional | Per-turn yield or bonus yield for the tile, see Stats | | overrideStats | Boolean | Default false | If on, a feature's yields replace any yield from underlying terrain instead of adding to it | | unbuildable | Boolean | Default false | If true, nothing can be built here - not even resource improvements | | impassable | Boolean | Default false | no unit can enter unless it has a special unique | | movementCost | Integer | Default 1 | base movement cost | | defenceBonus | Float | Default 0 | combat bonus for units being attacked here | | RGB | List Integer * 3 | Default 'Gold' | RGB color for 'Default' tileset display | | uniques | List | Default empty | List of effects, see here | | civilopediaText | List | Default empty | see civilopediaText chapter | Note that many Natural Wonders have hardcoded routines for their placement and are recognized by name (e.g. Great Barrier Reef being more than one tile). TileImprovements.json This file lists the improvements that can be constructed or created on a map tile by a unit (any unit having the appropriate unique). Note that improvements have two visual representations - icon and pixel graphic in the tileset. Omitting the icon results in a horribly ugly user interface, while omitting tileset graphics will just miss out on an optional visualization. If you provide a pixel graphic for FantasyHex, please be aware of the layering system and the ruleVariants in the tileset json. A single graphic may suffice if it has lots of transparency, as it will be drawn on top of all other terrain elements. Each improvement can have the following properties: | Attribute | Type | Optional? | Notes | |-----------|------|-----------|-------| | name | String | Required | | | terrainsCanBeFoundOn | List | Default empty | Terrains that allow this resource | | techRequired | String | Default none | The name of the technology required to build this improvement | | uniqueTo | String | Default none | The name of the nation this improvement is unique for | | | Float | Optional | Per-turn bonus yield for the tile, see Stats | | turnsToBuild | Integer | | Number of turns a worker spends building this (ignored for 'create' actions) | | uniques | List | Default empty | List of effects, see here | | shortcutKey | String | Default none | Keyboard binding. At the moment a single character (no function keys or Ctrl combinations) | | civilopediaText | List | Default empty | see civilopediaText chapter | Tiles with no terrains, but positive turns to build, can be built only when the tile has a resource that names this improvement or special uniques are used. (TODO: missing something?) Tiles with no terrains, and no turns to build, are like great improvements - they're placeable. That means a unit could exist with a 'Can create [this]' unique, and that the improvement will not show in a worker's improvement picker dialog. Removable Terrain features will need to be removed before building an improvement - unless the feature is named in terrainsCanBeFoundOn or the unique \"Does not need removal of [terrainFeature]\" is used (e.g. Camp allowed by resource). Special improvements: Road, Railroad, Remove *, Cancel improvement order, City ruins, City center, Barbarian encampment - these have special meanings hardcoded to their names. TileResources.json This file lists the resources that a map tile can have. Note the predefined resource types cannot be altered in json. Note also that resources have two visual representations - icon and pixel graphic in the tileset. Omitting the icon results in a horribly ugly user interface, while omitting tileset graphics will miss out on a visualization on the map. If you provide a pixel graphic for FantasyHex, please be aware of the layering system and the ruleVariants in the tileset json. A single graphic may suffice if it has lots of transparency, as it will be drawn on top of terrain and features but below an improvement - if the single improvement graphic exists at all. Each resource can have the following properties: | Attribute | Type | Optional? | Notes | |-----------|------|-----------|-------| | name | String | Required | | | resourceType | String | Default Bonus | Bonus, Luxury or Strategic | | terrainsCanBeFoundOn | List | Default empty | Terrains that allow this resource | | | Float | Optional | Per-turn bonus yield for the tile, see Stats , can be repeated | | improvement | String | Default empty | The improvement ( TileImprovements.json ) for this resource | | improvementStats | Object | Default empty | The additional yield when improved as sub-object with one or more Stats | | revealedBy | String | Default empty | The technology name required to see, work and improve this resource | | unique | String | Default empty | Effects, see here - at the moment only one unique may be added | | civilopediaText | List | Default empty | see civilopediaText chapter | Ruins.json Link to original This file contains the possible rewards ancient ruins give. It is not required, if omitted, the default file for the game is used, even in baseRuleSet mods. Each of the objects in the file represents a single reward you can get from ruins. It has the following properties: attribute Type optional or not notes name String required Name of the ruins. Never shown to the user, but they have to be distinct notification String required Notification added to the user when this reward is chosen. If omitted, an empty notification is shown. Some notifications may have parameters, refer to the table below. weight Integer (\u22650) defaults to 1 Weight this reward should have. Higher weights result in a higher chance of it being chosen* uniques List of Strings defaults to none [uniques]Uniques#one-time-effect) or uniques that will trigger when entering the ruins. If more than 1 unique is added, the notification will be shown multiple times due to a bug. excludedDifficulties List of Strings defaults to None A list of all difficulties on which this reward may not be awarded The exact algorithm for choosing a reward is the following: Create a list of all possible rewards, with rewards with a higher weight appearing multiple times. A reward with weight one will appear once, a reward with weight two will appear twice, etc. Shuffle this list Try give rewards starting from the top of the list. If any of the uniques of the rewards is valid in this context, reward it and stop trying more rewards. Notifications Some of the rewards ruins can give will have results that are not deterministic when writing it in the JSON, so creating a good notification for it would be impossible. An example for this would be the \"Gain [50]-[100] [Gold]\" unique, which will give a random amount of gold. For this reason, we allow some notifications to have parameters, in which values will be filled, such as \"You found [goldAmount] gold in the ruins!\". All the uniques which have this property can be found below. unique parameters Free [] found in the ruins The name of the unit will be filled in the notification, including unique units of the nation [] population in a random city The name of the city to which the population is added will be filled in the notification Gain []-[] [] The exact amount of the stat gained will be filled in the notification [] free random reasearchable Tech(s) from the [] The notification must have placeholders equal to the number of techs granted this way. Each of the names of these free techs will be filled in the notification Gain enough Faith for a Pantheon The amount of faith gained is filled in the notification Gain enough Faith for []% of a Great Prophet The amount of faith gained is filled in the notification Specific uniques A few uniques can be added to ancient ruin effects to modify when they can be earned. These are: - \"Only available after [amount] turns\" - \"Hidden when religion is disabled\" - \"Hidden after a great prophet has been earned\" Tileset-specific json A mod can define new Tilesets or add to existing ones, namely FantasyHex. There is one json file per Tileset, named same as the Tileset, and placed in a subfolder named \"TileSets\" relative to the other json files. This is called TileSetConfig and has the following structure: Attribute Type Optional? Notes useColorAsBaseTerrain Boolean Default true ? WIP unexploredTileColor Color Default Dark Gray {\"r\":0.25,\"g\":0.25,\"b\":0.25,\"a\":1} fogOfWarColor Color Default Black {\"r\":0,\"g\":0,\"b\":0,\"a\":1} ruleVariants List Default empty see below ruleVariants control substitutions when layering images for a tile, they are list looking like: \"ruleVariants\": { \"Grassland+Forest\": [\"Grassland\",\"GrasslandForest\"], \"Plains+Forest\": [\"Plains\",\"PlainsForest\"], \"Plains+Jungle\": [\"Plains\",\"PlainsJungle\"], ... } Each line means \"if the tile content is this... then combine the following png images\". The key part follows a specific order and must match in its entirety, meaning \"Plains+Forest\" is not valid for \"Plains+Forest+Deer\", and when it matches no other image layering is done except roads and units (I think - WIP ). When TileSetConfig's for the same Tileset are combined, for the first three properties the last mod wins, while ruleVariants are merged, meaning only an entry with the same key overwrites an earlier entry. Stats Terrains, features, resources and improvements may list yield statistics. They can be one of the following: - production, food, gold, science, culture, happiness, faith If an object carries general stats, any combination (or none) of these can be specified. For specialized stats, they might come as sub-object in a named field. Example: \"gold\": 2, \"improvement\": \"Quarry\", \"improvementStats\": {\"gold\": 1,\"production\": 1}, The values are usually integers, though the underlying code supports floating point. The effects are, however, insufficiently tested and therefore -so far- using fractional stats is unsupported. Go ahead and thoroughly test that in a mod and help out with feedback \ud83d\ude01.","title":"Map related JSON files"},{"location":"wiki/Map-related-JSON-files/#terrainsjson","text":"This file lists the base terrains, terrain features and natural wonders that can appear on the map. Each terrain entry can have the following properties: | Attribute | Type | Optional? | Notes | |-----------|------|-----------|-------| | name | String | Required | | | type | Enum | Required | Land, Water, TerrainFeature, NaturalWonder | | occursOn | List | Default none | Only for terrain features and Natural Wonders: The baseTerrain it can be placed on | | turnsInto | String | Default none | Only for Natural Wonders: After placing the Natural Wonder its base terrain is changed to this | | weight | Integer | Default 10 | Only for Natural Wonders: relative weight it will be picked by the map generator | | | Float | Optional | Per-turn yield or bonus yield for the tile, see Stats | | overrideStats | Boolean | Default false | If on, a feature's yields replace any yield from underlying terrain instead of adding to it | | unbuildable | Boolean | Default false | If true, nothing can be built here - not even resource improvements | | impassable | Boolean | Default false | no unit can enter unless it has a special unique | | movementCost | Integer | Default 1 | base movement cost | | defenceBonus | Float | Default 0 | combat bonus for units being attacked here | | RGB | List Integer * 3 | Default 'Gold' | RGB color for 'Default' tileset display | | uniques | List | Default empty | List of effects, see here | | civilopediaText | List | Default empty | see civilopediaText chapter | Note that many Natural Wonders have hardcoded routines for their placement and are recognized by name (e.g. Great Barrier Reef being more than one tile).","title":"Terrains.json"},{"location":"wiki/Map-related-JSON-files/#tileimprovementsjson","text":"This file lists the improvements that can be constructed or created on a map tile by a unit (any unit having the appropriate unique). Note that improvements have two visual representations - icon and pixel graphic in the tileset. Omitting the icon results in a horribly ugly user interface, while omitting tileset graphics will just miss out on an optional visualization. If you provide a pixel graphic for FantasyHex, please be aware of the layering system and the ruleVariants in the tileset json. A single graphic may suffice if it has lots of transparency, as it will be drawn on top of all other terrain elements. Each improvement can have the following properties: | Attribute | Type | Optional? | Notes | |-----------|------|-----------|-------| | name | String | Required | | | terrainsCanBeFoundOn | List | Default empty | Terrains that allow this resource | | techRequired | String | Default none | The name of the technology required to build this improvement | | uniqueTo | String | Default none | The name of the nation this improvement is unique for | | | Float | Optional | Per-turn bonus yield for the tile, see Stats | | turnsToBuild | Integer | | Number of turns a worker spends building this (ignored for 'create' actions) | | uniques | List | Default empty | List of effects, see here | | shortcutKey | String | Default none | Keyboard binding. At the moment a single character (no function keys or Ctrl combinations) | | civilopediaText | List | Default empty | see civilopediaText chapter | Tiles with no terrains, but positive turns to build, can be built only when the tile has a resource that names this improvement or special uniques are used. (TODO: missing something?) Tiles with no terrains, and no turns to build, are like great improvements - they're placeable. That means a unit could exist with a 'Can create [this]' unique, and that the improvement will not show in a worker's improvement picker dialog. Removable Terrain features will need to be removed before building an improvement - unless the feature is named in terrainsCanBeFoundOn or the unique \"Does not need removal of [terrainFeature]\" is used (e.g. Camp allowed by resource). Special improvements: Road, Railroad, Remove *, Cancel improvement order, City ruins, City center, Barbarian encampment - these have special meanings hardcoded to their names.","title":"TileImprovements.json"},{"location":"wiki/Map-related-JSON-files/#tileresourcesjson","text":"This file lists the resources that a map tile can have. Note the predefined resource types cannot be altered in json. Note also that resources have two visual representations - icon and pixel graphic in the tileset. Omitting the icon results in a horribly ugly user interface, while omitting tileset graphics will miss out on a visualization on the map. If you provide a pixel graphic for FantasyHex, please be aware of the layering system and the ruleVariants in the tileset json. A single graphic may suffice if it has lots of transparency, as it will be drawn on top of terrain and features but below an improvement - if the single improvement graphic exists at all. Each resource can have the following properties: | Attribute | Type | Optional? | Notes | |-----------|------|-----------|-------| | name | String | Required | | | resourceType | String | Default Bonus | Bonus, Luxury or Strategic | | terrainsCanBeFoundOn | List | Default empty | Terrains that allow this resource | | | Float | Optional | Per-turn bonus yield for the tile, see Stats , can be repeated | | improvement | String | Default empty | The improvement ( TileImprovements.json ) for this resource | | improvementStats | Object | Default empty | The additional yield when improved as sub-object with one or more Stats | | revealedBy | String | Default empty | The technology name required to see, work and improve this resource | | unique | String | Default empty | Effects, see here - at the moment only one unique may be added | | civilopediaText | List | Default empty | see civilopediaText chapter |","title":"TileResources.json"},{"location":"wiki/Map-related-JSON-files/#ruinsjson","text":"Link to original This file contains the possible rewards ancient ruins give. It is not required, if omitted, the default file for the game is used, even in baseRuleSet mods. Each of the objects in the file represents a single reward you can get from ruins. It has the following properties: attribute Type optional or not notes name String required Name of the ruins. Never shown to the user, but they have to be distinct notification String required Notification added to the user when this reward is chosen. If omitted, an empty notification is shown. Some notifications may have parameters, refer to the table below. weight Integer (\u22650) defaults to 1 Weight this reward should have. Higher weights result in a higher chance of it being chosen* uniques List of Strings defaults to none [uniques]Uniques#one-time-effect) or uniques that will trigger when entering the ruins. If more than 1 unique is added, the notification will be shown multiple times due to a bug. excludedDifficulties List of Strings defaults to None A list of all difficulties on which this reward may not be awarded The exact algorithm for choosing a reward is the following: Create a list of all possible rewards, with rewards with a higher weight appearing multiple times. A reward with weight one will appear once, a reward with weight two will appear twice, etc. Shuffle this list Try give rewards starting from the top of the list. If any of the uniques of the rewards is valid in this context, reward it and stop trying more rewards.","title":"Ruins.json"},{"location":"wiki/Map-related-JSON-files/#notifications","text":"Some of the rewards ruins can give will have results that are not deterministic when writing it in the JSON, so creating a good notification for it would be impossible. An example for this would be the \"Gain [50]-[100] [Gold]\" unique, which will give a random amount of gold. For this reason, we allow some notifications to have parameters, in which values will be filled, such as \"You found [goldAmount] gold in the ruins!\". All the uniques which have this property can be found below. unique parameters Free [] found in the ruins The name of the unit will be filled in the notification, including unique units of the nation [] population in a random city The name of the city to which the population is added will be filled in the notification Gain []-[] [] The exact amount of the stat gained will be filled in the notification [] free random reasearchable Tech(s) from the [] The notification must have placeholders equal to the number of techs granted this way. Each of the names of these free techs will be filled in the notification Gain enough Faith for a Pantheon The amount of faith gained is filled in the notification Gain enough Faith for []% of a Great Prophet The amount of faith gained is filled in the notification","title":"Notifications"},{"location":"wiki/Map-related-JSON-files/#specific-uniques","text":"A few uniques can be added to ancient ruin effects to modify when they can be earned. These are: - \"Only available after [amount] turns\" - \"Hidden when religion is disabled\" - \"Hidden after a great prophet has been earned\"","title":"Specific uniques"},{"location":"wiki/Map-related-JSON-files/#tileset-specific-json","text":"A mod can define new Tilesets or add to existing ones, namely FantasyHex. There is one json file per Tileset, named same as the Tileset, and placed in a subfolder named \"TileSets\" relative to the other json files. This is called TileSetConfig and has the following structure: Attribute Type Optional? Notes useColorAsBaseTerrain Boolean Default true ? WIP unexploredTileColor Color Default Dark Gray {\"r\":0.25,\"g\":0.25,\"b\":0.25,\"a\":1} fogOfWarColor Color Default Black {\"r\":0,\"g\":0,\"b\":0,\"a\":1} ruleVariants List Default empty see below ruleVariants control substitutions when layering images for a tile, they are list looking like: \"ruleVariants\": { \"Grassland+Forest\": [\"Grassland\",\"GrasslandForest\"], \"Plains+Forest\": [\"Plains\",\"PlainsForest\"], \"Plains+Jungle\": [\"Plains\",\"PlainsJungle\"], ... } Each line means \"if the tile content is this... then combine the following png images\". The key part follows a specific order and must match in its entirety, meaning \"Plains+Forest\" is not valid for \"Plains+Forest+Deer\", and when it matches no other image layering is done except roads and units (I think - WIP ). When TileSetConfig's for the same Tileset are combined, for the first three properties the last mod wins, while ruleVariants are merged, meaning only an entry with the same key overwrites an earlier entry.","title":"Tileset-specific json"},{"location":"wiki/Map-related-JSON-files/#stats","text":"Terrains, features, resources and improvements may list yield statistics. They can be one of the following: - production, food, gold, science, culture, happiness, faith If an object carries general stats, any combination (or none) of these can be specified. For specialized stats, they might come as sub-object in a named field. Example: \"gold\": 2, \"improvement\": \"Quarry\", \"improvementStats\": {\"gold\": 1,\"production\": 1}, The values are usually integers, though the underlying code supports floating point. The effects are, however, insufficiently tested and therefore -so far- using fractional stats is unsupported. Go ahead and thoroughly test that in a mod and help out with feedback \ud83d\ude01.","title":"Stats"},{"location":"wiki/Miscellaneous-JSON-files/","text":"Difficulties.json Eras.json ModOptions.json Generic Civilopedia Text Difficulties.json Link to original This file defines the difficulty levels a player can choose when starting a new game. Each difficulty level can have the following attributes: | Attribute | Type | Mandatory | Notes | | --------- | ---- | ------- | ----- | | name | String | Required | Name of the difficulty level | | baseHappiness | Integer | Default 0 | | extraHappinessPerLuxury | Float | Default 0 | | researchCostModifier | Float | Default 1 | | unitCostModifier | Float | Default 1 | | buildingCostModifier | Float | Default 1 | | policyCostModifier | Float | Default 1 | | unhappinessModifier | Float | Default 1 | | barbarianBonus | Float | Default 0 | | playerBonusStartingUnits | List of Units | Default empty | Can also be 'Era Starting Unit', maps to startingMilitaryUnit of the Eras file. All other units must be in Units.json ] | | aiCityGrowthModifier | Float | Default 1 | | aiUnitCostModifier | Float | Default 1 | | aiBuildingCostModifier | Float | Default 1 | | aiWonderCostModifier | Float | Default 1 | | aiBuildingMaintenanceModifier | Float | Default 1 | | aiUnitMaintenanceModifier | Float | Default 1 | | aiFreeTechs | List of Techs | Default empty | | aiMajorCivBonusStartingUnits | List of Units | Default empty | See above | | aiCityStateBonusStartingUnits | List of Units | Default empty | See above | | aiUnhappinessModifier | Float | Default 1 | | aisExchangeTechs | Boolean | | Unimplemented | | turnBarbariansCanEnterPlayerTiles | Integer | Default 0 | | clearBarbarianCampReward | Integer | Default 25 | Eras.json Link to original This file should contain all the era's you want to use in your mod. Each era can have the following attributes: | attribute | Type | optional or not | notes | | --------- | ---- | --------------- | ----- | | name | String | required | Name of the era | | researchAgreementCost | Integer (\u22650) | defaults to 300 | Cost of research agreements were the most technologically advanced civ is in this era | | iconRGB | List of 3 Integers | defaults to [255,255,255] | RGB color that icons for technologies of this era should have in the Tech screen | | unitBaseBuyCost | Integer (\u22650) | defaults to 200 | Base cost of buying units with Faith, Food, Science or Culture when no other cost is provided | | startingSettlerCount | Integer (\u22650) | defaults to 1 | Amount of settler units that should be spawned when starting a game in this era | | startingSettlerUnit | String | defaults to \"Settler\" | Name of the unit that should be used for the previous field. Must be in Units.json | | startingWokerCount | Integer (\u22650) | defaults to 0 | Amount of worker units that should be spawned when starting a game in this era | | startingWorkerUnit | String | defaults to \"Worker\" | Name of the unit that should be used for the previous field. Must be in Units.json | | startingMilitaryUnitCount | Integer (\u22650) | defaults to 1 | Amount of military units that should be spawned when starting a game in this era | | startingMilitaryUnit | String | defaults to \"Warrior\" | Name of the unit that should be used for the previous field. Must be in Units.json | | startingGold | Integer (\u22650) | defaults to 0 | Amount of gold each civ should receive when starting a game in this era | | startingCulture | Integer (\u22650) | defaults to 0 | Amount of culture each civ should receive when starting a game in this era | | settlerPopulation | Integer (>0) | defaults to 1 | Default amount of population each city should have when settled when starting a game in this era | | settlerBuildings | List of Strings | defaults to none | Buildings that should automatically be built whenever a city is settled when starting a game in this era | | startingObsoleteWonders | List of Strings | defaults to none | Wonders (and technically buildings) that should be impossible to built when starting a game in this era. Used in the base game to remove all wonders older than 2 era's | ModOptions.json This file is a little different: - Does not exist in Vanilla ruleset - Is entirely optional but will be created after downloading a mod The file can have the following attributes, including the values Unciv sets (no point in a mod author setting those): | Attribute | Type | Defaults | Notes | |-----------|------|-----------|-------| | isBaseRuleset | Boolean | false | Differentiates mods that change the vanilla ruleset or replace it | | maxXPfromBarbarians | Integer | 30 | ...as the name says... | | uniques | List | empty | Mod-wide specials, see here | | techsToRemove | List | empty | List of Technologies to remove (isBaseRuleset=false only) | | buildingsToRemove | List | empty | List of Buildings or Wonders to remove (isBaseRuleset=false only) | | unitsToRemove | List | empty | List of Units to remove (isBaseRuleset=false only) | | nationsToRemove | List | empty | List of Nations to remove (isBaseRuleset=false only) | | lastUpdated | String | empty | Set automatically after download - Last repository update, not necessarily last content change | | modUrl | String | empty | Set automatically after download - URL of repository | | author | String | empty | Set automatically after download - Owner of repository | | modSize | Integer | empty | Set automatically after download - kB in entire repository, not sum of default branch files | Civilopedia text Any 'thing' defined in json and listed in the Civilopedia can supply extra text, specifically for the Civilopedia. This can be used to explain special considerations better when the automatically generated display is insufficient, or for 'flavour', background stories and the like. Such text can be formatted and linked to other Civilopedia entries, within limits. An example of the format is: \"civilopediaText\": [ {\"text\":\"Ancient ruins provide a one-time random bonus when explored\"}, {\"separator\":true}, {\"text\":\"This line is red and links to the Scout including icons\", \"link\":\"Unit/Scout\", \"color\":\"red\"}, {\"text\":\"A big fat header sporting a golden star\", \"header\":1, \"starred\":true, \"color\":\"#ffeb7f\"}, ], List of attributes - note not all combinations are valid: |attribute|type|description| |---------|----|-----------| | text |String|Text to display.| | link |String|Create link and icon, format: Category/Name or external link ('http://','https://','mailto:').| | icon |String|Show icon without linking, format: Category/Name.| | extraImage |String|Display an Image instead of text. Can be a path found in a texture atlas or or the name of a png or jpg in the ExtraImages folder.| | imageSize |Float|Width in world units of the [extraImage], height is calculated preserving aspect ratio. Defaults to available width.| | header |Integer|Header level. 1 means double text size and decreases from there.| | size |Integer|Text size, default is 18. Use size or header but not both.| | indent |Integer|Indent level. 0 means text will follow icons, 1 aligns to the right of all icons, each further step is 30 units.| | padding |Float|Vertical padding between rows, defaults to 5 units.| | color |String|Sets text color, accepts names or 6/3-digit web colors (e.g. #FFA040).| | separator |Boolean|Renders a separator line instead of text. Can be combined only with color and size (line width, default 2).| | starred |Boolean|Decorates text with a star icon - if set, it receives the color instead of the text.| | centered |Boolean|Centers the line (and turns off automatic wrap).| The lines from json will 'surround' the automatically generated lines such that the latter are inserted just above the first json line carrying a link, if any. If no json lines have links, they will be inserted between the automatic title and the automatic info. This method may, however, change in the future.","title":"Miscellaneous JSON files"},{"location":"wiki/Miscellaneous-JSON-files/#difficultiesjson","text":"Link to original This file defines the difficulty levels a player can choose when starting a new game. Each difficulty level can have the following attributes: | Attribute | Type | Mandatory | Notes | | --------- | ---- | ------- | ----- | | name | String | Required | Name of the difficulty level | | baseHappiness | Integer | Default 0 | | extraHappinessPerLuxury | Float | Default 0 | | researchCostModifier | Float | Default 1 | | unitCostModifier | Float | Default 1 | | buildingCostModifier | Float | Default 1 | | policyCostModifier | Float | Default 1 | | unhappinessModifier | Float | Default 1 | | barbarianBonus | Float | Default 0 | | playerBonusStartingUnits | List of Units | Default empty | Can also be 'Era Starting Unit', maps to startingMilitaryUnit of the Eras file. All other units must be in Units.json ] | | aiCityGrowthModifier | Float | Default 1 | | aiUnitCostModifier | Float | Default 1 | | aiBuildingCostModifier | Float | Default 1 | | aiWonderCostModifier | Float | Default 1 | | aiBuildingMaintenanceModifier | Float | Default 1 | | aiUnitMaintenanceModifier | Float | Default 1 | | aiFreeTechs | List of Techs | Default empty | | aiMajorCivBonusStartingUnits | List of Units | Default empty | See above | | aiCityStateBonusStartingUnits | List of Units | Default empty | See above | | aiUnhappinessModifier | Float | Default 1 | | aisExchangeTechs | Boolean | | Unimplemented | | turnBarbariansCanEnterPlayerTiles | Integer | Default 0 | | clearBarbarianCampReward | Integer | Default 25 |","title":"Difficulties.json"},{"location":"wiki/Miscellaneous-JSON-files/#erasjson","text":"Link to original This file should contain all the era's you want to use in your mod. Each era can have the following attributes: | attribute | Type | optional or not | notes | | --------- | ---- | --------------- | ----- | | name | String | required | Name of the era | | researchAgreementCost | Integer (\u22650) | defaults to 300 | Cost of research agreements were the most technologically advanced civ is in this era | | iconRGB | List of 3 Integers | defaults to [255,255,255] | RGB color that icons for technologies of this era should have in the Tech screen | | unitBaseBuyCost | Integer (\u22650) | defaults to 200 | Base cost of buying units with Faith, Food, Science or Culture when no other cost is provided | | startingSettlerCount | Integer (\u22650) | defaults to 1 | Amount of settler units that should be spawned when starting a game in this era | | startingSettlerUnit | String | defaults to \"Settler\" | Name of the unit that should be used for the previous field. Must be in Units.json | | startingWokerCount | Integer (\u22650) | defaults to 0 | Amount of worker units that should be spawned when starting a game in this era | | startingWorkerUnit | String | defaults to \"Worker\" | Name of the unit that should be used for the previous field. Must be in Units.json | | startingMilitaryUnitCount | Integer (\u22650) | defaults to 1 | Amount of military units that should be spawned when starting a game in this era | | startingMilitaryUnit | String | defaults to \"Warrior\" | Name of the unit that should be used for the previous field. Must be in Units.json | | startingGold | Integer (\u22650) | defaults to 0 | Amount of gold each civ should receive when starting a game in this era | | startingCulture | Integer (\u22650) | defaults to 0 | Amount of culture each civ should receive when starting a game in this era | | settlerPopulation | Integer (>0) | defaults to 1 | Default amount of population each city should have when settled when starting a game in this era | | settlerBuildings | List of Strings | defaults to none | Buildings that should automatically be built whenever a city is settled when starting a game in this era | | startingObsoleteWonders | List of Strings | defaults to none | Wonders (and technically buildings) that should be impossible to built when starting a game in this era. Used in the base game to remove all wonders older than 2 era's |","title":"Eras.json"},{"location":"wiki/Miscellaneous-JSON-files/#modoptionsjson","text":"This file is a little different: - Does not exist in Vanilla ruleset - Is entirely optional but will be created after downloading a mod The file can have the following attributes, including the values Unciv sets (no point in a mod author setting those): | Attribute | Type | Defaults | Notes | |-----------|------|-----------|-------| | isBaseRuleset | Boolean | false | Differentiates mods that change the vanilla ruleset or replace it | | maxXPfromBarbarians | Integer | 30 | ...as the name says... | | uniques | List | empty | Mod-wide specials, see here | | techsToRemove | List | empty | List of Technologies to remove (isBaseRuleset=false only) | | buildingsToRemove | List | empty | List of Buildings or Wonders to remove (isBaseRuleset=false only) | | unitsToRemove | List | empty | List of Units to remove (isBaseRuleset=false only) | | nationsToRemove | List | empty | List of Nations to remove (isBaseRuleset=false only) | | lastUpdated | String | empty | Set automatically after download - Last repository update, not necessarily last content change | | modUrl | String | empty | Set automatically after download - URL of repository | | author | String | empty | Set automatically after download - Owner of repository | | modSize | Integer | empty | Set automatically after download - kB in entire repository, not sum of default branch files |","title":"ModOptions.json"},{"location":"wiki/Miscellaneous-JSON-files/#civilopedia-text","text":"Any 'thing' defined in json and listed in the Civilopedia can supply extra text, specifically for the Civilopedia. This can be used to explain special considerations better when the automatically generated display is insufficient, or for 'flavour', background stories and the like. Such text can be formatted and linked to other Civilopedia entries, within limits. An example of the format is: \"civilopediaText\": [ {\"text\":\"Ancient ruins provide a one-time random bonus when explored\"}, {\"separator\":true}, {\"text\":\"This line is red and links to the Scout including icons\", \"link\":\"Unit/Scout\", \"color\":\"red\"}, {\"text\":\"A big fat header sporting a golden star\", \"header\":1, \"starred\":true, \"color\":\"#ffeb7f\"}, ], List of attributes - note not all combinations are valid: |attribute|type|description| |---------|----|-----------| | text |String|Text to display.| | link |String|Create link and icon, format: Category/Name or external link ('http://','https://','mailto:').| | icon |String|Show icon without linking, format: Category/Name.| | extraImage |String|Display an Image instead of text. Can be a path found in a texture atlas or or the name of a png or jpg in the ExtraImages folder.| | imageSize |Float|Width in world units of the [extraImage], height is calculated preserving aspect ratio. Defaults to available width.| | header |Integer|Header level. 1 means double text size and decreases from there.| | size |Integer|Text size, default is 18. Use size or header but not both.| | indent |Integer|Indent level. 0 means text will follow icons, 1 aligns to the right of all icons, each further step is 30 units.| | padding |Float|Vertical padding between rows, defaults to 5 units.| | color |String|Sets text color, accepts names or 6/3-digit web colors (e.g. #FFA040).| | separator |Boolean|Renders a separator line instead of text. Can be combined only with color and size (line width, default 2).| | starred |Boolean|Decorates text with a star icon - if set, it receives the color instead of the text.| | centered |Boolean|Centers the line (and turns off automatic wrap).| The lines from json will 'surround' the automatically generated lines such that the latter are inserted just above the first json line carrying a link, if any. If no json lines have links, they will be inserted between the automatic title and the automatic info. This method may, however, change in the future.","title":"Civilopedia text"},{"location":"wiki/Mods/","text":"What's this about? Everyone has that thing they wish could be in the game. Unfortunately, the game only understands code, so mods are our way to give a degree of freedom to those of us who don't code. Mods can add, replace and remove basic game definitions, such as units, nations, buildings, improvements, resources and terrains. Games loaded with these mods will function according to the mod definition. The game only knows how to recognize existing definitions, so you can't add new unique abilities to nations/units/buildings/etc, only play around with existing ones There are two kinds of mods: Extension mods - these add new nations/units/buildings/resources to a base ruleset - can be either to the default ruleset, or to a base ruleset mod. Easy to do and probably the better place to get started. Base Ruleset mods - these replace the entire existing ruleset - tech tree, units, policies, nations etc - to give an entirely different experience than the base game. These generally require quite a bit of work, but give a whole new experience, and so are the most popular. Creating and editing mods from your phone is NOT RECOMMENDED - it's much easier using a desktop device! Audiovisual Mods I addition to changing the rules - or even without doing so, mods can override existing graphics or sounds, or add music tracks. The game also has the ability to display graphics that are not included in the base game at all, such as leader portrait or wonder splash images, that must be provided by mods. For details, see Audiovisual Mods . Custom tilesets are closely related, see Creating a custom tileset . Such mods are candidates for the \"Permanent audiovisual mod\" switch available on the Mod Management Screen. Note that this feature includes graphics or sounds from the selected mod in all games, even those started before installing the mod. In case of a mod bringing both changed rules and audiovisuals, the 'permanent' feature will include only the media on all games, to use the rules you will still need to select the mod for a new game. Mod names Mods need to conform to github repo naming rules, but best stay simple and use only letters, digits, and dashes - . Dashes are automatically converted to spaces for display and use within Unciv. Many punctuation or extended unicode characters might work, but at best potential users won't find them attractive, at worst we'll refuse support when you run into problems :smiling_imp: Mod components Mods are located in a /mods directory, on Desktop that should be next to your .jar file. Mods typically have 2 subfolders: - jsons - here you should put files that alter the data of game objects, the order of the files is as in the base json files . More information on these can be found here - Images - here you should put game images, as in the base image files . Please read the atlas chapter for important details. In order to remove objects from the game, you'll need to create a ModOptions file in the /jsons subfolder - there's an example here In a base ruleset mod, ALL the original objects are removed - this is done by adding a \"isBaseRuleset\":true configuration to your modOptions file, like so For an example, you can refer to the example mod - just download the Example-Aliens-Mod and put it in a /mods folder next to the jar, run Unciv, start a new game, and you'll be able to enable the mod, which will allow to you pick Aliens as a playable civilization! If you want to add a new civilization as a mod, you should check out the Civ making instructions to see what's required, or see the example Aliens mod =) More on Images and the texture atlas Images are combined (at runtime) into texture images with an 'atlas', so if you see \"game.atlas\" and \"game.png\" files being generated, now you know what for. Most mods will need only one pair of those, the base game has around four. When the game runs from a packaged distribution (android, jar), the texture+atlas files alone are relevant, so you need to include them in your repository and keep them up to date. Actually omitting the original images would work for these uses, but we still recommend including them, so developers running from source can access them. If your mod has lots of images (or large ones), the textures might 'spill' into additional texture \".png\" files - 2048x2048 is the limit for a single texture pack. This is not good for performance, which is why the base game controls which kinds of images go together into one texture(+atlas). This works for mods, too: Create not only one Images folder, but several, the additional ones named \"Images.xyz\", where xyz will become the filename of the additional texture file (So don't use both Images and Images.game - those will clash). Look at the Unciv base game to get a better idea how that works. To minimize texture swaps, try to group them by the situation where in the game they are needed. You can distibute by folder, but having the same subfolders under several \"Images.xyz\" and distributing the images between them will also work. Adding maps to mods You can also add maps to mods, so they'll be available to players who download your mod. A mod can also be maps-only, if all you want to do is share your maps. When you've finished making your map in the Map Editor, save it, and it will be in the /maps folder of your game. Copy it to a /maps folder in your mod , and you're done! Getting your mod out there In order to make your mod downloadable by anyone, you need to create a Github repository (instructions here ) The Images and jsons folders need to be in the root directory of the repo - see here for example. You can then manually download the mod from within the Mod Manager in Unciv: From Unciv's main screen, click \"Mods\" Click \"Download mod from URL\", and enter the location of your Github page The game will automatically download and extract your mod, and it'll be ready to use! Once you've tested that your mod CAN be downloaded, and that it works well once downloaded, you're ready for the final stage - GETTING IT TO THE USERS AUTOMATICALLY. In order to do this, all you need to do is: Go to your Github page Click the gear icon next to the About (top-right part of the page) In 'Topics', add \"unciv-mod\" When you open your app, it will query Github's list of repos with that topic , and now YOUR repo will appear there! I have the mod, now what? The primary use of mods is to add them when starting a new game, or configuring a map. This will mean that both the ruleset of the mod, and the images, will be in use for that specific game/map. For mods which are primarily visual or audio, there is a second use - through the mod manager, you can enable them as permanent audiovisual mods . This means that the images, sounds (or upcoming: music) from the mod will replace the original media everywhere in the game. Mod location for manual loading of mods In general, you should never be manually-loading your mods - not only is this clunky, it's also more error-prone. Unless you have a very specific use-case, you probably shouldn't be doing this. In Android, they should go into the Android/data/com.unciv.app/files/mods directory. In Chromebook, go to \"Play files\", should be on the sidebar on the left side of the window under \"My files\". Click the 3 vertical dots on the top right-hand corner of the window below the \"X\". If the option \"Show all Play folders\" does not have a check next to it click it. You should see some new files that appear on your screen. Now navigate to Android/data/com.unciv.app/files/mods When loading a mod, it needs to be in its own folder in /mods - this is how you will work when you're editing your mod. Other Existing mods can be found here ! A list of uniques and how to use them can be found here ! Some images don't exist at all in the base game, but can be added in mods. For more info, see Audiovisual Mods .","title":"Mods"},{"location":"wiki/Mods/#whats-this-about","text":"Everyone has that thing they wish could be in the game. Unfortunately, the game only understands code, so mods are our way to give a degree of freedom to those of us who don't code. Mods can add, replace and remove basic game definitions, such as units, nations, buildings, improvements, resources and terrains. Games loaded with these mods will function according to the mod definition. The game only knows how to recognize existing definitions, so you can't add new unique abilities to nations/units/buildings/etc, only play around with existing ones There are two kinds of mods: Extension mods - these add new nations/units/buildings/resources to a base ruleset - can be either to the default ruleset, or to a base ruleset mod. Easy to do and probably the better place to get started. Base Ruleset mods - these replace the entire existing ruleset - tech tree, units, policies, nations etc - to give an entirely different experience than the base game. These generally require quite a bit of work, but give a whole new experience, and so are the most popular. Creating and editing mods from your phone is NOT RECOMMENDED - it's much easier using a desktop device!","title":"What's this about?"},{"location":"wiki/Mods/#audiovisual-mods","text":"I addition to changing the rules - or even without doing so, mods can override existing graphics or sounds, or add music tracks. The game also has the ability to display graphics that are not included in the base game at all, such as leader portrait or wonder splash images, that must be provided by mods. For details, see Audiovisual Mods . Custom tilesets are closely related, see Creating a custom tileset . Such mods are candidates for the \"Permanent audiovisual mod\" switch available on the Mod Management Screen. Note that this feature includes graphics or sounds from the selected mod in all games, even those started before installing the mod. In case of a mod bringing both changed rules and audiovisuals, the 'permanent' feature will include only the media on all games, to use the rules you will still need to select the mod for a new game.","title":"Audiovisual Mods"},{"location":"wiki/Mods/#mod-names","text":"Mods need to conform to github repo naming rules, but best stay simple and use only letters, digits, and dashes - . Dashes are automatically converted to spaces for display and use within Unciv. Many punctuation or extended unicode characters might work, but at best potential users won't find them attractive, at worst we'll refuse support when you run into problems :smiling_imp:","title":"Mod names"},{"location":"wiki/Mods/#mod-components","text":"Mods are located in a /mods directory, on Desktop that should be next to your .jar file. Mods typically have 2 subfolders: - jsons - here you should put files that alter the data of game objects, the order of the files is as in the base json files . More information on these can be found here - Images - here you should put game images, as in the base image files . Please read the atlas chapter for important details. In order to remove objects from the game, you'll need to create a ModOptions file in the /jsons subfolder - there's an example here In a base ruleset mod, ALL the original objects are removed - this is done by adding a \"isBaseRuleset\":true configuration to your modOptions file, like so For an example, you can refer to the example mod - just download the Example-Aliens-Mod and put it in a /mods folder next to the jar, run Unciv, start a new game, and you'll be able to enable the mod, which will allow to you pick Aliens as a playable civilization! If you want to add a new civilization as a mod, you should check out the Civ making instructions to see what's required, or see the example Aliens mod =)","title":"Mod components"},{"location":"wiki/Mods/#more-on-images-and-the-texture-atlas","text":"Images are combined (at runtime) into texture images with an 'atlas', so if you see \"game.atlas\" and \"game.png\" files being generated, now you know what for. Most mods will need only one pair of those, the base game has around four. When the game runs from a packaged distribution (android, jar), the texture+atlas files alone are relevant, so you need to include them in your repository and keep them up to date. Actually omitting the original images would work for these uses, but we still recommend including them, so developers running from source can access them. If your mod has lots of images (or large ones), the textures might 'spill' into additional texture \".png\" files - 2048x2048 is the limit for a single texture pack. This is not good for performance, which is why the base game controls which kinds of images go together into one texture(+atlas). This works for mods, too: Create not only one Images folder, but several, the additional ones named \"Images.xyz\", where xyz will become the filename of the additional texture file (So don't use both Images and Images.game - those will clash). Look at the Unciv base game to get a better idea how that works. To minimize texture swaps, try to group them by the situation where in the game they are needed. You can distibute by folder, but having the same subfolders under several \"Images.xyz\" and distributing the images between them will also work.","title":"More on Images and the texture atlas"},{"location":"wiki/Mods/#adding-maps-to-mods","text":"You can also add maps to mods, so they'll be available to players who download your mod. A mod can also be maps-only, if all you want to do is share your maps. When you've finished making your map in the Map Editor, save it, and it will be in the /maps folder of your game. Copy it to a /maps folder in your mod , and you're done!","title":"Adding maps to mods"},{"location":"wiki/Mods/#getting-your-mod-out-there","text":"In order to make your mod downloadable by anyone, you need to create a Github repository (instructions here ) The Images and jsons folders need to be in the root directory of the repo - see here for example. You can then manually download the mod from within the Mod Manager in Unciv: From Unciv's main screen, click \"Mods\" Click \"Download mod from URL\", and enter the location of your Github page The game will automatically download and extract your mod, and it'll be ready to use! Once you've tested that your mod CAN be downloaded, and that it works well once downloaded, you're ready for the final stage - GETTING IT TO THE USERS AUTOMATICALLY. In order to do this, all you need to do is: Go to your Github page Click the gear icon next to the About (top-right part of the page) In 'Topics', add \"unciv-mod\" When you open your app, it will query Github's list of repos with that topic , and now YOUR repo will appear there!","title":"Getting your mod out there"},{"location":"wiki/Mods/#i-have-the-mod-now-what","text":"The primary use of mods is to add them when starting a new game, or configuring a map. This will mean that both the ruleset of the mod, and the images, will be in use for that specific game/map. For mods which are primarily visual or audio, there is a second use - through the mod manager, you can enable them as permanent audiovisual mods . This means that the images, sounds (or upcoming: music) from the mod will replace the original media everywhere in the game.","title":"I have the mod, now what?"},{"location":"wiki/Mods/#mod-location-for-manual-loading-of-mods","text":"In general, you should never be manually-loading your mods - not only is this clunky, it's also more error-prone. Unless you have a very specific use-case, you probably shouldn't be doing this. In Android, they should go into the Android/data/com.unciv.app/files/mods directory. In Chromebook, go to \"Play files\", should be on the sidebar on the left side of the window under \"My files\". Click the 3 vertical dots on the top right-hand corner of the window below the \"X\". If the option \"Show all Play folders\" does not have a check next to it click it. You should see some new files that appear on your screen. Now navigate to Android/data/com.unciv.app/files/mods When loading a mod, it needs to be in its own folder in /mods - this is how you will work when you're editing your mod.","title":"Mod location for manual loading of mods"},{"location":"wiki/Mods/#other","text":"Existing mods can be found here ! A list of uniques and how to use them can be found here ! Some images don't exist at all in the base game, but can be added in mods. For more info, see Audiovisual Mods .","title":"Other"},{"location":"wiki/Project-structure-and-major-classes/","text":"Project structure Since LibGDX, and therefore Unciv, are built for multi-platform support, the project structure is built accordingly. 99% of the code is in the Core project, which contains all the platform-independant code. The Desktop and Android folders contain platform-specific things, and the Android folder also contains the game Images and the all-important Assets, which are required for running from Desktop as well, so we bundle them up into the .jar file when releasing. The Test folder contains tests that can be run manually via gradle with ./gradlew tests:test , and are run automatically by Travis for every push. Translations Before we get to the Classes, a word on Languages. Unciv is playable in several handfuls of languages, and there's magic to support that. Whenever you include a new string in code you will need to give it a quick evaluation - will users see it, and if so, what do I need to do to support its translations. Sometimes you may not need to do anything, sometimes you will add a line to the translation templates , and sometimes you will adapt the string formatting to support the translations. For details, see the 'Translation generation - for developers' chapter . Major classes Civ, and therefore Unciv, is a game with endless interconnectivity - everything affects everything else. In order to have some semblance of order, we'll go over the main classes in the order in which they are serialized. So yes, you can - for instance - get the center tile of a city, a TileInfo, directly from CityInfo. But delving into all the connections would only harm the point of this overview, that's what the actual code is for ;) The Game State: GameInfo CivilizationInfo CityInfo TileMap TileInfo MapUnit RuleSet (unique in that it is not part of the game state) The UI: MainMenuScreen NewGameScreen WorldScreen CityScreen MapEditorScreen Picker Screens - TechPickerScreen, PolicyPickerScreen, ImprovementPickerScreen, PromotionPickerScreen Game State The Game - GameInfo First off, let's clarify: When we say \"The Game\", we mean the state of the game (what turn it is, who the players are, what each one has etc) and not the UI of the game. That is, The Game is the currently played game, not Unciv . The game contains three major parts: The list of the players, or civilizations - List The map upon which the game is played - TileMap The ruleset by which the game is played - RuleSet . This includes what technologies, buildings, units etc. are available, and IS NOT serialized and deserialized, but comes straight from the game files - more on that later. Parameters unique to this game - difficulty, game speed, victory conditions, etc. When we save the game, or load the game, we're actually serializing and deserializing this class, which means that the this class is the root of the entire game state. Most objects in the \"state tree\" have a transient reference to their parent, meaning the tree can be traversed in-code in all directions, and frequently is. A Civilization - CivilizationInfo This represents one of the players of the game, and NOT a specific nation - meaning, not France, but rather \"Player X who is France in this game\". In another game, there will be another France. As one of the focal points of the game, it contains a lot of important information, the most important of which are: The list of cities the civilization has - List Which nation this is - references a certain Nation (part of the ruleset) Various Managers for the different aspects of the civilization - PolicyManager , GoldenAgeManager , GreatPersonManager , TechManager , VictoryManager , DiplomacyManager A City - CityInfo This contains the information about a specific city. Beyond basic information like name, location on map etc, the most important classes it contains are: Calculating the yield of the city - CityStats Managers for the various aspects - PopulationManager , CityConstructions , CityExpansionManager The tiles controlled and worked by the city - only their locations are permanently saved in the CityInfo, the actual information is in the TileInfo in the TileMap The map - TileMap This contains mostly helper functions and acts as a wrapper for the list of tiles it contains A tile - TileInfo Each tile is comprised of several layers, and so has information for each. Tiles have, primarily: - A base terrain - Grassland, Hills, Desert etc. References a certain Terrain (part of the ruleset) - An optional terrain feature - Forest, Jungle, Oasis etc. References a certain Terrain (part of the ruleset) - An optional resource - Iron, Dye, Wheat etc. References a certain TileResource (part of the ruleset) - An improvement built on the tile, if any. References a certain TileImprovement (part of the ruleset) - The units that are currently in the tile - MapUnit A unit on the map - MapUnit Unlike buildings, Unit in Unciv has two meanings. One is a Type of unit (like Spearman), and one is a specific instance of a unit (say, a Babylonian Spearman, at a certain position, with X health). MapUnit is a specific instance of a unit, whereas BaseUnit is the type of unit. Main information: - A name - references a specific BaseUnit - Health and Movement - Promotion status - UnitPromotions Ruleset So far so good - but what of everything that makes Civ, Civ? The units, the buildings, the nations, the improvements etc? Since these things remain the same for every game, these are not saved on a per-game basis, but rather are saved in json files in Unciv's asset folder. Each class in the game state that saves one of these will reference it by name, and when the game is running it will check the Ruleset to find the relevant information for that object. The various objects are: - Technology - referenced mainly in CivilizationInfo.TechManager - Nations - referenced mainly in CivilizationInfo - Policy - referenced mainly in CivilizationInfo.PolicyManager (seeing a pattern here?) - Building - referenced mainly in CityInfo.ConstructionManager - BaseUnit - referenced mainly in MapUnit - Promotion - referenced mainly in MapUnit - Terrain - referenced mainly in TileInfo - TileResource - referenced mainly in TileInfo - TileImprovement - referenced mainly in TileInfo There are also Translations in the Ruleset, but they technically have nothing to do with the game state but rather with the UI display. The information for all of these is in json files in android\\assets\\jsons UI UncivGame is the 'base' class for the UI, from which everything starts, but it itself doesn't do much. When we change a screen, we're changing a value in UncivGame, the interesting stuff happens in the screens themselves. The main menu - MainMenuScreen This is what the user sees when first entering the game. It acts as a hub to loading games, adding mods, options etc, without loading an actual game upfront - this allows us to differentiate between \"User can't enter game\" and \"User can't load game\" problems Starting a new game - NewGameScreen This is basically a giant setting screen for GameOptions and MapOptions classes, divided into: GameOptionsTable - game speed, mods, etc MapOptionsTable - either from preexisting map file or generated, in which case: size, map generation type, etc. PlayerPickerTable - What civs are in the game and who controls them The World Screen - WorldScreen 90% of the game is spent on this screen, so naturally it's the fullest, with the most things happening. This is the main hub of the game, with all other screens being opened from it, and closing back to reveal it. Most notable are: * The map itself - a TileMapHolder - with each of the rendered tiles being a TileGroup * The information panels - WorldScreenTopBar for stats and resources, UnitTable for the currently selected unit, TileInfoTable or the currently selected tile, BattleTable for battle simulation, and NotificationsScroll for the notifications * The minimap - MinimapHolder * Buttons linking to other screens - to the TechPickerScreen , EmpireOverviewScreen , and PolicyPickerScreen * The almighty Next Turn button The city screen - CityScreen The second-most important screen. Notable parts: * the City Stats table - should definitely be its own class come to think of it * The construction list and current construction (bottom left) - ConstructionsTable * Existing buildings, specialists and stats drilldown - CityInfoTable Others A few words need to be said about the NextTurn process, but there isn't really a good place for it so I'll put it here. We clone the GameInfo and use a \"new\" GameInfo for each turn because of 2 reasons. The first is multithreading and thread safety, and the second is multiplayer reproducibility. The first point is pretty basic. The NextTurn needs to happen in a separate thread so that the user can still have a responsive game when it's off doing stuff. Stuff in the GameInfo changes on NextTurn, so if you're rendering that same GameInfo, this could cause conflicts. Also, after NextTurn we generally autosave, and if stuff changes in the state while we're trying to serialize it to put it in the save file, that's Not Fun. A single clone solves both of these problems at once. The second point is less obvious. If we use our mutable state, changing stuff in place, then what happens when we're playing in Multiplayer? Multiplayer is based upon the fact that you can receive an entire game state and go from there, and in fact the move to multiplayer was what made the whole \"clone\" thing necessary (on the way it also solved the aforementioned threading problems)","title":"Project structure"},{"location":"wiki/Project-structure-and-major-classes/#project-structure","text":"Since LibGDX, and therefore Unciv, are built for multi-platform support, the project structure is built accordingly. 99% of the code is in the Core project, which contains all the platform-independant code. The Desktop and Android folders contain platform-specific things, and the Android folder also contains the game Images and the all-important Assets, which are required for running from Desktop as well, so we bundle them up into the .jar file when releasing. The Test folder contains tests that can be run manually via gradle with ./gradlew tests:test , and are run automatically by Travis for every push.","title":"Project structure"},{"location":"wiki/Project-structure-and-major-classes/#translations","text":"Before we get to the Classes, a word on Languages. Unciv is playable in several handfuls of languages, and there's magic to support that. Whenever you include a new string in code you will need to give it a quick evaluation - will users see it, and if so, what do I need to do to support its translations. Sometimes you may not need to do anything, sometimes you will add a line to the translation templates , and sometimes you will adapt the string formatting to support the translations. For details, see the 'Translation generation - for developers' chapter .","title":"Translations"},{"location":"wiki/Project-structure-and-major-classes/#major-classes","text":"Civ, and therefore Unciv, is a game with endless interconnectivity - everything affects everything else. In order to have some semblance of order, we'll go over the main classes in the order in which they are serialized. So yes, you can - for instance - get the center tile of a city, a TileInfo, directly from CityInfo. But delving into all the connections would only harm the point of this overview, that's what the actual code is for ;) The Game State: GameInfo CivilizationInfo CityInfo TileMap TileInfo MapUnit RuleSet (unique in that it is not part of the game state) The UI: MainMenuScreen NewGameScreen WorldScreen CityScreen MapEditorScreen Picker Screens - TechPickerScreen, PolicyPickerScreen, ImprovementPickerScreen, PromotionPickerScreen","title":"Major classes"},{"location":"wiki/Project-structure-and-major-classes/#game-state","text":"","title":"Game State"},{"location":"wiki/Project-structure-and-major-classes/#the-game-gameinfo","text":"First off, let's clarify: When we say \"The Game\", we mean the state of the game (what turn it is, who the players are, what each one has etc) and not the UI of the game. That is, The Game is the currently played game, not Unciv . The game contains three major parts: The list of the players, or civilizations - List The map upon which the game is played - TileMap The ruleset by which the game is played - RuleSet . This includes what technologies, buildings, units etc. are available, and IS NOT serialized and deserialized, but comes straight from the game files - more on that later. Parameters unique to this game - difficulty, game speed, victory conditions, etc. When we save the game, or load the game, we're actually serializing and deserializing this class, which means that the this class is the root of the entire game state. Most objects in the \"state tree\" have a transient reference to their parent, meaning the tree can be traversed in-code in all directions, and frequently is.","title":"The Game - GameInfo"},{"location":"wiki/Project-structure-and-major-classes/#a-civilization-civilizationinfo","text":"This represents one of the players of the game, and NOT a specific nation - meaning, not France, but rather \"Player X who is France in this game\". In another game, there will be another France. As one of the focal points of the game, it contains a lot of important information, the most important of which are: The list of cities the civilization has - List Which nation this is - references a certain Nation (part of the ruleset) Various Managers for the different aspects of the civilization - PolicyManager , GoldenAgeManager , GreatPersonManager , TechManager , VictoryManager , DiplomacyManager","title":"A Civilization - CivilizationInfo"},{"location":"wiki/Project-structure-and-major-classes/#a-city-cityinfo","text":"This contains the information about a specific city. Beyond basic information like name, location on map etc, the most important classes it contains are: Calculating the yield of the city - CityStats Managers for the various aspects - PopulationManager , CityConstructions , CityExpansionManager The tiles controlled and worked by the city - only their locations are permanently saved in the CityInfo, the actual information is in the TileInfo in the TileMap","title":"A City - CityInfo"},{"location":"wiki/Project-structure-and-major-classes/#the-map-tilemap","text":"This contains mostly helper functions and acts as a wrapper for the list of tiles it contains","title":"The map - TileMap"},{"location":"wiki/Project-structure-and-major-classes/#a-tile-tileinfo","text":"Each tile is comprised of several layers, and so has information for each. Tiles have, primarily: - A base terrain - Grassland, Hills, Desert etc. References a certain Terrain (part of the ruleset) - An optional terrain feature - Forest, Jungle, Oasis etc. References a certain Terrain (part of the ruleset) - An optional resource - Iron, Dye, Wheat etc. References a certain TileResource (part of the ruleset) - An improvement built on the tile, if any. References a certain TileImprovement (part of the ruleset) - The units that are currently in the tile - MapUnit","title":"A tile - TileInfo"},{"location":"wiki/Project-structure-and-major-classes/#a-unit-on-the-map-mapunit","text":"Unlike buildings, Unit in Unciv has two meanings. One is a Type of unit (like Spearman), and one is a specific instance of a unit (say, a Babylonian Spearman, at a certain position, with X health). MapUnit is a specific instance of a unit, whereas BaseUnit is the type of unit. Main information: - A name - references a specific BaseUnit - Health and Movement - Promotion status - UnitPromotions","title":"A unit on the map - MapUnit"},{"location":"wiki/Project-structure-and-major-classes/#ruleset","text":"So far so good - but what of everything that makes Civ, Civ? The units, the buildings, the nations, the improvements etc? Since these things remain the same for every game, these are not saved on a per-game basis, but rather are saved in json files in Unciv's asset folder. Each class in the game state that saves one of these will reference it by name, and when the game is running it will check the Ruleset to find the relevant information for that object. The various objects are: - Technology - referenced mainly in CivilizationInfo.TechManager - Nations - referenced mainly in CivilizationInfo - Policy - referenced mainly in CivilizationInfo.PolicyManager (seeing a pattern here?) - Building - referenced mainly in CityInfo.ConstructionManager - BaseUnit - referenced mainly in MapUnit - Promotion - referenced mainly in MapUnit - Terrain - referenced mainly in TileInfo - TileResource - referenced mainly in TileInfo - TileImprovement - referenced mainly in TileInfo There are also Translations in the Ruleset, but they technically have nothing to do with the game state but rather with the UI display. The information for all of these is in json files in android\\assets\\jsons","title":"Ruleset"},{"location":"wiki/Project-structure-and-major-classes/#ui","text":"UncivGame is the 'base' class for the UI, from which everything starts, but it itself doesn't do much. When we change a screen, we're changing a value in UncivGame, the interesting stuff happens in the screens themselves.","title":"UI"},{"location":"wiki/Project-structure-and-major-classes/#the-main-menu-mainmenuscreen","text":"This is what the user sees when first entering the game. It acts as a hub to loading games, adding mods, options etc, without loading an actual game upfront - this allows us to differentiate between \"User can't enter game\" and \"User can't load game\" problems","title":"The main menu - MainMenuScreen"},{"location":"wiki/Project-structure-and-major-classes/#starting-a-new-game-newgamescreen","text":"This is basically a giant setting screen for GameOptions and MapOptions classes, divided into: GameOptionsTable - game speed, mods, etc MapOptionsTable - either from preexisting map file or generated, in which case: size, map generation type, etc. PlayerPickerTable - What civs are in the game and who controls them","title":"Starting a new game - NewGameScreen"},{"location":"wiki/Project-structure-and-major-classes/#the-world-screen-worldscreen","text":"90% of the game is spent on this screen, so naturally it's the fullest, with the most things happening. This is the main hub of the game, with all other screens being opened from it, and closing back to reveal it. Most notable are: * The map itself - a TileMapHolder - with each of the rendered tiles being a TileGroup * The information panels - WorldScreenTopBar for stats and resources, UnitTable for the currently selected unit, TileInfoTable or the currently selected tile, BattleTable for battle simulation, and NotificationsScroll for the notifications * The minimap - MinimapHolder * Buttons linking to other screens - to the TechPickerScreen , EmpireOverviewScreen , and PolicyPickerScreen * The almighty Next Turn button","title":"The World Screen - WorldScreen"},{"location":"wiki/Project-structure-and-major-classes/#the-city-screen-cityscreen","text":"The second-most important screen. Notable parts: * the City Stats table - should definitely be its own class come to think of it * The construction list and current construction (bottom left) - ConstructionsTable * Existing buildings, specialists and stats drilldown - CityInfoTable","title":"The city screen - CityScreen"},{"location":"wiki/Project-structure-and-major-classes/#others","text":"A few words need to be said about the NextTurn process, but there isn't really a good place for it so I'll put it here. We clone the GameInfo and use a \"new\" GameInfo for each turn because of 2 reasons. The first is multithreading and thread safety, and the second is multiplayer reproducibility. The first point is pretty basic. The NextTurn needs to happen in a separate thread so that the user can still have a responsive game when it's off doing stuff. Stuff in the GameInfo changes on NextTurn, so if you're rendering that same GameInfo, this could cause conflicts. Also, after NextTurn we generally autosave, and if stuff changes in the state while we're trying to serialize it to put it in the save file, that's Not Fun. A single clone solves both of these problems at once. The second point is less obvious. If we use our mutable state, changing stuff in place, then what happens when we're playing in Multiplayer? Multiplayer is based upon the fact that you can receive an entire game state and go from there, and in fact the move to multiplayer was what made the whole \"clone\" thing necessary (on the way it also solved the aforementioned threading problems)","title":"Others"},{"location":"wiki/Regions/","text":"Regions The Concept During the generation of a random map (only; not pre-made maps) the map is split into a number of regions equal to the number of major civs. Each region gets classified according to its prevalent terrain, or if unable to be classified is called a \"hybrid\" region. The region type corresponds to the start bias of the civs as they are distributed. The region type also determines start placement and what luxuries will appear in the region. Example ![](https://user-images.githubusercontent.com/63475501/140308518-ad5a2f50-d5f1-4467-a296-3a67f6d0b007.png) How to define region behavior in your mod The game will work without any extra json definitions, but if you want the region system to work well when generating maps for your mod, these are the relevant uniques to define. Terrains.json \"Always Fertility [amount] for Map Generation\", \"[amount] to Fertility for Map Generation\" - these determine how good a terrain is for purposes of dividing land up fairly. The numbers are arbitrary but should reflect the relative value of the terrains. \"A Region is formed with at least [amount]% [simpleTerrain] tiles, with priority [amount]\", \"A Region is formed with at least [amount]% [simpleTerrain] tiles and [simpleTerrain] tiles, with priority [amount]\" - these determine the rules for when a region is classified as eg a \"desert\" region. Terrains are evaluated in ascending priority order, so in the base ruleset tundra regions are checked first. \"A Region can not contain more [simpleTerrain] tiles than [simpleTerrain] tiles\" - a useful compliment to the sum-of-two-terrains criterium above, if both terrains are in and of themselves terrain types. So in the base ruleset a large enough sum of jungle and forest allows a region to be classified as jungle, but only if there is more jungle than forest. \"Base Terrain on this tile is not counted for Region determination\" - for terrain features that are unremovable or otherwise dominate the tile. Used for Hills in the base ruleset. A region not fulfilling any criteria is classified as \"Hybrid\" \"Considered [terrainQuality] when determining start locations\" - where \"terrainQuality\" is one of \"Food\", \"Production\", \"Desirable\", \"Undesirable\". Usually used together with the \" \" or \" \" to determine what terrain is attractive when determining start locations. Note: if there are none of these for a terrain, the game will use the base stats of the terrain to guess a quality, but if there are any, the game will assume that they are complete.","title":"Regions"},{"location":"wiki/Regions/#regions","text":"","title":"Regions"},{"location":"wiki/Regions/#the-concept","text":"During the generation of a random map (only; not pre-made maps) the map is split into a number of regions equal to the number of major civs. Each region gets classified according to its prevalent terrain, or if unable to be classified is called a \"hybrid\" region. The region type corresponds to the start bias of the civs as they are distributed. The region type also determines start placement and what luxuries will appear in the region. Example ![](https://user-images.githubusercontent.com/63475501/140308518-ad5a2f50-d5f1-4467-a296-3a67f6d0b007.png)","title":"The Concept"},{"location":"wiki/Regions/#how-to-define-region-behavior-in-your-mod","text":"The game will work without any extra json definitions, but if you want the region system to work well when generating maps for your mod, these are the relevant uniques to define.","title":"How to define region behavior in your mod"},{"location":"wiki/Regions/#terrainsjson","text":"\"Always Fertility [amount] for Map Generation\", \"[amount] to Fertility for Map Generation\" - these determine how good a terrain is for purposes of dividing land up fairly. The numbers are arbitrary but should reflect the relative value of the terrains. \"A Region is formed with at least [amount]% [simpleTerrain] tiles, with priority [amount]\", \"A Region is formed with at least [amount]% [simpleTerrain] tiles and [simpleTerrain] tiles, with priority [amount]\" - these determine the rules for when a region is classified as eg a \"desert\" region. Terrains are evaluated in ascending priority order, so in the base ruleset tundra regions are checked first. \"A Region can not contain more [simpleTerrain] tiles than [simpleTerrain] tiles\" - a useful compliment to the sum-of-two-terrains criterium above, if both terrains are in and of themselves terrain types. So in the base ruleset a large enough sum of jungle and forest allows a region to be classified as jungle, but only if there is more jungle than forest. \"Base Terrain on this tile is not counted for Region determination\" - for terrain features that are unremovable or otherwise dominate the tile. Used for Hills in the base ruleset. A region not fulfilling any criteria is classified as \"Hybrid\" \"Considered [terrainQuality] when determining start locations\" - where \"terrainQuality\" is one of \"Food\", \"Production\", \"Desirable\", \"Undesirable\". Usually used together with the \" \" or \" \" to determine what terrain is attractive when determining start locations. Note: if there are none of these for a terrain, the game will use the base stats of the terrain to guess a quality, but if there are any, the game will assume that they are complete.","title":"Terrains.json"},{"location":"wiki/Translating/","text":"Starting out The translation files are at /android/assets/jsons/translations If you're adding a new language, you'll need to create a new file ('Create a new file' to the right of the folder name in the UI), and copy into it the contents of template.properties If you're adding stuff to an existing language, simply start editing the file! You don't need to download anything, all translation work can be done on the Github website :) When you feel that you're ready to add your translation to the game, you'll need to create a merge request, which takes your changes and puts them into the main version of the game - it's pretty straightforward once you do it Pitfalls If a translation template (the stuff to the left of \" = \") contains square brackets, you will have to include each of them verbatim in your translation, but you can move them. Upper/lower case is relevant! e.g. All [personFilter] are cool can be translated as Tous les [personFilter] sont cool , but not as Tous les [personnages] sont cool , and neither as Nous sommes vraiment cool . Failing this is the main cause of your PR's showing up with red \"x\"es and \"checks failed\". Blanks: Watch out for blanks at the start of a line or two of them before the equals sign. If you got such a line - those blanks are part of the translation key and must not be deleted on the left side, and you should probably also include them in your translation (unless your language doesn't need spaces to separate things). Changes in the templates: When we find a typo in the english texts and fix it, or marginally change a wording, the template changes. Often the old template will not be automatically fixed in the existing translations, because it's a lot of work and in most cases the developers cannot be sure the translation is still correct. For you, that might look like your translations are simply disappearing with an update. In such a case, you have the option to use github's history to look up old versions, copy the old translation, place it where the new template now says \"requires translation\" - and proofread and adapt it to the new english version. The history link for each file is in the top right area and has a nice round clock icon. Wait, what just happened? Like most open-source projects, Unciv is developed at Github, so if you don't have a user you'll first have to create one. The way Github works is the following: You create a 'fork' repo, i.e. copy, of Unciv that belongs to your user (myUser/Unciv) You make changes to your copy. These changes are called a 'commit'. You make a pull request, which is basically asking for the changes you made on myUser/Unciv to be merged into the main repo (yairm210/Unciv) When you ask to 'edit' a file in yairm210/Unciv, these stages happen automatically - but it's important to understand what's happening behind the scenes do you understand where the changes actually are! Why not use a crowdsourcing translation website like <...>? Testing. Currently, translations undergo a number of tests for verification. This allows some language changes to be accepted and others not, and it's all in the same platform with the same tests. External translation tools don't allow for this. History and revisions. This is what Git was made for, and nothing like it exists in the world. I'm not exaggerating. Release cycle. We release versions weekly. If we need to take information from an external website every time, and for many that I've checked - you need to download the info as a csv or something and convert it. Every extra step hurts. Discussions. Most crowdsourcing translation websites don't allow for discussions and corrections on translations. Github does. Mass changes. If we're changing the source of the translation but want to keep the various destinations (say, we change \"Gold from trade routes +[amount]%\" to \"+[amount]% Gold from trade routes\"), if all the translation files are in Git we can do that in 1 minute. If it's external, this varies greatly. Other notes Make sure that you make the changes in the 'master' branch in your repo! Each untranslated phrase will have a \"requires translation\" line before it, so you can quickly find them. You don't need to remove them yourself if you don't want to - they will be automatically removed the next time we rebuild the file. Do as much as you're comfortable with - it's a big game with a lot of named objects, so don't feel pressured into doing everything =) Note that Right-to-Left languages such as Arabic and Hebrew are not supported by the framework :/ Translation generation - for developers The automatic template generation Before releasing every version, we regenerate the translation files. Sometimes, new strings (names, uniques, etc) are added in the json files. In order to not have to add every single one to the translation files manually, we have a class - TranslationFileWriter - that, for every language: Goes over the template.properties and copies translation lines For every json file in the jsons folder Selects all string values - both in objects, and in arrays in objects Generates a 'key = value' line This means that every text that ISN'T in the jsons needs to be added manually to the template.properties in order to be translated! That also means if you've been adding new json structures you (or someone) should check TranslationFileWriter and see if it is able to cope with them. Rules for templates added manually Building a new UI and doing something like popup.add(\"Hello world\".toLabel()) is a typical case: This is not contained in json data, so you'll have to add the template to template.properties yourself. For this example, adding Hello world = somewhere in a line of its own could suffice. Note the space at the end - it's absolutely required, and see to it your editor does not destroy your work. If you want to make sure, use Android Studio for git integration, but edit the file in an external editor, then run the unit tests locally before pushing. (to do: add link for instructions how to do that) Leading spaces on a translation line or more than one space between the text and the = would mean these spaces are a key part of the string to be translated . That can work, but be warned: translators often overlook that those spaces are a required part of both template and translation, so if you can do without, then doing without is safer. Translation templates can use placeholders, and there's two varieties: [] and {} . Square ones take precedence over curly ones, and nesting works only with a single level of curly nested inside one level of square. I both cases the symbols themselves ( []{} ) are removed by the translation engine. Square brackets [] mean the outer and inner components are both translated individually. The outer template will use alias names inside the brackets - example: Your code outputs \"Everyone gains [5000] gold!\", then the translation template should be \"Everyone gains [amount] gold! = \". The translation engine would translate the \"Everyone gains [] gold!\" and \"5000\" individually and reassemble them - of course, the number is simply passed through. But in other cases that could be e.g. a Unit name that would be translated, and you could trust that translations for units are already handled just fine. Note that uniques often use the feature, but it is in no way limited to them. It it makes life easier for translators, use it. Curly brackets {} are simpler - the contents within the brackets are translated individually, while the outer parts are passed through verbatim. Example: \"+$amount${Fonts.gold} {Gold}\".toLabel() - note the first ${} is a kotlin template while the second pair becomes part of the string. It tells the translation engine to ignore the numbers and the symbol but to translate the single word \"Gold\".","title":"Translating"},{"location":"wiki/Translating/#starting-out","text":"The translation files are at /android/assets/jsons/translations If you're adding a new language, you'll need to create a new file ('Create a new file' to the right of the folder name in the UI), and copy into it the contents of template.properties If you're adding stuff to an existing language, simply start editing the file! You don't need to download anything, all translation work can be done on the Github website :) When you feel that you're ready to add your translation to the game, you'll need to create a merge request, which takes your changes and puts them into the main version of the game - it's pretty straightforward once you do it","title":"Starting out"},{"location":"wiki/Translating/#pitfalls","text":"If a translation template (the stuff to the left of \" = \") contains square brackets, you will have to include each of them verbatim in your translation, but you can move them. Upper/lower case is relevant! e.g. All [personFilter] are cool can be translated as Tous les [personFilter] sont cool , but not as Tous les [personnages] sont cool , and neither as Nous sommes vraiment cool . Failing this is the main cause of your PR's showing up with red \"x\"es and \"checks failed\". Blanks: Watch out for blanks at the start of a line or two of them before the equals sign. If you got such a line - those blanks are part of the translation key and must not be deleted on the left side, and you should probably also include them in your translation (unless your language doesn't need spaces to separate things). Changes in the templates: When we find a typo in the english texts and fix it, or marginally change a wording, the template changes. Often the old template will not be automatically fixed in the existing translations, because it's a lot of work and in most cases the developers cannot be sure the translation is still correct. For you, that might look like your translations are simply disappearing with an update. In such a case, you have the option to use github's history to look up old versions, copy the old translation, place it where the new template now says \"requires translation\" - and proofread and adapt it to the new english version. The history link for each file is in the top right area and has a nice round clock icon.","title":"Pitfalls"},{"location":"wiki/Translating/#wait-what-just-happened","text":"Like most open-source projects, Unciv is developed at Github, so if you don't have a user you'll first have to create one. The way Github works is the following: You create a 'fork' repo, i.e. copy, of Unciv that belongs to your user (myUser/Unciv) You make changes to your copy. These changes are called a 'commit'. You make a pull request, which is basically asking for the changes you made on myUser/Unciv to be merged into the main repo (yairm210/Unciv) When you ask to 'edit' a file in yairm210/Unciv, these stages happen automatically - but it's important to understand what's happening behind the scenes do you understand where the changes actually are!","title":"Wait, what just happened?"},{"location":"wiki/Translating/#why-not-use-a-crowdsourcing-translation-website-like","text":"Testing. Currently, translations undergo a number of tests for verification. This allows some language changes to be accepted and others not, and it's all in the same platform with the same tests. External translation tools don't allow for this. History and revisions. This is what Git was made for, and nothing like it exists in the world. I'm not exaggerating. Release cycle. We release versions weekly. If we need to take information from an external website every time, and for many that I've checked - you need to download the info as a csv or something and convert it. Every extra step hurts. Discussions. Most crowdsourcing translation websites don't allow for discussions and corrections on translations. Github does. Mass changes. If we're changing the source of the translation but want to keep the various destinations (say, we change \"Gold from trade routes +[amount]%\" to \"+[amount]% Gold from trade routes\"), if all the translation files are in Git we can do that in 1 minute. If it's external, this varies greatly.","title":"Why not use a crowdsourcing translation website like <...>?"},{"location":"wiki/Translating/#other-notes","text":"Make sure that you make the changes in the 'master' branch in your repo! Each untranslated phrase will have a \"requires translation\" line before it, so you can quickly find them. You don't need to remove them yourself if you don't want to - they will be automatically removed the next time we rebuild the file. Do as much as you're comfortable with - it's a big game with a lot of named objects, so don't feel pressured into doing everything =) Note that Right-to-Left languages such as Arabic and Hebrew are not supported by the framework :/","title":"Other notes"},{"location":"wiki/Translating/#translation-generation-for-developers","text":"","title":"Translation generation - for developers"},{"location":"wiki/Translating/#the-automatic-template-generation","text":"Before releasing every version, we regenerate the translation files. Sometimes, new strings (names, uniques, etc) are added in the json files. In order to not have to add every single one to the translation files manually, we have a class - TranslationFileWriter - that, for every language: Goes over the template.properties and copies translation lines For every json file in the jsons folder Selects all string values - both in objects, and in arrays in objects Generates a 'key = value' line This means that every text that ISN'T in the jsons needs to be added manually to the template.properties in order to be translated! That also means if you've been adding new json structures you (or someone) should check TranslationFileWriter and see if it is able to cope with them.","title":"The automatic template generation"},{"location":"wiki/Translating/#rules-for-templates-added-manually","text":"Building a new UI and doing something like popup.add(\"Hello world\".toLabel()) is a typical case: This is not contained in json data, so you'll have to add the template to template.properties yourself. For this example, adding Hello world = somewhere in a line of its own could suffice. Note the space at the end - it's absolutely required, and see to it your editor does not destroy your work. If you want to make sure, use Android Studio for git integration, but edit the file in an external editor, then run the unit tests locally before pushing. (to do: add link for instructions how to do that) Leading spaces on a translation line or more than one space between the text and the = would mean these spaces are a key part of the string to be translated . That can work, but be warned: translators often overlook that those spaces are a required part of both template and translation, so if you can do without, then doing without is safer. Translation templates can use placeholders, and there's two varieties: [] and {} . Square ones take precedence over curly ones, and nesting works only with a single level of curly nested inside one level of square. I both cases the symbols themselves ( []{} ) are removed by the translation engine. Square brackets [] mean the outer and inner components are both translated individually. The outer template will use alias names inside the brackets - example: Your code outputs \"Everyone gains [5000] gold!\", then the translation template should be \"Everyone gains [amount] gold! = \". The translation engine would translate the \"Everyone gains [] gold!\" and \"5000\" individually and reassemble them - of course, the number is simply passed through. But in other cases that could be e.g. a Unit name that would be translated, and you could trust that translations for units are already handled just fine. Note that uniques often use the feature, but it is in no way limited to them. It it makes life easier for translators, use it. Curly brackets {} are simpler - the contents within the brackets are translated individually, while the outer parts are passed through verbatim. Example: \"+$amount${Fonts.gold} {Gold}\".toLabel() - note the first ${} is a kotlin template while the second pair becomes part of the string. It tells the translation engine to ignore the numbers and the symbol but to translate the single word \"Gold\".","title":"Rules for templates added manually"},{"location":"wiki/Translations%2C-mods%2C-and-modding-freedom-in-Open-Source/","text":"Unciv is, at its core, a remake of Civ V, meaning mechanics-wise there's almost by definition not much place for innovation. In terms of UI, there's nothing here that hasn't been done dozens of times, with far greater polish. However, there is one area where Unciv is groundbreaking: in its accessibility of translations, the possibility space of its mods, and the relationship between them. Translations The translation process So let's start with translation. Surely this is a solved problem, right? Source text + language = translated text, and this information needs to be in a file so the game can read it. What makes us different from, for example, Firaxis? There are a couple of things, but the most significant is that this is an open-source game, and thus the translations are open-source as well. This means translators are both amateurs and not obligated to translate, so if translating is difficult, they simply won't. Amateurs can make mistakes, which is why it's vital that mistakes are easy to spot. That means that formats like \"translation key\" - e.g. DIPLOMACY_GREETING = Siamo lieti di fare la vostra conoscenza. are much less effective than A pleasure to meet you. = Siamo lieti di fare la vostra conoscenza. This format lends itself both the easier translation (it's immediately obvious what needs to be translated) and actual collaboration. A common suggestion that we get (by people with little familiarity with the project) is to \"use a website for translation\". This is not bad advice for a small open source game, but there are multiple disadvantages that (for now) no translation website provides enough advantage to outweigh: Testing . Currently, translations undergo a number of tests for verification - more on that later! This allows some language changes to be accepted and others not, and it's all in the same platform with the same tests. External translation tools don't allow for this. History and revisions . This is what Git was made for, and nothing like it exists in the world. By itself this would not Release cycle . We release versions semiweekly, and if we needed to upload changes to the translation website for every in-game change, and download them for every release, that's extra work. For some websites this is automate-able - for most it is not. Discussions . Most crowdsourcing translation websites don't allow for discussions and corrections on translations. Github makes every translation collaborative work. Mass changes . If we're changing the source of the translation but want to keep the various destinations (say, we change \"Gold from trade routes +[amount]%\" to \"+[amount]% Gold from trade routes\"), if all the translation files are in Git we can do that in 1 minute. If it's external, this varies greatly. Here are some ways that we managed to go wrong in the past: Putting all languages into the same file (\"one big translation dictionary\") - when multiple people edit this file for different languages, they can conflict with each other. Separate to different files for simpler management. Using json - json is great for machines, but less so for humans, who can easily make mistakes. Json format is surprisingly finnicky, miss a closing \" and the whole file is now unreadable. The format we decided to go for is one file per language, delimited by \" = \" for visual separation, in a .properties file. Lines starting in # are considered comments, so we can add comments for translators. Building the translation files As stated, Unciv releases versions semiweekly, and very often these changes include new objects or new UI elements. How do we keep all translation files up to date? In Unciv, all object data is stored in json format. This allows us to iterate on all objects, regardless of type, and extract the various text fields (strings or lists of strings). We avoid duplication by saving all translation texts we've already added, and use the existing translations to populate the \"value\" for each translation \"key\" we found in the json files. Since we rebuild the entire translation file every time, there's currently no way for translators to retain their own comments for future translators. But on the other hand, since for each line that we add we already know if it's translated or not, this allows us to add a # Requires translation line before every non-translated line, which helps translators for languages that are almost fully translated to easily locate the new or changed terms for translation with ctrl+f (and of course this marking will disappear the next time we rebuild the file). Since there are UI texts that are not part of any specific object (like \"Start new game\"), we have a separate template.properties file for texts to translate that are not in the json files. Unlike adding objects, where the developer doesn't need to address the translation files at all since it's all linked, when adding UI elements with new texts devs need to remember to add the texts to template.properties file. Translation placeholders This is all well and good for specific text-to-text translations, but what about translating \"A Temple has been built in Rome\"? The same template could potentially be any building name, or any city name! We do this with placeholders, which looks something like this: [construction] has been built in [cityName] = [cityName] ha costruito [construction] . As you can see, the placement of the parameters can change between languages, so we have to name all parameters. This also means that there can be explicitly wrong translations - if any parameter that appears in the source does not appear in the translated version, we won't be able to display this in-game! This is one of the translation tests that we mentioned earlier - when a translator opens a PR, the game undergoes build & test via the Github Actions, and will notify on failures. Finding the text that warns of the failure within the action output is currently mostly done by devs, but I hope to be able to automate this too someday. To translate a text like \"[Temple] has been built in [Rome]\", therefore, we need to: - Find the relevant translation (we do this by erasing all text between square brackets in input and finding the relevant translation text) - Map placeholder names to input text (construction = Temple, cityName = Rome) - Replace placeholders in translation with TRANSLATED input text (in [cityName] ha costruito [construction] , replace \"[cityName]\" with translation of \"Rome\", and \"[construction]\" with translation of \"Temple\") Translating mod data The translation generation reads information from \"a ruleset\", i.e. the set of jsons defining the game's objects. Every mod is also a ruleset, either replacing or adding to the base ruleset defined in the game. This means that the same translation generation that we do for the base game can also be applied to mods, and so each modder can decide (from within the game) to generate translation files for his mod, and since mods are uploaded to Github to be widely available as part of the mod release methodology, translators will be able to translate those files the exact same way that they translate Unciv's base ruleset. Uniques Moddable unique effects Every object in Unciv can include \"uniques\" - a list of strings, each granting a unique effect that is not applicable for every object of its type. For example, the Palace building has the unique \"Indicates the capital city\", and the settler has the unique \"Founds a new city\". This allows us to share effects between multiple units, and to avoid hardcoding and allow modders to add any effect to any object. Here too we encounter the problem of \"generic\" uniques - how can we have these effects grant a building, some stats, etc, using the same unique for all objects? Why, with placeholders of course! For example, one building has \"Requires a [Library] in all cities\", where \"Library\" can be replaced with any other building for similar effects. We can then extract the parameters from the unique at runtime, to know how to resolve the unique's effects. Since the translation template is the same as the unique template, these uniques are instantly translatable as well! We do have a slight problem, though - since translation texts come directly from the json files, and the json files have \"Requires a [Library] in all cities\", how do we tell the translators not to directly translate \"Library\" but the take the parameter name verbatim? Well, 95% of translation parameters fit nicely into a certain type - units, buildings, techs, terrains etc. So we can search for an object with than name, and since we find a Library building, we can put \"Requires a [buildingName] in all cities = \" as our translation line. Filters As time went on, we noticed that many of our \"uniques\" weren't so unique after all. Many were the same but with slightly different conditions. One affects all cities, one only coastal cities, and one only the city the building is built in. One affects Mounted units, one affects wounded units, one affects all water units, etc. We started compiling these conditions into \"filters\", which limited the number of uniques while expanding their range considerably. Take the following example unique for a building: \"[+1 Food] from [Deer] tiles [in this city]\". In its \"placeholder\" form, this is \"[stats] from [tileFilter] tiles [cityFilter]\". stats can accept any list of stats, e.g. '-2 Gold, +1 Science', '+3 Culture', etc. tileFilter can accept any number of tile parameters (base terrain e.g. 'Plains', terrain type eg. 'Land'/'Water', terrain features e.g. 'Forest', improvements e.g. 'Mine', resources e.g. 'Iron'. cityFilter can accept 'in this city', 'in all cities', 'in capital', 'in coastal cities', etc. There are also filters for units, all acceptable values are documented here . Unique management with Enums The further along we go, the more generic the uniques become, and the more of them there are. Older uniques become new ones, by being merged or made more generic, and the older ones are deprecated. Deprecation notices are put on Discord, but a one-time message is easy to miss, and if you come back after a while you don't know what's changed. Modders discover during gameplay that the values they put for uniques were incorrect. All these problems are solved with a single solution - since all uniques are defined by their text, we can create an enum with ALL existing uniques, which lets us: Find all usages of a unique in the IDE instantly Mark deprecated uniques as such using @Deprecated(\"as of ) for devs (and modders!) Compare uniques using enum values, which is faster What's more, with a little bit of autodetection magic, we can determine the type of the parameter using its text. Using the above example, \"[stats] from [tileFilter] tiles [cityFilter]\", we can tell by the names of the parameters what each one is supposed to be,. We can then check at loading time for each unique, if its parameter values matches the parameter type it's supposed to have, which lets us catch incorrect parameters. The \"autodetection\" of parameter types for translations can also be fed from here, leading to much more accurate translation texts - instead of detecting from an example (e.g. \"Requires a [Library] in all cities\" from the json), we now use a dev-inputted value like \"Requires a [buildingName] in all cities\". This allows us to accept multiple types, like for e.g. \"Requires [buildingName/techName/policyName]\". Deprecated values can be detected due to the @Deprecated annotation, and can be displayed to the modders when loading the mod, together with the correct replacement. Conditionals Beyond the existing filters for units, buildings, tiles etc, there are some conditions that are global. For example, uniques that take effect when the empire is happy; when a tech has been researched; when the empire is at war; etc. Rather than being 'build in' to specific uniques, these conditions can be seen as extensions of existing uniques and thus globally relevant. For example, instead of \"[+1 Production] [in all cities] when empire is happy\", we can extract the conditional to \"[+1 Production] [in all cities] \". This does two things: A. Turns the 'extra' unique back into a regular \"[stats] [cityFilter]\" unique B. Turns the conditional into an extra piece that can be added onto any other unique Conditionals have a lot of nuance, especially regarding translation and ordering, so work in that field is more gradual. What's next? We have yet to fully map all existing uniques and convert all textual references in the code to Enum usages, and have yet to extract all conditionals from their uniques. We already have a map of what uniques can be put on what objects - it won't take much to add that check as well and warn against uniques that are put on the wrong sorts of objects. Once we build the full inventory of the uniques, instead of the wiki page that needs to be updated manually we'll be able to generate a list of all acceptable uniques and their parameters directly from the source of truth. Put that in a webpage, add hover-links for each parameter type, generate and upload to github.io every version, and watch the magic happen. We'll also be able to notify modders if they use \"unknown\" uniques.","title":"Translations, mods, and modding freedom in Open Source"},{"location":"wiki/Translations%2C-mods%2C-and-modding-freedom-in-Open-Source/#translations","text":"","title":"Translations"},{"location":"wiki/Translations%2C-mods%2C-and-modding-freedom-in-Open-Source/#the-translation-process","text":"So let's start with translation. Surely this is a solved problem, right? Source text + language = translated text, and this information needs to be in a file so the game can read it. What makes us different from, for example, Firaxis? There are a couple of things, but the most significant is that this is an open-source game, and thus the translations are open-source as well. This means translators are both amateurs and not obligated to translate, so if translating is difficult, they simply won't. Amateurs can make mistakes, which is why it's vital that mistakes are easy to spot. That means that formats like \"translation key\" - e.g. DIPLOMACY_GREETING = Siamo lieti di fare la vostra conoscenza. are much less effective than A pleasure to meet you. = Siamo lieti di fare la vostra conoscenza. This format lends itself both the easier translation (it's immediately obvious what needs to be translated) and actual collaboration. A common suggestion that we get (by people with little familiarity with the project) is to \"use a website for translation\". This is not bad advice for a small open source game, but there are multiple disadvantages that (for now) no translation website provides enough advantage to outweigh: Testing . Currently, translations undergo a number of tests for verification - more on that later! This allows some language changes to be accepted and others not, and it's all in the same platform with the same tests. External translation tools don't allow for this. History and revisions . This is what Git was made for, and nothing like it exists in the world. By itself this would not Release cycle . We release versions semiweekly, and if we needed to upload changes to the translation website for every in-game change, and download them for every release, that's extra work. For some websites this is automate-able - for most it is not. Discussions . Most crowdsourcing translation websites don't allow for discussions and corrections on translations. Github makes every translation collaborative work. Mass changes . If we're changing the source of the translation but want to keep the various destinations (say, we change \"Gold from trade routes +[amount]%\" to \"+[amount]% Gold from trade routes\"), if all the translation files are in Git we can do that in 1 minute. If it's external, this varies greatly. Here are some ways that we managed to go wrong in the past: Putting all languages into the same file (\"one big translation dictionary\") - when multiple people edit this file for different languages, they can conflict with each other. Separate to different files for simpler management. Using json - json is great for machines, but less so for humans, who can easily make mistakes. Json format is surprisingly finnicky, miss a closing \" and the whole file is now unreadable. The format we decided to go for is one file per language, delimited by \" = \" for visual separation, in a .properties file. Lines starting in # are considered comments, so we can add comments for translators.","title":"The translation process"},{"location":"wiki/Translations%2C-mods%2C-and-modding-freedom-in-Open-Source/#building-the-translation-files","text":"As stated, Unciv releases versions semiweekly, and very often these changes include new objects or new UI elements. How do we keep all translation files up to date? In Unciv, all object data is stored in json format. This allows us to iterate on all objects, regardless of type, and extract the various text fields (strings or lists of strings). We avoid duplication by saving all translation texts we've already added, and use the existing translations to populate the \"value\" for each translation \"key\" we found in the json files. Since we rebuild the entire translation file every time, there's currently no way for translators to retain their own comments for future translators. But on the other hand, since for each line that we add we already know if it's translated or not, this allows us to add a # Requires translation line before every non-translated line, which helps translators for languages that are almost fully translated to easily locate the new or changed terms for translation with ctrl+f (and of course this marking will disappear the next time we rebuild the file). Since there are UI texts that are not part of any specific object (like \"Start new game\"), we have a separate template.properties file for texts to translate that are not in the json files. Unlike adding objects, where the developer doesn't need to address the translation files at all since it's all linked, when adding UI elements with new texts devs need to remember to add the texts to template.properties file.","title":"Building the translation files"},{"location":"wiki/Translations%2C-mods%2C-and-modding-freedom-in-Open-Source/#translation-placeholders","text":"This is all well and good for specific text-to-text translations, but what about translating \"A Temple has been built in Rome\"? The same template could potentially be any building name, or any city name! We do this with placeholders, which looks something like this: [construction] has been built in [cityName] = [cityName] ha costruito [construction] . As you can see, the placement of the parameters can change between languages, so we have to name all parameters. This also means that there can be explicitly wrong translations - if any parameter that appears in the source does not appear in the translated version, we won't be able to display this in-game! This is one of the translation tests that we mentioned earlier - when a translator opens a PR, the game undergoes build & test via the Github Actions, and will notify on failures. Finding the text that warns of the failure within the action output is currently mostly done by devs, but I hope to be able to automate this too someday. To translate a text like \"[Temple] has been built in [Rome]\", therefore, we need to: - Find the relevant translation (we do this by erasing all text between square brackets in input and finding the relevant translation text) - Map placeholder names to input text (construction = Temple, cityName = Rome) - Replace placeholders in translation with TRANSLATED input text (in [cityName] ha costruito [construction] , replace \"[cityName]\" with translation of \"Rome\", and \"[construction]\" with translation of \"Temple\")","title":"Translation placeholders"},{"location":"wiki/Translations%2C-mods%2C-and-modding-freedom-in-Open-Source/#translating-mod-data","text":"The translation generation reads information from \"a ruleset\", i.e. the set of jsons defining the game's objects. Every mod is also a ruleset, either replacing or adding to the base ruleset defined in the game. This means that the same translation generation that we do for the base game can also be applied to mods, and so each modder can decide (from within the game) to generate translation files for his mod, and since mods are uploaded to Github to be widely available as part of the mod release methodology, translators will be able to translate those files the exact same way that they translate Unciv's base ruleset.","title":"Translating mod data"},{"location":"wiki/Translations%2C-mods%2C-and-modding-freedom-in-Open-Source/#uniques","text":"","title":"Uniques"},{"location":"wiki/Translations%2C-mods%2C-and-modding-freedom-in-Open-Source/#moddable-unique-effects","text":"Every object in Unciv can include \"uniques\" - a list of strings, each granting a unique effect that is not applicable for every object of its type. For example, the Palace building has the unique \"Indicates the capital city\", and the settler has the unique \"Founds a new city\". This allows us to share effects between multiple units, and to avoid hardcoding and allow modders to add any effect to any object. Here too we encounter the problem of \"generic\" uniques - how can we have these effects grant a building, some stats, etc, using the same unique for all objects? Why, with placeholders of course! For example, one building has \"Requires a [Library] in all cities\", where \"Library\" can be replaced with any other building for similar effects. We can then extract the parameters from the unique at runtime, to know how to resolve the unique's effects. Since the translation template is the same as the unique template, these uniques are instantly translatable as well! We do have a slight problem, though - since translation texts come directly from the json files, and the json files have \"Requires a [Library] in all cities\", how do we tell the translators not to directly translate \"Library\" but the take the parameter name verbatim? Well, 95% of translation parameters fit nicely into a certain type - units, buildings, techs, terrains etc. So we can search for an object with than name, and since we find a Library building, we can put \"Requires a [buildingName] in all cities = \" as our translation line.","title":"Moddable unique effects"},{"location":"wiki/Translations%2C-mods%2C-and-modding-freedom-in-Open-Source/#filters","text":"As time went on, we noticed that many of our \"uniques\" weren't so unique after all. Many were the same but with slightly different conditions. One affects all cities, one only coastal cities, and one only the city the building is built in. One affects Mounted units, one affects wounded units, one affects all water units, etc. We started compiling these conditions into \"filters\", which limited the number of uniques while expanding their range considerably. Take the following example unique for a building: \"[+1 Food] from [Deer] tiles [in this city]\". In its \"placeholder\" form, this is \"[stats] from [tileFilter] tiles [cityFilter]\". stats can accept any list of stats, e.g. '-2 Gold, +1 Science', '+3 Culture', etc. tileFilter can accept any number of tile parameters (base terrain e.g. 'Plains', terrain type eg. 'Land'/'Water', terrain features e.g. 'Forest', improvements e.g. 'Mine', resources e.g. 'Iron'. cityFilter can accept 'in this city', 'in all cities', 'in capital', 'in coastal cities', etc. There are also filters for units, all acceptable values are documented here .","title":"Filters"},{"location":"wiki/Translations%2C-mods%2C-and-modding-freedom-in-Open-Source/#unique-management-with-enums","text":"The further along we go, the more generic the uniques become, and the more of them there are. Older uniques become new ones, by being merged or made more generic, and the older ones are deprecated. Deprecation notices are put on Discord, but a one-time message is easy to miss, and if you come back after a while you don't know what's changed. Modders discover during gameplay that the values they put for uniques were incorrect. All these problems are solved with a single solution - since all uniques are defined by their text, we can create an enum with ALL existing uniques, which lets us: Find all usages of a unique in the IDE instantly Mark deprecated uniques as such using @Deprecated(\"as of ) for devs (and modders!) Compare uniques using enum values, which is faster What's more, with a little bit of autodetection magic, we can determine the type of the parameter using its text. Using the above example, \"[stats] from [tileFilter] tiles [cityFilter]\", we can tell by the names of the parameters what each one is supposed to be,. We can then check at loading time for each unique, if its parameter values matches the parameter type it's supposed to have, which lets us catch incorrect parameters. The \"autodetection\" of parameter types for translations can also be fed from here, leading to much more accurate translation texts - instead of detecting from an example (e.g. \"Requires a [Library] in all cities\" from the json), we now use a dev-inputted value like \"Requires a [buildingName] in all cities\". This allows us to accept multiple types, like for e.g. \"Requires [buildingName/techName/policyName]\". Deprecated values can be detected due to the @Deprecated annotation, and can be displayed to the modders when loading the mod, together with the correct replacement.","title":"Unique management with Enums"},{"location":"wiki/Translations%2C-mods%2C-and-modding-freedom-in-Open-Source/#conditionals","text":"Beyond the existing filters for units, buildings, tiles etc, there are some conditions that are global. For example, uniques that take effect when the empire is happy; when a tech has been researched; when the empire is at war; etc. Rather than being 'build in' to specific uniques, these conditions can be seen as extensions of existing uniques and thus globally relevant. For example, instead of \"[+1 Production] [in all cities] when empire is happy\", we can extract the conditional to \"[+1 Production] [in all cities] \". This does two things: A. Turns the 'extra' unique back into a regular \"[stats] [cityFilter]\" unique B. Turns the conditional into an extra piece that can be added onto any other unique Conditionals have a lot of nuance, especially regarding translation and ordering, so work in that field is more gradual.","title":"Conditionals"},{"location":"wiki/Translations%2C-mods%2C-and-modding-freedom-in-Open-Source/#whats-next","text":"We have yet to fully map all existing uniques and convert all textual references in the code to Enum usages, and have yet to extract all conditionals from their uniques. We already have a map of what uniques can be put on what objects - it won't take much to add that check as well and warn against uniques that are put on the wrong sorts of objects. Once we build the full inventory of the uniques, instead of the wiki page that needs to be updated manually we'll be able to generate a list of all acceptable uniques and their parameters directly from the source of truth. Put that in a webpage, add hover-links for each parameter type, generate and upload to github.io every version, and watch the magic happen. We'll also be able to notify modders if they use \"unknown\" uniques.","title":"What's next?"},{"location":"wiki/Uniques/","text":"Overview Generated Documentation Unique locations Parameter types stats tileFilter unitFilter cityFilter buildingFilter Overview Every type of object has some traits that are shared across all, or most, objects of its kind. For example, a building's stat increase, cost and required tech; a unit's type, movement and attack; a resource's type, improvement and bonus stats from improvement. All such traits have their own fields in the said object types. But there are also other traits, that are only in a small subset of objects will have. Units that can see submarines from more than one tile away, or can move after attacking, or has a combat bonus against a certain other type of unit. Buildings that give a free great person, or improve stats dependent on the population of a city, or provide extra yield to certain tiles. These traits cannot be given their own fields due to the huge number of them. Instead, every special trait that an object has is encoded into a single parameter: the list of unique traits, or \"uniques\". In the json files, this looks something like \"uniques\": [\"Requires a [Market] in all cities\", \"Cost increases by [30] per owned city\"] . As seen in the above example, in order to provide flexibility and generalization, Uniques have certain parameters , marked by the fact that they are inside square braces. These parameters can be changed, and the game will recognize the text inside them and act accordingly. A list of all available uniques can be found here . Generated Documentation This part of the wiki is human-edited and partially out of date. However, we now have automatically generated documentation, complete for all Uniques that have been updated to the new UniqueType system. It is part of the main source tree and can be found here. . This version should always be up-to-date with the uniques and conditionals currently supported in the game. Unique locations Most uniques are \"Global uniques\" - meaning, they can be put in one of these places: - Nation uniques - Always active for a specific Nation - Policy uniques - Active once the policy has been chosen - Building uniques - Active once the building has been constructed in any city - Tech uniques - Active once the tech has been researched - Era uniques - Active once in the specified era - Religion uniques - Founder & Enhancer beliefs from your religion Most uniques are ongoing - they describe something continuous. Some, however, are one-time actions (free technology, free unit, etc) - these cannot be put in a Nation unique, since unlike the other categories, there is no specific time to activate them. Such uniques will be marked in the documentation as \"one time effect\". Parameter types Parameters come in various types, and will be addressed as such inside the [square brackets]. amount - This indicates a whole number, possibly with a + or - sign, such as \"2\", \"+13\", or \"-3\". unitName, buildingName, improvementName etc - Rather self explanatory. Examples: \"Warrior\", \"Library\", and \"Mine\", accordingly. stat - This is one of the 7 major stats in the game - \"Gold\", \"Science\", \"Production\", \"Food\", \"Happiness\", \"Culture\" and \"Faith\". Note that the stat names need to be capitalized! stats, tileFilter, unitFilter, cityFilter, constructionFilter/buildingFilter - these are more complex and are addressed individually stats This indicates a text comprised of specific stats and is slightly more complex. Each stats is comprised of several stat changes, each in the form of \"+{amount} {stat}\", where 'stat' is one of the seven major stats mentioned above. For example: \"+1 Science\". These can be strung together with \", \" between them, for example: \"+2 Production, +3 Food\". A full example would be, for the \"[stats] from every [buildingName]\" unique: \"[+1 Culture, +1 Gold] from every [Barracks]\" tileFilter TileFilters are split up into two parts: terrainFilters and improvementFilters. TerrainFilters only check if the tile itself has certain characteristics, while the improvementFilters only checks the improvement on a tile. Using the tileFilter itself will check both of these. terrainFilters allow us to specify tiles according to a number of different aspects: A filter names a specific json attribute (by name): Base terrain Terrain features Base terrain uniques Terrain feature uniques Resource Natural wonder Or the filter is a constant string choosing a derived test: \"All\" \"Water\", \"Land\" \"Coastal\" (at least one direct neighbor is a coast) \"River\" (as in all 'river on tile' contexts, it means 'adjacent to a river on at least one side') \"Open terrain\", \"Rough terrain\" (note all terrain not having the rough unique is counted as open) \"Friendly Land\" - land belonging to you, or other civs with open borders to you \"Foreign Land\" - any land that isn't friendly land \"Enemy land\" - any land belonging to a civ you are at war with \"Water resource\", \"Strategic resource\", \"Luxury resource\", \"Bonus resource\" \"Natural Wonder\" (as opposed to above which means testing for a specific Natural Wonder by name, this tests for any of them) Please note all of these are case-sensitive . Also note: Resource filters depend on whether a viewing civ is known in the context where the filter runs. Water and specific tests require a viewing civ, and if the resource needs a tech to be visible, that tech to be researched by the viewing civ. The other resource category tests can succeed without a known viewing civ only for resources not requiring any tech. So - test your mod! So for instance, the unique \"[stats] from [tileFilter] tiles [cityFilter]\" can match several cases: - \"[+2 Food] from [Lakes] tiles [in this city]\" - \"[+1 Gold] from [Water] tiles [in all cities]\" - \"[+1 Production] from [Forest] tiles [in all coastal cities]\" Please note that using resources is most use cases, but not in combat ones. This is due to the fact that resources can be visible to some civs while invisible to others - so if you're attacking with a +10% combat bonus from Coal, while the enemy can't see coal, it could get weird. improvementFilters only check for the improvements on a tile. The following are implemented: - improvement name (Note that \"Road\" and \"Railroad\" do work as improvementFilters, but not as tileFilters at the moment.) - \"All\" - \"Great Improvements\", \"Great\" - \"All Road\" - for Roads & Railroads unitFilter unitFilters allow us to activate uniques for specific units, based on: unit name unit type - e.g. Melee, Ranged, WaterSubmarine, etc. \"Land\", \"Water\", \"Air\" \"land units\", \"water units\", \"air units\" \"non-air\" for non-air non-missile units \"Military\", \"military units\" \"Civilian\", \"civilian units\" \"All\" \"Melee\" \"Ranged\" \"Nuclear Weapon\" \"Great Person\", \"Great\" \"Embarked\" \"Wounded\", \"wounded units\" \"Barbarians\", \"Barbarian\" \"City-State\" Any exact unique the unit has Any exact unique the unit type has Any combination of the above (will match only if all match). The format is \"{filter1} {filter2}\" and can match any number of filters. For example: \"[{Military} {Water}]\" units, \"[{Wounded} {Armor}]\" units, etc. No space or other text is allowed between the \"[\" and the first \"{\". cityFilter cityFilters allow us to choose the range of cities affected by this unique: \"in this city\" \"in all cities\" \"in other cities\" \"in all coastal cities\" \"in capital\" \"in all non-occupied cities\" - all cities that are not puppets and don't have extra unhappiness from being recently conquered \"in all cities with a world wonder\" \"in all cities connected to capital\" \"in all cities with a garrison\" \"in non-enemy foreign cities\" - In all cities owned by civs other than you that you are not at war with \"in foreign cities\" \"in annexed cities\" \"in holy cities\" \"in City-State cities\" \"in cities following this religion\" - Should only be used in pantheon/follower uniques for religions \"in all cities in which the majority religion is a major religion\" \"in all cities in which the majority religion is a enhanced religion\" constructionFilter ConstructionFilters allow us to activate uniques while constructing certain buildings or units. For units, the UnitFilter is called. For Buildings, the following options are implemented: \"All\" \"Buildings\", \"Building\" \"Wonders\", \"Wonders\" \"National Wonder\" \"World Wonder\" -- All wonders that are not national wonders building name The name of the building it replaces (so for example uniques for libraries will apply to paper makers as well) an exact unique the building has (e.g.: \"spaceship part\") \"Culture\", \"Gold\", etc. if the building is \"stat-related\" for that stat. Stat-related buildings are defined as one of the following: Provides that stat directly (e.g. +1 Culture) Provides a percentage bonus for that stat (e.g. +10% Production) Provides that stat as a bonus for resources (e.g. +1 Food for Wheat) Provides that stat per some amount of population (e.g. +1 Science for every 2 population [cityFilter]) Conditionals Some uniques also allow for the placing of conditionals. These are conditions that need to be met for the unique to be active. In the unique \"[+10]% Growth \\\", the part is a conditional, denoted by the pointy brackets. Making a building with this unique will provide a 10% Growth boost to cities with this building, but only as long as the empire is at war. Multiple conditionals can be applied to the same unique, for example, you can have a promotion with the following unique: \"[+33]% Strength \\ \\\" Which will only apply the strength boost when fighting armored units in open terrain. This system is currently in development, so only a small amount of conditionals exist, and only a few uniques can have conditionals for now. It will be expanded greatly, improving the amount of combinations that can be made and therefore the amount of different uniques that exist. Uniques that support conditionals will be denoted with a \"\u00a9\" sign for now. \"Quantity of Resources gifted by City-States increased by 100%\" - Replaced with \"Quantity of Resources gifted by City-States increased by [amount]%\"","title":"Uniques"},{"location":"wiki/Uniques/#overview","text":"Every type of object has some traits that are shared across all, or most, objects of its kind. For example, a building's stat increase, cost and required tech; a unit's type, movement and attack; a resource's type, improvement and bonus stats from improvement. All such traits have their own fields in the said object types. But there are also other traits, that are only in a small subset of objects will have. Units that can see submarines from more than one tile away, or can move after attacking, or has a combat bonus against a certain other type of unit. Buildings that give a free great person, or improve stats dependent on the population of a city, or provide extra yield to certain tiles. These traits cannot be given their own fields due to the huge number of them. Instead, every special trait that an object has is encoded into a single parameter: the list of unique traits, or \"uniques\". In the json files, this looks something like \"uniques\": [\"Requires a [Market] in all cities\", \"Cost increases by [30] per owned city\"] . As seen in the above example, in order to provide flexibility and generalization, Uniques have certain parameters , marked by the fact that they are inside square braces. These parameters can be changed, and the game will recognize the text inside them and act accordingly. A list of all available uniques can be found here .","title":"Overview"},{"location":"wiki/Uniques/#generated-documentation","text":"This part of the wiki is human-edited and partially out of date. However, we now have automatically generated documentation, complete for all Uniques that have been updated to the new UniqueType system. It is part of the main source tree and can be found here. . This version should always be up-to-date with the uniques and conditionals currently supported in the game.","title":"Generated Documentation"},{"location":"wiki/Uniques/#unique-locations","text":"Most uniques are \"Global uniques\" - meaning, they can be put in one of these places: - Nation uniques - Always active for a specific Nation - Policy uniques - Active once the policy has been chosen - Building uniques - Active once the building has been constructed in any city - Tech uniques - Active once the tech has been researched - Era uniques - Active once in the specified era - Religion uniques - Founder & Enhancer beliefs from your religion Most uniques are ongoing - they describe something continuous. Some, however, are one-time actions (free technology, free unit, etc) - these cannot be put in a Nation unique, since unlike the other categories, there is no specific time to activate them. Such uniques will be marked in the documentation as \"one time effect\".","title":"Unique locations"},{"location":"wiki/Uniques/#parameter-types","text":"Parameters come in various types, and will be addressed as such inside the [square brackets]. amount - This indicates a whole number, possibly with a + or - sign, such as \"2\", \"+13\", or \"-3\". unitName, buildingName, improvementName etc - Rather self explanatory. Examples: \"Warrior\", \"Library\", and \"Mine\", accordingly. stat - This is one of the 7 major stats in the game - \"Gold\", \"Science\", \"Production\", \"Food\", \"Happiness\", \"Culture\" and \"Faith\". Note that the stat names need to be capitalized! stats, tileFilter, unitFilter, cityFilter, constructionFilter/buildingFilter - these are more complex and are addressed individually","title":"Parameter types"},{"location":"wiki/Uniques/#stats","text":"This indicates a text comprised of specific stats and is slightly more complex. Each stats is comprised of several stat changes, each in the form of \"+{amount} {stat}\", where 'stat' is one of the seven major stats mentioned above. For example: \"+1 Science\". These can be strung together with \", \" between them, for example: \"+2 Production, +3 Food\". A full example would be, for the \"[stats] from every [buildingName]\" unique: \"[+1 Culture, +1 Gold] from every [Barracks]\"","title":"stats"},{"location":"wiki/Uniques/#tilefilter","text":"TileFilters are split up into two parts: terrainFilters and improvementFilters. TerrainFilters only check if the tile itself has certain characteristics, while the improvementFilters only checks the improvement on a tile. Using the tileFilter itself will check both of these. terrainFilters allow us to specify tiles according to a number of different aspects: A filter names a specific json attribute (by name): Base terrain Terrain features Base terrain uniques Terrain feature uniques Resource Natural wonder Or the filter is a constant string choosing a derived test: \"All\" \"Water\", \"Land\" \"Coastal\" (at least one direct neighbor is a coast) \"River\" (as in all 'river on tile' contexts, it means 'adjacent to a river on at least one side') \"Open terrain\", \"Rough terrain\" (note all terrain not having the rough unique is counted as open) \"Friendly Land\" - land belonging to you, or other civs with open borders to you \"Foreign Land\" - any land that isn't friendly land \"Enemy land\" - any land belonging to a civ you are at war with \"Water resource\", \"Strategic resource\", \"Luxury resource\", \"Bonus resource\" \"Natural Wonder\" (as opposed to above which means testing for a specific Natural Wonder by name, this tests for any of them) Please note all of these are case-sensitive . Also note: Resource filters depend on whether a viewing civ is known in the context where the filter runs. Water and specific tests require a viewing civ, and if the resource needs a tech to be visible, that tech to be researched by the viewing civ. The other resource category tests can succeed without a known viewing civ only for resources not requiring any tech. So - test your mod! So for instance, the unique \"[stats] from [tileFilter] tiles [cityFilter]\" can match several cases: - \"[+2 Food] from [Lakes] tiles [in this city]\" - \"[+1 Gold] from [Water] tiles [in all cities]\" - \"[+1 Production] from [Forest] tiles [in all coastal cities]\" Please note that using resources is most use cases, but not in combat ones. This is due to the fact that resources can be visible to some civs while invisible to others - so if you're attacking with a +10% combat bonus from Coal, while the enemy can't see coal, it could get weird. improvementFilters only check for the improvements on a tile. The following are implemented: - improvement name (Note that \"Road\" and \"Railroad\" do work as improvementFilters, but not as tileFilters at the moment.) - \"All\" - \"Great Improvements\", \"Great\" - \"All Road\" - for Roads & Railroads","title":"tileFilter"},{"location":"wiki/Uniques/#unitfilter","text":"unitFilters allow us to activate uniques for specific units, based on: unit name unit type - e.g. Melee, Ranged, WaterSubmarine, etc. \"Land\", \"Water\", \"Air\" \"land units\", \"water units\", \"air units\" \"non-air\" for non-air non-missile units \"Military\", \"military units\" \"Civilian\", \"civilian units\" \"All\" \"Melee\" \"Ranged\" \"Nuclear Weapon\" \"Great Person\", \"Great\" \"Embarked\" \"Wounded\", \"wounded units\" \"Barbarians\", \"Barbarian\" \"City-State\" Any exact unique the unit has Any exact unique the unit type has Any combination of the above (will match only if all match). The format is \"{filter1} {filter2}\" and can match any number of filters. For example: \"[{Military} {Water}]\" units, \"[{Wounded} {Armor}]\" units, etc. No space or other text is allowed between the \"[\" and the first \"{\".","title":"unitFilter"},{"location":"wiki/Uniques/#cityfilter","text":"cityFilters allow us to choose the range of cities affected by this unique: \"in this city\" \"in all cities\" \"in other cities\" \"in all coastal cities\" \"in capital\" \"in all non-occupied cities\" - all cities that are not puppets and don't have extra unhappiness from being recently conquered \"in all cities with a world wonder\" \"in all cities connected to capital\" \"in all cities with a garrison\" \"in non-enemy foreign cities\" - In all cities owned by civs other than you that you are not at war with \"in foreign cities\" \"in annexed cities\" \"in holy cities\" \"in City-State cities\" \"in cities following this religion\" - Should only be used in pantheon/follower uniques for religions \"in all cities in which the majority religion is a major religion\" \"in all cities in which the majority religion is a enhanced religion\"","title":"cityFilter"},{"location":"wiki/Uniques/#constructionfilter","text":"ConstructionFilters allow us to activate uniques while constructing certain buildings or units. For units, the UnitFilter is called. For Buildings, the following options are implemented: \"All\" \"Buildings\", \"Building\" \"Wonders\", \"Wonders\" \"National Wonder\" \"World Wonder\" -- All wonders that are not national wonders building name The name of the building it replaces (so for example uniques for libraries will apply to paper makers as well) an exact unique the building has (e.g.: \"spaceship part\") \"Culture\", \"Gold\", etc. if the building is \"stat-related\" for that stat. Stat-related buildings are defined as one of the following: Provides that stat directly (e.g. +1 Culture) Provides a percentage bonus for that stat (e.g. +10% Production) Provides that stat as a bonus for resources (e.g. +1 Food for Wheat) Provides that stat per some amount of population (e.g. +1 Science for every 2 population [cityFilter])","title":"constructionFilter"},{"location":"wiki/Uniques/#conditionals","text":"Some uniques also allow for the placing of conditionals. These are conditions that need to be met for the unique to be active. In the unique \"[+10]% Growth \\\", the part is a conditional, denoted by the pointy brackets. Making a building with this unique will provide a 10% Growth boost to cities with this building, but only as long as the empire is at war. Multiple conditionals can be applied to the same unique, for example, you can have a promotion with the following unique: \"[+33]% Strength \\ \\\" Which will only apply the strength boost when fighting armored units in open terrain. This system is currently in development, so only a small amount of conditionals exist, and only a few uniques can have conditionals for now. It will be expanded greatly, improving the amount of combinations that can be made and therefore the amount of different uniques that exist. Uniques that support conditionals will be denoted with a \"\u00a9\" sign for now. \"Quantity of Resources gifted by City-States increased by 100%\" - Replaced with \"Quantity of Resources gifted by City-States increased by [amount]%\"","title":"Conditionals"},{"location":"wiki/Unit-related-JSON-files/","text":"Units.json UnitPromotions.json UnitTypes.json Units.json Link to original This file should contain a list of all the units, both military and civilian, that you want to use in your mod. Each unit can have the following attributes: | attribute | Type | optional or not | notes | | --------- | ---- | -------- | ----- | | name | String | required | The name of the units (required) | | unitType | String | required | The type of the unit. Must be in UnitTypes.json | | cost | Integer (\u22650) | defaults to 0 | The amount of production required to build this unit | | movement | Integer (\u22650) | defaults to 0 | The amount of movement points the unit has by default | | strength | Integer (\u22650) | defaults to 0 | The melee attack and defensive strength of the unit. If this and rangedStrength are ommited or 0, the unit will be a civilian | | rangedStrength | Integer (\u22650) | defaults to 0 | The ranged attack strength of the unit. If omitted, the unit cannot ranged attack | | range | Integer (\u22650) | defaults to 2 | The default range from which ranged attacks can be preformed | | interceptRange | Integer (\u22650) | defaults to 0 | Air units attacking within in this range will be intercepted | | requiredTech | String | defaults to none | The tech required to build this unit. Must be in Techs.json | | obsoleteTech | String | defaults to none | After researching this tech, the unit can no longer be build. Must be in Techs.json | | requiredResource | String | defaults to none | Resource that is consumed by building this unit. Must be in TileResources.json | | upgradesTo | String | defaults to none | Unit that this unit can upgrade to when it is available. Must be in Units.json | | replaces | String | defaults to none | If this unit is unique to a nation, this is the unit it replaces. Must be in Units.json | | uniqueTo | String | defaults to none | The nation that this unit is unique to. Must be in Nations.json | | hurryCostModifier | Integer | defaults to 0 | If this unit is bought for gold/faith, it's price is increased by so much percent | | promotions | List of Strings | defaults to none | A list of all the promotions the unit automatically receives upon being built. Each promotion must be in UnitPromotions.json | | uniques | List of Strings | defaults to none | A list of the unique abilities this unit has. A list of almost all uniques can be found here | | replacementTextForUniques | String | defaults to none | If provided, this will be displayed instead of the list of uniques. Can be used for better formatting. | | attackSound | String | defaults to none | The sound that is to be played when this unit attacks. For possible values, see sounds | civilopediaText | List | Default empty | see civilopediaText chapter | UnitPromotions.json Link to original This file lists the available unit promotions. Each promotion must have an icon, except progressions ending in \" I\", \" II\", \" III\" (no IV V VI allowed) are rendered by looking up an icon without those suffixes and adding stars. Remember, promotions can be \"bought\" with XP, but also granted by the unit type, buildings, wonders and such. They are preserved when a unit upgrades, therefore special properties of nation unique units that can be inherited when they upgrade should be in a promotion, not uniques/stats in the units json (example: Slinger withdraw). Each promotion can have the following properties: | Attribute | Type | Optional? | Notes | |-----------|------|-----------|-------| | name | String | Required | See above for \"I, II, III\" progressions | | prerequisites | List | Default empty | Prerequisite promotions | | effect | String | Default empty | Deprecated, use uniques instead | | unitTypes | List | Default empty | The unit types for which this promotion applies as specified in UnitTypes.json | | uniques | List | Default empty | List of effects, see here | | civilopediaText | List | Default empty | see civilopediaText chapter | UnitTypes.json Link to original This optional file is used for defining new types of units. The names of these can be used in unitFilters, and these types determine what domain the unit moves in: over land, over water or through the air. If the file is ommitted, the following are automatically added: Civilian, Melee, Ranged, Scout, Mounted, Armor, Siege, WaterCivilian, WaterMelee, WaterRanged, WaterSubmarine, WaterAircraftCarrier, Fighter, Bomber, AtomicBomber, and Missile. attribute Type optional or not notes name String required The name of the unit type movementType String required The domain through which the unit moves. Allowed values: \"Water\", \"Land\", \"Air\" uniques List of String defaults to none A list of the unique abilities every unit of this type has. A list of almost all uniques can be found here Sounds Standard values are below. The sounds themselves can be found here . arrow, artillery, bombard, bombing, cannon, chimes, choir, click, coin, construction, elephant, fortify, gdrAttack, horse, jetgun, machinegun, metalhit, missile, nonmetalhit, nuke, paper, policy, promote, setup, shipguns, shot, slider, swap, tankshot, throw, torpedo, upgrade, whoosh . Mods can add their own sounds, as long as any new value in attackSound has a corresponding sound file in the mod's sound folder, using one of the formats mp3, ogg or wav (file name extension must match codec used). Remember, names are case sensitive. Small sizes strongly recommended, Unciv's own sounds use 24kHz joint stereo 8-bit VBR at about 50-100kBps.","title":"Unit related JSON files"},{"location":"wiki/Unit-related-JSON-files/#unitsjson","text":"Link to original This file should contain a list of all the units, both military and civilian, that you want to use in your mod. Each unit can have the following attributes: | attribute | Type | optional or not | notes | | --------- | ---- | -------- | ----- | | name | String | required | The name of the units (required) | | unitType | String | required | The type of the unit. Must be in UnitTypes.json | | cost | Integer (\u22650) | defaults to 0 | The amount of production required to build this unit | | movement | Integer (\u22650) | defaults to 0 | The amount of movement points the unit has by default | | strength | Integer (\u22650) | defaults to 0 | The melee attack and defensive strength of the unit. If this and rangedStrength are ommited or 0, the unit will be a civilian | | rangedStrength | Integer (\u22650) | defaults to 0 | The ranged attack strength of the unit. If omitted, the unit cannot ranged attack | | range | Integer (\u22650) | defaults to 2 | The default range from which ranged attacks can be preformed | | interceptRange | Integer (\u22650) | defaults to 0 | Air units attacking within in this range will be intercepted | | requiredTech | String | defaults to none | The tech required to build this unit. Must be in Techs.json | | obsoleteTech | String | defaults to none | After researching this tech, the unit can no longer be build. Must be in Techs.json | | requiredResource | String | defaults to none | Resource that is consumed by building this unit. Must be in TileResources.json | | upgradesTo | String | defaults to none | Unit that this unit can upgrade to when it is available. Must be in Units.json | | replaces | String | defaults to none | If this unit is unique to a nation, this is the unit it replaces. Must be in Units.json | | uniqueTo | String | defaults to none | The nation that this unit is unique to. Must be in Nations.json | | hurryCostModifier | Integer | defaults to 0 | If this unit is bought for gold/faith, it's price is increased by so much percent | | promotions | List of Strings | defaults to none | A list of all the promotions the unit automatically receives upon being built. Each promotion must be in UnitPromotions.json | | uniques | List of Strings | defaults to none | A list of the unique abilities this unit has. A list of almost all uniques can be found here | | replacementTextForUniques | String | defaults to none | If provided, this will be displayed instead of the list of uniques. Can be used for better formatting. | | attackSound | String | defaults to none | The sound that is to be played when this unit attacks. For possible values, see sounds | civilopediaText | List | Default empty | see civilopediaText chapter |","title":"Units.json"},{"location":"wiki/Unit-related-JSON-files/#unitpromotionsjson","text":"Link to original This file lists the available unit promotions. Each promotion must have an icon, except progressions ending in \" I\", \" II\", \" III\" (no IV V VI allowed) are rendered by looking up an icon without those suffixes and adding stars. Remember, promotions can be \"bought\" with XP, but also granted by the unit type, buildings, wonders and such. They are preserved when a unit upgrades, therefore special properties of nation unique units that can be inherited when they upgrade should be in a promotion, not uniques/stats in the units json (example: Slinger withdraw). Each promotion can have the following properties: | Attribute | Type | Optional? | Notes | |-----------|------|-----------|-------| | name | String | Required | See above for \"I, II, III\" progressions | | prerequisites | List | Default empty | Prerequisite promotions | | effect | String | Default empty | Deprecated, use uniques instead | | unitTypes | List | Default empty | The unit types for which this promotion applies as specified in UnitTypes.json | | uniques | List | Default empty | List of effects, see here | | civilopediaText | List | Default empty | see civilopediaText chapter |","title":"UnitPromotions.json"},{"location":"wiki/Unit-related-JSON-files/#unittypesjson","text":"Link to original This optional file is used for defining new types of units. The names of these can be used in unitFilters, and these types determine what domain the unit moves in: over land, over water or through the air. If the file is ommitted, the following are automatically added: Civilian, Melee, Ranged, Scout, Mounted, Armor, Siege, WaterCivilian, WaterMelee, WaterRanged, WaterSubmarine, WaterAircraftCarrier, Fighter, Bomber, AtomicBomber, and Missile. attribute Type optional or not notes name String required The name of the unit type movementType String required The domain through which the unit moves. Allowed values: \"Water\", \"Land\", \"Air\" uniques List of String defaults to none A list of the unique abilities every unit of this type has. A list of almost all uniques can be found here","title":"UnitTypes.json"},{"location":"wiki/Unit-related-JSON-files/#sounds","text":"Standard values are below. The sounds themselves can be found here . arrow, artillery, bombard, bombing, cannon, chimes, choir, click, coin, construction, elephant, fortify, gdrAttack, horse, jetgun, machinegun, metalhit, missile, nonmetalhit, nuke, paper, policy, promote, setup, shipguns, shot, slider, swap, tankshot, throw, torpedo, upgrade, whoosh . Mods can add their own sounds, as long as any new value in attackSound has a corresponding sound file in the mod's sound folder, using one of the formats mp3, ogg or wav (file name extension must match codec used). Remember, names are case sensitive. Small sizes strongly recommended, Unciv's own sounds use 24kHz joint stereo 8-bit VBR at about 50-100kBps.","title":"Sounds"},{"location":"wiki/_Footer/","text":"To edit this wiki, open a pull request against the files under /docs/wiki in the main Unciv repository. ( Details )","title":" Footer"},{"location":"wiki/_Sidebar/","text":"Home Installing on macOS Translating Modding Mods Making a new Civilization Creating a custom tileset JSON files for mods Uniques Images and texture atlas Audiovisual Mods Development Getting Started Coding standards Project structure and major classes Building locally without Android Studio From code to deployment","title":"[Home](.)"},{"location":"wiki/_Sidebar/#home","text":"","title":"Home"},{"location":"wiki/_Sidebar/#installing-on-macos","text":"","title":"Installing on macOS"},{"location":"wiki/_Sidebar/#translating","text":"","title":"Translating"},{"location":"wiki/_Sidebar/#modding","text":"Mods Making a new Civilization Creating a custom tileset JSON files for mods Uniques Images and texture atlas Audiovisual Mods","title":"Modding"},{"location":"wiki/_Sidebar/#development","text":"Getting Started Coding standards Project structure and major classes Building locally without Android Studio From code to deployment","title":"Development"}]} \ No newline at end of file diff --git a/site/sitemap.xml b/site/sitemap.xml new file mode 100644 index 0000000000..ec6d5cc9d4 --- /dev/null +++ b/site/sitemap.xml @@ -0,0 +1,143 @@ + + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + + None + 2022-02-23 + daily + + \ No newline at end of file diff --git a/site/sitemap.xml.gz b/site/sitemap.xml.gz new file mode 100644 index 0000000000..de60c39b68 Binary files /dev/null and b/site/sitemap.xml.gz differ diff --git a/site/unique parameters/index.html b/site/unique parameters/index.html new file mode 100644 index 0000000000..a045b0129b --- /dev/null +++ b/site/unique parameters/index.html @@ -0,0 +1,1379 @@ + + + + + + + + + + + + + + + + Unique parameters - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + + + + +
    +
    + + + + +

    Unique parameters

    + +

    This page contains an overview of all different parameters used in uniques and what values can be filled into them. +Each of the different parameter types is described below, including all possible values for them. +These are split into two categories: +- descriptions: e.g., "the name of any unit" +- Text that looks like this. This last one must be used exactly the same +Note that all of these are case-sensitive!

    +

    action

    +

    An action that a unit can preform. Currently, there are only two actions part of this: +- Spread Religion +- Remove Foreign religions from your own cities

    +

    amount

    +

    This indicates a whole number, possibly with a + or - sign, such as 2, +13, or -3.

    +

    baseTerrain

    +

    The name of any terrain that is a base terrain according to the json file.

    +

    baseUnitFilter

    +

    Unit filters can be divided up into two parts: baseUnitFilters and mapUnitFilters. +The former is tested against the unit as it appears in the json. +This means it doesn't have an owning civ or tile it stands on, just its base properties. +The latter is tested against the unit as it appears on the map, including its nation, tile, health and all other properties.

    +

    The following are allowed to be used: +- unit name +- unit type - e.g. Melee, Ranged, WaterSubmarine, etc. +- Land, Water, Air +- land units, water units, air units +- non-air for non-air non-missile units +- Military, military units +- Civilian, civilian units +- All +- Melee +- Ranged +- Nuclear Weapon +- Great Person, Great +- Embarked +- Any exact unique the unit has +- Any exact unique the unit type has +- Any combination of the above (will match only if all match). The format is {filter1} {filter2} and can match any number of filters. For example: [{Military} {Water}] units, [{non-air} {Armor}] units, etc. No space or other text is allowed between the [ and the first {.

    +

    belief

    +

    The name of any belief

    +

    beliefType

    +

    Pantheon, Follower, Founder or Enhancer.

    +

    buildingFilter

    +

    Allows to only activate a unique for certain buildings. Allowed options are:

    +
      +
    • All
    • +
    • Buildings, Building
    • +
    • Wonders, Wonders
    • +
    • National Wonder
    • +
    • World Wonder -- All wonders that are not national wonders
    • +
    • building name
    • +
    • The name of the building it replaces (so for example uniques for libraries will apply to paper makers as well)
    • +
    • an exact unique the building has (e.g.: spaceship part)
    • +
    • Culture, Gold, etc. if the building is stat-related for that stat. Stat-related buildings are defined as one of the following:
    • +
    • Provides that stat directly (e.g. +1 Culture)
    • +
    • Provides a percentage bonus for that stat (e.g. +10% Production)
    • +
    • Provides that stat as a bonus for resources (e.g. +1 Food from every Wheat)
    • +
    • Provides that stat per some amount of population (e.g. +1 Science for every 2 population [cityFilter])
    • +
    +

    buildingName

    +

    The name of any one building

    +

    cityFilter

    +

    cityFilters allow us to choose the range of cities affected by this unique:

    +
      +
    • in this city
    • +
    • in all cities
    • +
    • in other cities
    • +
    • in all coastal cities
    • +
    • in capital
    • +
    • in all non-occupied cities - all cities that are not puppets and don't have extra unhappiness from being recently conquered
    • +
    • in all cities with a world wonder
    • +
    • in all cities connected to capital
    • +
    • in all cities with a garrison
    • +
    • in non-enemy foreign cities - In all cities owned by civs other than you that you are not at war with
    • +
    • in foreign cities
    • +
    • in annexed cities
    • +
    • in holy cities
    • +
    • in City-State cities
    • +
    • in cities following this religion - Should only be used in pantheon/follower uniques for religions
    • +
    • in all cities in which the majority religion is a major religion
    • +
    • in all cities in which the majority religion is a enhanced religion
    • +
    +

    combatantFilter

    +

    This indicates a combatant, which can either be a unit or a city (when bombarding). +Must either be City or a mapUnitFilter.

    +

    constructionFilter

    +

    A filter for used when testing the current construction of a city. All values of baseUnitFilter and buildingFilter are allowed.

    +

    costOrStrength

    +

    Cost or Strength

    +

    era

    +

    The name of any era

    +

    foundingOrEnhancing

    +

    founding or enhancing

    +

    great person

    +

    The name of any great person

    +

    improvementFilter

    +

    For filtering a specific improvement.

    +

    Allowed values are: +- improvement name (Note that "Road" and "Railroad" do work as improvementFilters, but not as tileFilters at the moment.) +- All +- Great Improvements, Great +- All Road - for Roads & Railroads

    +

    improvementName

    +

    The name of any improvement

    +

    mapUnitFilter

    +

    This indicates a unit as placed on the map. Compare with baseUnitFilter. +It can be any value noted in baseUnitFilter or one of the following: +- Wounded, wounded units +- City-State +- Barbarians, Barbarian +- Again, any combination of the above is also allowed, e.g. [{Wounded} {Water}] units.

    +

    plunderableStat

    +

    All the following stats can be plundered: Gold, Science, Culture, Faith

    +

    policy

    +

    The name of any policy

    +

    promotion

    +

    The name of any promotion

    +

    regionType

    +

    Used for dividing the world into regions in each of which a single player is placed at the start of the game. +Allowed values are Hybrid and the name of any terrain that has one of the following two uniques: +- A Region is formed with at least [amount]% [simpleTerrain] tiles, with priority [amount] +- A Region is formed with at least [amount]% [simpleTerrain] tiles and [simpleTerrain] tiles, with priority [amount]

    +

    resource

    +

    The name of any resource

    +

    simpleTerrain

    +

    Used by NaturalWonderGenerator to place natural wonders

    +

    Allowed values are: +- Land +- Water +- Elevated +- The name of any terrain

    +

    specialist

    +

    The name of any specialist

    +

    stats

    +

    This indicates a text comprised of specific stats and is slightly more complex.

    +

    Each stats is comprised of several stat changes, each in the form of +{amount} {stat}, where 'stat' is one of the seven major stats mentioned above. +For example: +1 Science.

    +

    These can be strung together with ", " between them, for example: +2 Production, +3 Food.

    +

    stat

    +

    This is one of the 7 major stats in the game - Gold, Science, Production, Food, Happiness, Culture and Faith. Note that the stat names need to be capitalized!

    +

    tech

    +

    The name of any tech

    +

    terrainFilter

    +

    This indicates the terrain on a single tile. The following values are allowed:

    +
      +
    • A filter names a specific json attribute (by name):
        +
      • Base terrain
      • +
      • Terrain features
      • +
      • Base terrain uniques
      • +
      • Terrain feature uniques
      • +
      • Resource
      • +
      • Natural wonder
      • +
      +
    • +
    • Or the filter is a constant string choosing a derived test:
        +
      • All
      • +
      • Water, Land
      • +
      • Coastal (at least one direct neighbor is a coast)
      • +
      • River (as in all 'river on tile' contexts, it means 'adjacent to a river on at least one side')
      • +
      • Open terrain, Rough terrain (note all terrain not having the rough unique is counted as open)
      • +
      • Friendly Land - land belonging to you, or other civs with open borders to you
      • +
      • Foreign Land - any land that isn't friendly land
      • +
      • Enemy land - any land belonging to a civ you are at war with
      • +
      • Water resource, Strategic resource, Luxury resource, Bonus resource
      • +
      • Natural Wonder (as opposed to above which means testing for a specific Natural Wonder by name, this tests for any of them)
      • +
      +
    • +
    +

    Please note all of these are case-sensitive.

    +

    Also note: Resource filters depend on whether a viewing civ is known in the context where the filter runs. Water and specific tests require a viewing civ, and if the resource needs a tech to be visible, that tech to be researched by the viewing civ. The other resource category tests can succeed without a known viewing civ only for resources not requiring any tech. So - test your mod!

    +

    So for instance, the unique "[stats] from [tileFilter] tiles [cityFilter]" can match several cases:

    +

    terrainQuality

    +

    Used to indicate for what use the terrain should be viewed when dividing the world into regions, in each of which a single player is placed at the start of the game.

    +

    Allowed values are: +- improvement name (Note that "Road" and "Railroad" do work as improvementFilters, but not as tileFilters at the moment.) +- "All" +- "Great Improvements", "Great" +- "All Road" - for Roads & Railroads

    +

    tileFilter

    +

    Anything that can be used either in an improvementFilter or in a tileFilter can be used here

    +

    victoryType

    +

    The name of any victory type: +- Neutral +- Cultural +- Diplomatic +- Domination +- Scientific +- Time

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/uniques/index.html b/site/uniques/index.html new file mode 100644 index 0000000000..bd7406b235 --- /dev/null +++ b/site/uniques/index.html @@ -0,0 +1,7348 @@ + + + + + + + + + + + + + + + + Uniques - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Uniques

    + +

    Table of Contents

    + +

    Triggerable uniques

    +

    🔷 Free [baseUnitFilter] appears

    +

    Example: "Free [Melee] appears"

    +

    Applicable to: Triggerable

    +

    🔷 [amount] free [baseUnitFilter] units appear

    +

    Example: "[20] free [Melee] units appear"

    +

    Applicable to: Triggerable

    +

    🔷 Free Social Policy

    +

    Applicable to: Triggerable

    +

    🔷 [amount] Free Social Policies

    +

    Example: "[20] Free Social Policies"

    +

    Applicable to: Triggerable

    +

    🔷 Empire enters golden age

    +

    Applicable to: Triggerable

    +

    🔷 Free Great Person

    +

    Applicable to: Triggerable

    +

    🔷 [amount] population [cityFilter]

    +

    Example: "[20] population [in all cities]"

    +

    Applicable to: Triggerable

    +

    🔷 Free Technology

    +

    Applicable to: Triggerable

    +

    🔷 [amount] Free Technologies

    +

    Example: "[20] Free Technologies"

    +

    Applicable to: Triggerable

    +

    🔷 Reveals the entire map

    +

    Applicable to: Triggerable

    +

    🔷 Triggers voting for the Diplomatic Victory

    +

    Applicable to: Triggerable

    +

    🔷 This Unit gains the [promotion] promotion

    +

    Example: "This Unit gains the [Shock I] promotion"

    +

    Applicable to: Triggerable

    +

    🔷 [mapUnitFilter] units gain the [promotion] promotion

    +

    Example: "[Wounded] units gain the [Shock I] promotion"

    +

    Applicable to: Triggerable

    +

    🔷 Provides the cheapest [stat] building in your first [amount] cities for free

    +

    Example: "Provides the cheapest [Culture] building in your first [20] cities for free"

    +

    Applicable to: Triggerable

    +

    🔷 Provides a [buildingName] in your first [amount] cities for free

    +

    Example: "Provides a [Library] in your first [20] cities for free"

    +

    Applicable to: Triggerable

    +

    🔷 Will not be displayed in Civilopedia

    +

    Applicable to: Triggerable, Global, Nation, Era, Tech, Policy, FounderBelief, FollowerBelief, Building, Wonder, Unit, UnitType, Promotion, Terrain, Improvement, Resource, Ruins, CityState, ModOptions, Conditional

    +

    Global uniques

    +

    🔷 [stats]

    +

    Example: "[+1 Gold, +2 Production]"

    +

    Applicable to: Global, FollowerBelief, Improvement

    +

    🔷 [stats] [cityFilter]

    +

    Example: "[+1 Gold, +2 Production] [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [stats] from every specialist [cityFilter]

    +

    Example: "[+1 Gold, +2 Production] from every specialist [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [stats] per [amount] population [cityFilter]

    +

    Example: "[+1 Gold, +2 Production] per [20] population [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [stats] in cities with [amount] or more population

    +

    Example: "[+1 Gold, +2 Production] in cities with [20] or more population"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [stats] in cities on [terrainFilter] tiles

    +

    Example: "[+1 Gold, +2 Production] in cities on [Forest] tiles"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [stats] from all [buildingFilter] buildings

    +

    Example: "[+1 Gold, +2 Production] from all [Culture] buildings"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [stats] whenever a Great Person is expended

    +

    Example: "[+1 Gold, +2 Production] whenever a Great Person is expended"

    +

    Applicable to: Global

    +

    🔷 [stats] from [tileFilter] tiles [cityFilter]

    +

    Example: "[+1 Gold, +2 Production] from [Farm] tiles [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [stats] from [tileFilter] tiles without [tileFilter] [cityFilter]

    +

    Example: "[+1 Gold, +2 Production] from [Farm] tiles without [Farm] [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [stats] from every [tileFilter/specialist/buildingFilter]

    +

    Example: "[+1 Gold, +2 Production] from every [tileFilter/specialist/buildingFilter]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [stats] from each Trade Route

    +

    Example: "[+1 Gold, +2 Production] from each Trade Route"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% [stat]

    +

    Example: "[20]% [Culture]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% [stat] [cityFilter]

    +

    Example: "[20]% [Culture] [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% [stat] from every [tileFilter/specialist/buildingName]

    +

    Example: "[20]% [Culture] from every [tileFilter/specialist/buildingName]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% Yield from every [tileFilter]

    +

    Example: "[20]% Yield from every [Farm]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% [stat] from City-States

    +

    Example: "[20]% [Culture] from City-States"

    +

    Applicable to: Global

    +

    🔷 Gold from all trade routes +25%

    +

    Applicable to: Global

    +

    🔷 Nullifies [stat] [cityFilter]

    +

    Example: "Nullifies [Culture] [in all cities]"

    +

    Applicable to: Global

    +

    🔷 Nullifies Growth [cityFilter]

    +

    Example: "Nullifies Growth [in all cities]"

    +

    Applicable to: Global

    +

    🔷 [amount]% Production when constructing [buildingFilter] wonders [cityFilter]

    +

    Example: "[20]% Production when constructing [Culture] wonders [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% Production when constructing [buildingFilter] buildings [cityFilter]

    +

    Example: "[20]% Production when constructing [Culture] buildings [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% Production when constructing [baseUnitFilter] units [cityFilter]

    +

    Example: "[20]% Production when constructing [Melee] units [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% Production towards any buildings that already exist in the Capital

    +

    Example: "[20]% Production towards any buildings that already exist in the Capital"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 Tile yields from Natural Wonders doubled

    +

    Applicable to: Global

    +

    🔷 Military Units gifted from City-States start with [amount] XP

    +

    Example: "Military Units gifted from City-States start with [20] XP"

    +

    Applicable to: Global

    +

    🔷 Militaristic City-States grant units [amount] times as fast when you are at war with a common nation

    +

    Example: "Militaristic City-States grant units [20] times as fast when you are at war with a common nation"

    +

    Applicable to: Global

    +

    🔷 Gifts of Gold to City-States generate [amount]% more Influence

    +

    Example: "Gifts of Gold to City-States generate [20]% more Influence"

    +

    Applicable to: Global

    +

    🔷 Can spend Gold to annex or puppet a City-State that has been your ally for [amount] turns.

    +

    Example: "Can spend Gold to annex or puppet a City-State that has been your ally for [20] turns."

    +

    Applicable to: Global

    +

    🔷 City-State territory always counts as friendly territory

    +

    Applicable to: Global

    +

    🔷 Allied City-States will occasionally gift Great People

    +

    Applicable to: Global

    +

    🔷 [amount]% City-State Influence degradation

    +

    Example: "[20]% City-State Influence degradation"

    +

    Applicable to: Global

    +

    🔷 Resting point for Influence with City-States is increased by [amount]

    +

    Example: "Resting point for Influence with City-States is increased by [20]"

    +

    Applicable to: Global

    +

    🔷 Allied City-States provide [stat] equal to [amount]% of what they produce for themselves

    +

    Example: "Allied City-States provide [Culture] equal to [20]% of what they produce for themselves"

    +

    Applicable to: Global

    +

    🔷 [amount]% resources gifted by City-States

    +

    Example: "[20]% resources gifted by City-States"

    +

    Applicable to: Global

    +

    🔷 [amount]% Happiness from luxury resources gifted by City-States

    +

    Example: "[20]% Happiness from luxury resources gifted by City-States"

    +

    Applicable to: Global

    +

    🔷 City-State Influence recovers at twice the normal rate

    +

    Applicable to: Global

    +

    🔷 [amount] units cost no maintenance

    +

    Example: "[20] units cost no maintenance"

    +

    Applicable to: Global

    +

    🔷 Cannot build [baseUnitFilter] units

    +

    Example: "Cannot build [Melee] units"

    +

    Applicable to: Global

    +

    🔷 [amount]% growth [cityFilter]

    +

    Example: "[20]% growth [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% Food is carried over after population increases [cityFilter]

    +

    Example: "[20]% Food is carried over after population increases [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 Gain a free [buildingName] [cityFilter]

    +

    Example: "Gain a free [Library] [in all cities]"

    +

    Applicable to: Global

    +

    🔷 [amount]% Great Person generation [cityFilter]

    +

    Example: "[20]% Great Person generation [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% great person generation [cityFilter]

    +

    Example: "[20]% great person generation [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 May choose [amount] additional [beliefType] beliefs when [foundingOrEnhancing] a religion

    +

    Example: "May choose [20] additional [Follower] beliefs when [founding] a religion"

    +

    Applicable to: Global

    +

    🔷 May choose [amount] additional belief(s) of any type when [foundingOrEnhancing] a religion

    +

    Example: "May choose [20] additional belief(s) of any type when [founding] a religion"

    +

    Applicable to: Global

    +

    🔷 [amount]% unhappiness from population [cityFilter]

    +

    Example: "[20]% unhappiness from population [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% unhappiness from specialists [cityFilter]

    +

    Example: "[20]% unhappiness from specialists [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% Food consumption by specialists [cityFilter]

    +

    Example: "[20]% Food consumption by specialists [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 Provides 1 happiness per 2 additional social policies adopted

    +

    Applicable to: Global

    +

    🔷 [amount]% of excess happiness converted to [stat]

    +

    Example: "[20]% of excess happiness converted to [Culture]"

    +

    Applicable to: Global

    +

    🔷 [amount]% Culture cost of natural border growth [cityFilter]

    +

    Example: "[20]% Culture cost of natural border growth [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% Gold cost of acquiring tiles [cityFilter]

    +

    Example: "[20]% Gold cost of acquiring tiles [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] at an increasing price ([amount])

    +

    Example: "May buy [Melee] units for [20] [Culture] [in all cities] at an increasing price ([20])"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 May buy [buildingFilter] buildings for [amount] [stat] [cityFilter] at an increasing price ([amount])

    +

    Example: "May buy [Culture] buildings for [20] [Culture] [in all cities] at an increasing price ([20])"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 May buy [baseUnitFilter] units for [amount] [stat] [cityFilter]

    +

    Example: "May buy [Melee] units for [20] [Culture] [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 May buy [buildingFilter] buildings for [amount] [stat] [cityFilter]

    +

    Example: "May buy [Culture] buildings for [20] [Culture] [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 May buy [baseUnitFilter] units with [stat] [cityFilter]

    +

    Example: "May buy [Melee] units with [Culture] [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 May buy [buildingFilter] buildings with [stat] [cityFilter]

    +

    Example: "May buy [Culture] buildings with [Culture] [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 May buy [baseUnitFilter] units with [stat] for [amount] times their normal Production cost

    +

    Example: "May buy [Melee] units with [Culture] for [20] times their normal Production cost"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 May buy [buildingFilter] buildings with [stat] for [amount] times their normal Production cost

    +

    Example: "May buy [Culture] buildings with [Culture] for [20] times their normal Production cost"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 Enables conversion of city production to gold

    +

    Applicable to: Global

    +

    🔷 Enables conversion of city production to science

    +

    Applicable to: Global

    +

    🔷 [stat] cost of purchasing items in cities [amount]%

    +

    Example: "[Culture] cost of purchasing items in cities [20]%"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [stat] cost of purchasing [buildingFilter] buildings [amount]%

    +

    Example: "[Culture] cost of purchasing [Culture] buildings [20]%"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [stat] cost of purchasing [baseUnitFilter] units [amount]%

    +

    Example: "[Culture] cost of purchasing [Melee] units [20]%"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 Improves movement speed on roads

    +

    Applicable to: Global

    +

    🔷 Roads connect tiles across rivers

    +

    Applicable to: Global

    +

    🔷 [amount]% maintenance on road & railroads

    +

    Example: "[20]% maintenance on road & railroads"

    +

    Applicable to: Global

    +

    🔷 [amount]% maintenance cost for buildings [cityFilter]

    +

    Example: "[20]% maintenance cost for buildings [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 Receive a free Great Person at the end of every [comment] (every 394 years), after researching [tech]. Each bonus person can only be chosen once.

    +

    Example: "Receive a free Great Person at the end of every [comment] (every 394 years), after researching [Agriculture]. Each bonus person can only be chosen once."

    +

    Applicable to: Global

    +

    🔷 Once The Long Count activates, the year on the world screen displays as the traditional Mayan Long Count.

    +

    Applicable to: Global

    +

    🔷 Retain [amount]% of the happiness from a luxury after the last copy has been traded away

    +

    Example: "Retain [20]% of the happiness from a luxury after the last copy has been traded away"

    +

    Applicable to: Global

    +

    🔷 [amount] Happiness from each type of luxury resource

    +

    Example: "[20] Happiness from each type of luxury resource"

    +

    Applicable to: Global

    +

    🔷 Each city founded increases culture cost of policies [amount]% less than normal

    +

    Example: "Each city founded increases culture cost of policies [20]% less than normal"

    +

    Applicable to: Global

    +

    🔷 [amount]% Culture cost of adopting new Policies

    +

    Example: "[20]% Culture cost of adopting new Policies"

    +

    Applicable to: Global

    +

    🔷 Quantity of strategic resources produced by the empire +[amount]%

    +

    Example: "Quantity of strategic resources produced by the empire +[20]%"

    +

    Applicable to: Global

    +

    🔷 Double quantity of [resource] produced

    +

    Example: "Double quantity of [Iron] produced"

    +

    Applicable to: Global

    +

    🔷 Double Happiness from Natural Wonders

    +

    Applicable to: Global

    +

    🔷 Enables construction of Spaceship parts

    +

    Applicable to: Global

    +

    🔷 Enemy land units must spend 1 extra movement point when inside your territory (obsolete upon Dynamite)

    +

    Applicable to: Global

    +

    🔷 Production to science conversion in cities increased by 33%

    +

    Applicable to: Global

    +

    🔷 Notified of new Barbarian encampments

    +

    Applicable to: Global

    +

    🔷 "Borrows" city names from other civilizations in the game

    +

    Applicable to: Global

    +

    🔷 Units fight as though they were at full strength even when damaged

    +

    Applicable to: Global

    +

    🔷 100 Gold for discovering a Natural Wonder (bonus enhanced to 500 Gold if first to discover it)

    +

    Applicable to: Global

    +

    🔷 Unhappiness from number of Cities doubled

    +

    Applicable to: Global

    +

    🔷 Great General provides double combat bonus

    +

    Applicable to: Global

    +

    🔷 Receive a tech boost when scientific buildings/wonders are built in capital

    +

    Applicable to: Global

    +

    🔷 May not generate great prophet equivalents naturally

    +

    Applicable to: Global

    +

    🔷 67% chance to earn 25 Gold and recruit a Barbarian unit from a conquered encampment

    +

    Applicable to: Global

    +

    🔷 50% chance of capturing defeated Barbarian naval units and earning 25 Gold

    +

    Applicable to: Global

    +

    🔷 Receive triple Gold from Barbarian encampments and pillaging Cities

    +

    Applicable to: Global

    +

    🔷 Enables Open Borders agreements

    +

    Applicable to: Global

    +

    🔷 Enables Research agreements

    +

    Applicable to: Global

    +

    🔷 Science gained from research agreements [amount]%

    +

    Example: "Science gained from research agreements [20]%"

    +

    Applicable to: Global

    +

    🔷 Triggers victory

    +

    Applicable to: Global

    +

    🔷 Triggers a Cultural Victory upon completion

    +

    Applicable to: Global

    +

    🔷 [amount]% City Strength from defensive buildings

    +

    Example: "[20]% City Strength from defensive buildings"

    +

    Applicable to: Global

    +

    🔷 [amount]% tile improvement construction time

    +

    Example: "[20]% tile improvement construction time"

    +

    Applicable to: Global

    +

    🔷 [amount]% Gold from Great Merchant trade missions

    +

    Example: "[20]% Gold from Great Merchant trade missions"

    +

    Applicable to: Global

    +

    🔷 [mapUnitFilter] Units adjacent to this city heal [amount] HP per turn when healing

    +

    Example: "[Wounded] Units adjacent to this city heal [20] HP per turn when healing"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [amount]% Golden Age length

    +

    Example: "[20]% Golden Age length"

    +

    Applicable to: Global

    +

    🔷 [amount]% Strength for cities

    +

    Example: "[20]% Strength for cities"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 New [baseUnitFilter] units start with [amount] Experience [cityFilter]

    +

    Example: "New [Melee] units start with [20] Experience [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 All newly-trained [baseUnitFilter] units [cityFilter] receive the [promotion] promotion

    +

    Example: "All newly-trained [Melee] units [in all cities] receive the [Shock I] promotion"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 [baseUnitFilter] units built [cityFilter] can [action] [amount] extra times

    +

    Example: "[Melee] units built [in all cities] can [action] [20] extra times"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 Enables embarkation for land units

    +

    Applicable to: Global

    +

    🔷 Enables embarked units to enter ocean tiles

    +

    Applicable to: Global

    +

    🔷 Population loss from nuclear attacks [amount]% [cityFilter]

    +

    Example: "Population loss from nuclear attacks [20]% [in all cities]"

    +

    Applicable to: Global

    +

    🔷 [amount]% Natural religion spread [cityFilter]

    +

    Example: "[20]% Natural religion spread [in all cities]"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 Religion naturally spreads to cities [amount] tiles away

    +

    Example: "Religion naturally spreads to cities [20] tiles away"

    +

    Applicable to: Global, FollowerBelief

    +

    🔷 Can be continually researched

    +

    Applicable to: Global

    +

    🔷 [amount] Unit Supply

    +

    Example: "[20] Unit Supply"

    +

    Applicable to: Global

    +

    🔷 [amount] Unit Supply per [amount] population [cityFilter]

    +

    Example: "[20] Unit Supply per [20] population [in all cities]"

    +

    Applicable to: Global

    +

    🔷 [amount] Unit Supply per city

    +

    Example: "[20] Unit Supply per city"

    +

    Applicable to: Global

    +

    🔷 Units in cities cost no Maintenance

    +

    Applicable to: Global

    +

    🔷 Rebel units may spawn

    +

    Applicable to: Global

    +

    🔷 [amount]% Strength

    +

    Example: "[20]% Strength"

    +

    Applicable to: Global, Unit

    +

    🔷 [amount]% Strength decreasing with distance from the capital

    +

    Example: "[20]% Strength decreasing with distance from the capital"

    +

    Applicable to: Global, Unit

    +

    🔷 [amount]% to Flank Attack bonuses

    +

    Example: "[20]% to Flank Attack bonuses"

    +

    Applicable to: Global, Unit

    +

    🔷 +30% Strength when fighting City-State units and cities

    +

    Applicable to: Global

    +

    🔷 [amount] Movement

    +

    Example: "[20] Movement"

    +

    Applicable to: Global, Unit

    +

    🔷 [amount] Sight

    +

    Example: "[20] Sight"

    +

    Applicable to: Global, Unit, Terrain

    +

    🔷 [amount] Range

    +

    Example: "[20] Range"

    +

    Applicable to: Global, Unit

    +

    🔷 [amount] HP when healing

    +

    Example: "[20] HP when healing"

    +

    Applicable to: Global, Unit

    +

    🔷 [amount]% Spread Religion Strength

    +

    Example: "[20]% Spread Religion Strength"

    +

    Applicable to: Global, Unit

    +

    🔷 No defensive terrain bonus

    +

    Applicable to: Global, Unit

    +

    🔷 No defensive terrain penalty

    +

    Applicable to: Global, Unit

    +

    🔷 No movement cost to pillage

    +

    Applicable to: Global, Unit

    +

    🔷 May heal outside of friendly territory

    +

    Applicable to: Global, Unit

    +

    🔷 All healing effects doubled

    +

    Applicable to: Global, Unit

    +

    🔷 Heals [amount] damage if it kills a unit

    +

    Example: "Heals [20] damage if it kills a unit"

    +

    Applicable to: Global, Unit

    +

    🔷 Can only heal by pillaging

    +

    Applicable to: Global, Unit

    +

    🔷 Normal vision when embarked

    +

    Applicable to: Global, Unit

    +

    🔷 Defense bonus when embarked

    +

    Applicable to: Global, Unit

    +

    🔷 Embarked units can defend themselves

    +

    Applicable to: Global

    +

    🔷 [amount]% maintenance costs

    +

    Example: "[20]% maintenance costs"

    +

    Applicable to: Global, Unit

    +

    🔷 [amount]% Gold cost of upgrading

    +

    Example: "[20]% Gold cost of upgrading"

    +

    Applicable to: Global, Unit

    +

    🔷 [greatPerson] is earned [amount]% faster

    +

    Example: "[greatPerson] is earned [20]% faster"

    +

    Applicable to: Global, Unit

    +

    🔷 Earn [amount]% of the damage done to [mapUnitFilter] units as [plunderableStat]

    +

    Example: "Earn [20]% of the damage done to [Wounded] units as [Gold]"

    +

    Applicable to: Global, Unit

    +

    🔷 Upon capturing a city, receive [amount] times its [stat] production as [plunderableStat] immediately

    +

    Example: "Upon capturing a city, receive [20] times its [Culture] production as [Gold] immediately"

    +

    Applicable to: Global, Unit

    +

    🔷 Earn [amount]% of killed [mapUnitFilter] unit's [costOrStrength] as [plunderableStat]

    +

    Example: "Earn [20]% of killed [Wounded] unit's [Cost] as [Gold]"

    +

    Applicable to: Global, Unit

    +

    🔷 [amount] XP gained from combat

    +

    Example: "[20] XP gained from combat"

    +

    Applicable to: Global, Unit

    +

    🔷 [amount]% XP gained from combat

    +

    Example: "[20]% XP gained from combat"

    +

    Applicable to: Global, Unit

    +

    🔷 This Unit upgrades for free

    +

    Applicable to: Global

    +

    Nation uniques

    +

    🔷 Will not be chosen for new games

    +

    Applicable to: Nation

    +

    🔷 Starts with [tech]

    +

    Example: "Starts with [Agriculture]"

    +

    Applicable to: Nation

    +

    Tech uniques

    +

    🔷 Starting tech

    +

    Applicable to: Tech

    +

    🔷 Only available

    +

    Applicable to: Tech, Policy, Building, Unit, Promotion, Improvement

    +

    FollowerBelief uniques

    +

    🔷 [amount]% [stat] from every follower, up to [amount]%

    +

    Example: "[20]% [Culture] from every follower, up to [20]%"

    +

    Applicable to: FollowerBelief

    +

    🔷 Earn [amount]% of [mapUnitFilter] unit's [costOrStrength] as [plunderableStat] when killed within 4 tiles of a city following this religion

    +

    Example: "Earn [20]% of [Wounded] unit's [Cost] as [Gold] when killed within 4 tiles of a city following this religion"

    +

    Applicable to: FollowerBelief

    +

    Building uniques

    +

    🔷 Consumes [amount] [resource]

    +

    Example: "Consumes [20] [Iron]"

    +

    Applicable to: Building, Unit, Improvement

    +

    🔷 Provides [amount] [resource]

    +

    Example: "Provides [20] [Iron]"

    +

    Applicable to: Building, Improvement

    +

    🔷 Unbuildable

    +

    Applicable to: Building, Unit

    +

    🔷 Cannot be purchased

    +

    Applicable to: Building, Unit

    +

    🔷 Can be purchased with [stat] [cityFilter]

    +

    Example: "Can be purchased with [Culture] [in all cities]"

    +

    Applicable to: Building, Unit

    +

    🔷 Can be purchased for [amount] [stat] [cityFilter]

    +

    Example: "Can be purchased for [20] [Culture] [in all cities]"

    +

    Applicable to: Building, Unit

    +

    🔷 Limited to [amount] per Civilization

    +

    Example: "Limited to [20] per Civilization"

    +

    Applicable to: Building, Unit

    +

    🔷 Hidden until [amount] social policy branches have been completed

    +

    Example: "Hidden until [20] social policy branches have been completed"

    +

    Applicable to: Building, Unit

    +

    🔷 Excess Food converted to Production when under construction

    +

    Applicable to: Building, Unit

    +

    🔷 Requires at least [amount] population

    +

    Example: "Requires at least [20] population"

    +

    Applicable to: Building, Unit

    +

    🔷 Cost increases by [amount] per owned city

    +

    Example: "Cost increases by [20] per owned city"

    +

    Applicable to: Building

    +

    🔷 Requires a [buildingName] in all cities

    +

    Example: "Requires a [Library] in all cities"

    +

    Applicable to: Building

    +

    🔷 Requires a [buildingName] in at least [amount] cities

    +

    Example: "Requires a [Library] in at least [20] cities"

    +

    Applicable to: Building

    +

    🔷 Must be on [terrainFilter]

    +

    Example: "Must be on [Forest]"

    +

    Applicable to: Building

    +

    🔷 Must not be on [terrainFilter]

    +

    Example: "Must not be on [Forest]"

    +

    Applicable to: Building

    +

    🔷 Must be next to [terrainFilter]

    +

    Example: "Must be next to [Forest]"

    +

    Applicable to: Building, Improvement

    +

    🔷 Must not be next to [terrainFilter]

    +

    Example: "Must not be next to [Forest]"

    +

    Applicable to: Building

    +

    🔷 Unsellable

    +

    Applicable to: Building

    +

    🔷 Obsolete with [tech]

    +

    Example: "Obsolete with [Agriculture]"

    +

    Applicable to: Building, Improvement, Resource

    +

    🔷 Indicates the capital city

    +

    Applicable to: Building

    +

    🔷 Provides 1 extra copy of each improved luxury resource near this City

    +

    Applicable to: Building

    +

    🔷 Destroyed when the city is captured

    +

    Applicable to: Building

    +

    🔷 Never destroyed when the city is captured

    +

    Applicable to: Building

    +

    🔷 Doubles Gold given to enemy if city is captured

    +

    Applicable to: Building

    +

    🔷 Remove extra unhappiness from annexed cities

    +

    Applicable to: Building

    +

    🔷 Spaceship part

    +

    Applicable to: Building, Unit

    +

    🔷 Hidden when religion is disabled

    +

    Applicable to: Building, Unit, Ruins

    +

    🔷 Hidden when [victoryType] Victory is disabled

    +

    Example: "Hidden when [Domination] Victory is disabled"

    +

    Applicable to: Building, Unit

    +

    Unit uniques

    +

    🔷 Founds a new city

    +

    Applicable to: Unit

    +

    🔷 Can construct [improvementName]

    +

    Example: "Can construct [Trading Post]"

    +

    Applicable to: Unit

    +

    🔷 Can build [improvementFilter/terrainFilter] improvements on tiles

    +

    Example: "Can build [improvementFilter/terrainFilter] improvements on tiles"

    +

    Applicable to: Unit

    +

    🔷 May create improvements on water resources

    +

    Applicable to: Unit

    +

    🔷 May found a religion

    +

    Applicable to: Unit

    +

    🔷 May enhance a religion

    +

    Applicable to: Unit

    +

    🔷 Can only attack [combatantFilter] units

    +

    Example: "Can only attack [City] units"

    +

    Applicable to: Unit

    +

    🔷 Can only attack [tileFilter] tiles

    +

    Example: "Can only attack [Farm] tiles"

    +

    Applicable to: Unit

    +

    🔷 Cannot attack

    +

    Applicable to: Unit

    +

    🔷 Must set up to ranged attack

    +

    Applicable to: Unit

    +

    🔷 Self-destructs when attacking

    +

    Applicable to: Unit

    +

    🔷 Blast radius [amount]

    +

    Example: "Blast radius [20]"

    +

    Applicable to: Unit

    +

    🔷 Ranged attacks may be performed over obstacles

    +

    Applicable to: Unit

    +

    🔷 Uncapturable

    +

    Applicable to: Unit

    +

    🔷 May withdraw before melee ([amount]%)

    +

    Example: "May withdraw before melee ([20]%)"

    +

    Applicable to: Unit

    +

    🔷 Unable to capture cities

    +

    Applicable to: Unit

    +

    🔷 Can move after attacking

    +

    Applicable to: Unit

    +

    🔷 Can move immediately once bought

    +

    Applicable to: Unit

    +

    🔷 Unit will heal every turn, even if it performs an action

    +

    Applicable to: Unit

    +

    🔷 All adjacent units heal [amount] HP when healing

    +

    Example: "All adjacent units heal [20] HP when healing"

    +

    Applicable to: Unit

    +

    🔷 Eliminates combat penalty for attacking across a coast

    +

    Applicable to: Unit

    +

    🔷 6 tiles in every direction always visible

    +

    Applicable to: Unit

    +

    🔷 Can carry [amount] [mapUnitFilter] units

    +

    Example: "Can carry [20] [Wounded] units"

    +

    Applicable to: Unit

    +

    🔷 Can carry [amount] extra [mapUnitFilter] units

    +

    Example: "Can carry [20] extra [Wounded] units"

    +

    Applicable to: Unit

    +

    🔷 Cannot be carried by [mapUnitFilter] units

    +

    Example: "Cannot be carried by [Wounded] units"

    +

    Applicable to: Unit

    +

    🔷 May capture killed [mapUnitFilter] units

    +

    Example: "May capture killed [Wounded] units"

    +

    Applicable to: Unit

    +

    🔷 Invisible to others

    +

    Applicable to: Unit

    +

    🔷 Invisible to non-adjacent units

    +

    Applicable to: Unit

    +

    🔷 Can see invisible [mapUnitFilter] units

    +

    Example: "Can see invisible [Wounded] units"

    +

    Applicable to: Unit

    +

    🔷 May upgrade to [baseUnitFilter] through ruins-like effects

    +

    Example: "May upgrade to [Melee] through ruins-like effects"

    +

    Applicable to: Unit

    +

    🔷 Double movement in [terrainFilter]

    +

    Example: "Double movement in [Forest]"

    +

    Applicable to: Unit

    +

    🔷 All tiles cost 1 movement

    +

    Applicable to: Unit

    +

    🔷 Can pass through impassable tiles

    +

    Applicable to: Unit

    +

    🔷 Ignores terrain cost

    +

    Applicable to: Unit

    +

    🔷 Ignores Zone of Control

    +

    Applicable to: Unit

    +

    🔷 Rough terrain penalty

    +

    Applicable to: Unit

    +

    🔷 Can enter ice tiles

    +

    Applicable to: Unit

    +

    🔷 Cannot enter ocean tiles

    +

    Applicable to: Unit

    +

    🔷 May enter foreign tiles without open borders

    +

    Applicable to: Unit

    +

    🔷 May enter foreign tiles without open borders, but loses [amount] religious strength each turn it ends there

    +

    Example: "May enter foreign tiles without open borders, but loses [20] religious strength each turn it ends there"

    +

    Applicable to: Unit

    +

    🔷 Never appears as a Barbarian unit

    +

    Applicable to: Unit

    +

    🔷 Religious Unit

    +

    Applicable to: Unit

    +

    🔷 Can be added to [comment] in the Capital

    +

    Example: "Can be added to [comment] in the Capital"

    +

    Applicable to: Unit

    +

    Promotion uniques

    +

    🔷 Heal this unit by [amount] HP

    +

    Example: "Heal this unit by [20] HP"

    +

    Applicable to: Promotion

    +

    Terrain uniques

    +

    🔷 Must be adjacent to [amount] [simpleTerrain] tiles

    +

    Example: "Must be adjacent to [20] [Elevated] tiles"

    +

    Applicable to: Terrain

    +

    🔷 Must be adjacent to [amount] to [amount] [simpleTerrain] tiles

    +

    Example: "Must be adjacent to [20] to [20] [Elevated] tiles"

    +

    Applicable to: Terrain

    +

    🔷 Must not be on [amount] largest landmasses

    +

    Example: "Must not be on [20] largest landmasses"

    +

    Applicable to: Terrain

    +

    🔷 Must be on [amount] largest landmasses

    +

    Example: "Must be on [20] largest landmasses"

    +

    Applicable to: Terrain

    +

    🔷 Occurs on latitudes from [amount] to [amount] percent of distance equator to pole

    +

    Example: "Occurs on latitudes from [20] to [20] percent of distance equator to pole"

    +

    Applicable to: Terrain

    +

    🔷 Occurs in groups of [amount] to [amount] tiles

    +

    Example: "Occurs in groups of [20] to [20] tiles"

    +

    Applicable to: Terrain

    +

    🔷 Neighboring tiles will convert to [baseTerrain]

    +

    Example: "Neighboring tiles will convert to [Grassland]"

    +

    Applicable to: Terrain

    +

    🔷 Neighboring tiles except [baseTerrain] will convert to [baseTerrain]

    +

    Example: "Neighboring tiles except [Grassland] will convert to [Grassland]"

    +

    Applicable to: Terrain

    +

    🔷 Grants 500 Gold to the first civilization to discover it

    +

    Applicable to: Terrain

    +

    🔷 Units ending their turn on this terrain take [amount] damage

    +

    Example: "Units ending their turn on this terrain take [20] damage"

    +

    Applicable to: Terrain

    +

    🔷 Grants [promotion] ([comment]) to adjacent [mapUnitFilter] units for the rest of the game

    +

    Example: "Grants [Shock I] ([comment]) to adjacent [Wounded] units for the rest of the game"

    +

    Applicable to: Terrain

    +

    🔷 [amount] Strength for cities built on this terrain

    +

    Example: "[20] Strength for cities built on this terrain"

    +

    Applicable to: Terrain

    +

    🔷 Provides a one-time Production bonus to the closest city when cut down

    +

    Applicable to: Terrain

    +

    🔷 Tile provides yield without assigned population

    +

    Applicable to: Terrain, Improvement

    +

    🔷 Nullifies all other stats this tile provides

    +

    Applicable to: Terrain

    +

    🔷 Only [improvementFilter] improvements may be built on this tile

    +

    Example: "Only [All Road] improvements may be built on this tile"

    +

    Applicable to: Terrain

    +

    🔷 Blocks line-of-sight from tiles at same elevation

    +

    Applicable to: Terrain

    +

    🔷 Has an elevation of [amount] for visibility calculations

    +

    Example: "Has an elevation of [20] for visibility calculations"

    +

    Applicable to: Terrain

    +

    🔷 Always Fertility [amount] for Map Generation

    +

    Example: "Always Fertility [20] for Map Generation"

    +

    Applicable to: Terrain

    +

    🔷 [amount] to Fertility for Map Generation

    +

    Example: "[20] to Fertility for Map Generation"

    +

    Applicable to: Terrain

    +

    🔷 A Region is formed with at least [amount]% [simpleTerrain] tiles, with priority [amount]

    +

    Example: "A Region is formed with at least [20]% [Elevated] tiles, with priority [20]"

    +

    Applicable to: Terrain

    +

    🔷 A Region is formed with at least [amount]% [simpleTerrain] tiles and [simpleTerrain] tiles, with priority [amount]

    +

    Example: "A Region is formed with at least [20]% [Elevated] tiles and [Elevated] tiles, with priority [20]"

    +

    Applicable to: Terrain

    +

    🔷 A Region can not contain more [simpleTerrain] tiles than [simpleTerrain] tiles

    +

    Example: "A Region can not contain more [Elevated] tiles than [Elevated] tiles"

    +

    Applicable to: Terrain

    +

    🔷 Base Terrain on this tile is not counted for Region determination

    +

    Applicable to: Terrain

    +

    🔷 Starts in regions of this type receive an extra [resource]

    +

    Example: "Starts in regions of this type receive an extra [Iron]"

    +

    Applicable to: Terrain

    +

    🔷 Never receives any resources

    +

    Applicable to: Terrain

    +

    🔷 Becomes [terrainName] when adjacent to [terrainFilter]

    +

    Example: "Becomes [terrainName] when adjacent to [Forest]"

    +

    Applicable to: Terrain

    +

    🔷 Considered [terrainQuality] when determining start locations

    +

    Example: "Considered [Undesirable] when determining start locations"

    +

    Applicable to: Terrain

    +

    🔷 Doesn't generate naturally

    +

    Applicable to: Terrain, Resource

    +

    🔷 Occurs at temperature between [amount] and [amount] and humidity between [amount] and [amount]

    +

    Example: "Occurs at temperature between [20] and [20] and humidity between [20] and [20]"

    +

    Applicable to: Terrain

    +

    🔷 Occurs in chains at high elevations

    +

    Applicable to: Terrain

    +

    🔷 Occurs in groups around high elevations

    +

    Applicable to: Terrain

    +

    🔷 Every [amount] tiles with this terrain will receive a major deposit of a strategic resource.

    +

    Example: "Every [20] tiles with this terrain will receive a major deposit of a strategic resource."

    +

    Applicable to: Terrain

    +

    🔷 Rare feature

    +

    Applicable to: Terrain

    +

    🔷 Resistant to nukes

    +

    Applicable to: Terrain

    +

    🔷 Can be destroyed by nukes

    +

    Applicable to: Terrain

    +

    🔷 Fresh water

    +

    Applicable to: Terrain

    +

    🔷 Rough terrain

    +

    Applicable to: Terrain

    +

    Improvement uniques

    +

    🔷 Can also be built on tiles adjacent to fresh water

    +

    Applicable to: Improvement

    +

    🔷 [stats] from [tileFilter] tiles

    +

    Example: "[+1 Gold, +2 Production] from [Farm] tiles"

    +

    Applicable to: Improvement

    +

    🔷 [stats] for each adjacent [tileFilter]

    +

    Example: "[+1 Gold, +2 Production] for each adjacent [Farm]"

    +

    Applicable to: Improvement

    +

    🔷 Can be built outside your borders

    +

    Applicable to: Improvement

    +

    🔷 Can be built just outside your borders

    +

    Applicable to: Improvement

    +

    🔷 Cannot be built on [tileFilter] tiles

    +

    Example: "Cannot be built on [Farm] tiles"

    +

    Applicable to: Improvement

    +

    🔷 Does not need removal of [tileFilter]

    +

    Example: "Does not need removal of [Farm]"

    +

    Applicable to: Improvement

    +

    🔷 Gives a defensive bonus of [amount]%

    +

    Example: "Gives a defensive bonus of [20]%"

    +

    Applicable to: Improvement

    +

    🔷 Costs [amount] gold per turn when in your territory

    +

    Example: "Costs [20] gold per turn when in your territory"

    +

    Applicable to: Improvement

    +

    🔷 Adjacent enemy units ending their turn take [amount] damage

    +

    Example: "Adjacent enemy units ending their turn take [20] damage"

    +

    Applicable to: Improvement

    +

    🔷 Great Improvement

    +

    Applicable to: Improvement

    +

    🔷 Provides a random bonus when entered

    +

    Applicable to: Improvement

    +

    🔷 Unpillagable

    +

    Applicable to: Improvement

    +

    🔷 Indestructible

    +

    Applicable to: Improvement

    +

    🔷 Irremovable

    +

    Applicable to: Improvement

    +

    Resource uniques

    +

    🔷 Generated with weight [amount]

    +

    Example: "Generated with weight [20]"

    +

    Applicable to: Resource

    +

    🔷 Minor deposits generated with weight [amount]

    +

    Example: "Minor deposits generated with weight [20]"

    +

    Applicable to: Resource

    +

    🔷 Generated near City States with weight [amount]

    +

    Example: "Generated near City States with weight [20]"

    +

    Applicable to: Resource

    +

    🔷 Special placement during map generation

    +

    Applicable to: Resource

    +

    🔷 Generated on every [amount] tiles

    +

    Example: "Generated on every [20] tiles"

    +

    Applicable to: Resource

    +

    🔷 Guaranteed with Strategic Balance resource option

    +

    Applicable to: Resource

    +

    🔷 Deposits in [tileFilter] tiles always provide [amount] resources

    +

    Example: "Deposits in [Farm] tiles always provide [20] resources"

    +

    Applicable to: Resource

    +

    🔷 Can only be created by Mercantile City-States

    +

    Applicable to: Resource

    +

    Ruins uniques

    +

    🔷 Free [baseUnitFilter] found in the ruins

    +

    Example: "Free [Melee] found in the ruins"

    +

    Applicable to: Ruins

    +

    🔷 [amount] population in a random city

    +

    Example: "[20] population in a random city"

    +

    Applicable to: Ruins

    +

    🔷 [amount] free random researchable Tech(s) from the [era]

    +

    Example: "[20] free random researchable Tech(s) from the [Ancient era]"

    +

    Applicable to: Ruins

    +

    🔷 Gain [amount] [stat]

    +

    Example: "Gain [20] [Culture]"

    +

    Applicable to: Ruins

    +

    🔷 Gain [amount]-[amount] [stat]

    +

    Example: "Gain [20]-[20] [Culture]"

    +

    Applicable to: Ruins

    +

    🔷 Gain enough Faith for a Pantheon

    +

    Applicable to: Ruins

    +

    🔷 Gain enough Faith for [amount]% of a Great Prophet

    +

    Example: "Gain enough Faith for [20]% of a Great Prophet"

    +

    Applicable to: Ruins

    +

    🔷 Reveal up to [amount/'all'] [tileFilter] within a [amount] tile radius

    +

    Example: "Reveal up to [amount/'all'] [Farm] within a [20] tile radius"

    +

    Applicable to: Ruins

    +

    🔷 From a randomly chosen tile [amount] tiles away from the ruins, reveal tiles up to [amount] tiles away with [amount]% chance

    +

    Example: "From a randomly chosen tile [20] tiles away from the ruins, reveal tiles up to [20] tiles away with [20]% chance"

    +

    Applicable to: Ruins

    +

    🔷 This Unit gains [amount] XP

    +

    Example: "This Unit gains [20] XP"

    +

    Applicable to: Ruins

    +

    🔷 This Unit upgrades for free including special upgrades

    +

    Applicable to: Ruins

    +

    🔷 Only available after [amount] turns

    +

    Example: "Only available after [20] turns"

    +

    Applicable to: Ruins

    +

    🔷 Hidden before founding a Pantheon

    +

    Applicable to: Ruins

    +

    🔷 Hidden after founding a Pantheon

    +

    Applicable to: Ruins

    +

    🔷 Hidden after generating a Great Prophet

    +

    Applicable to: Ruins

    +

    CityState uniques

    +

    🔷 Provides [stats] per turn

    +

    Example: "Provides [+1 Gold, +2 Production] per turn"

    +

    Applicable to: CityState

    +

    🔷 Provides [stats] [cityFilter] per turn

    +

    Example: "Provides [+1 Gold, +2 Production] [in all cities] per turn"

    +

    Applicable to: CityState

    +

    🔷 Provides [amount] Happiness

    +

    Example: "Provides [20] Happiness"

    +

    Applicable to: CityState

    +

    🔷 Provides military units every ≈[amount] turns

    +

    Example: "Provides military units every ≈[20] turns"

    +

    Applicable to: CityState

    +

    🔷 Provides a unique luxury

    +

    Applicable to: CityState

    +

    Conditional uniques

    +

    🔷

    +

    Applicable to: Conditional

    +

    🔷

    +

    Applicable to: Conditional

    +

    🔷

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Applicable to: Conditional

    +

    🔷

    +

    Applicable to: Conditional

    +

    🔷

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    🔷

    +

    Example: ""

    +

    Applicable to: Conditional

    +

    Deprecated uniques

    +
      +
    • "[stats] from every Wonder" - Deprecated as of 3.19.1, replace with "[stats] from every [Wonder]"
    • +
    • "[stats] from every [buildingFilter] in cities where this religion has at least [amount] followers" - Deprecated as of 3.19.3, replace with "[stats] from every [buildingFilter] "
    • +
    • "+25% Production towards any buildings that already exist in the Capital" - Deprecated as of 3.19.3, replace with "[+25]% Production towards any buildings that already exist in the Capital"
    • +
    • "[amount]% of food is carried over after population increases" - Deprecated as of 3.19.2, replace with "[amount]% Food is carried over after population increases [in this city]"
    • +
    • "[amount]% of food is carried over [cityFilter] after population increases" - Deprecated as of 3.19.2, replace with "[amount]% Food is carried over after population increases [cityFilter]"
    • +
    • "[amount]% Culture cost of natural border growth [cityFilter]" - Deprecated as of 3.19.2, replace with "[amount]% Culture cost of natural border growth [cityFilter]"
    • +
    • "-[amount]% Culture cost of acquiring tiles [cityFilter]" - Deprecated as of 3.19.1, replace with "[-amount]% Culture cost of natural border growth [cityFilter]"
    • +
    • "[amount]% cost of natural border growth" - Deprecated as of 3.19.1, replace with "[amount]% Culture cost of natural border growth [in all cities]"
    • +
    • "-[amount]% Gold cost of acquiring tiles [cityFilter]" - Deprecated as of 3.19.1, replace with "[-amount]% Gold cost of acquiring tiles [cityFilter]"
    • +
    • "[stat] cost of purchasing [baseUnitFilter] units in cities [amount]%" - Deprecated as of 3.19.3, replace with "[stat] cost of purchasing [baseUnitFilter] units [amount]%"
    • +
    • "+[amount]% attacking strength for cities with garrisoned units" - Deprecated as of 3.19.1, replace with "[+amount]% Strength for cities "
    • +
    • "Can embark and move over Coasts and Oceans immediately" - Deprecated as of 3.19.9, replace with "Enables embarkation for land units ", "Enables embarked units to enter ocean tiles "
    • +
    • "Population loss from nuclear attacks -[amount]%" - Deprecated as of 3.19.2, replace with "Population loss from nuclear attacks [-amount]% [in this city]"
    • +
    • "[amount]% Natural religion spread [cityFilter] with [tech/policy]" - Deprecated as of 3.19.3, replace with "[amount]% Natural religion spread [cityFilter] " OR "[amount]% Natural religion spread [cityFilter] "
    • +
    • "[amount] HP when healing in [tileFilter] tiles" - Deprecated as of 3.19.4, replace with "[amount] HP when healing "
    • +
    • "Melee units pay no movement cost to pillage" - Deprecated as of 3.18.17, replace with "No movement cost to pillage "
    • +
    • "Heal adjacent units for an additional 15 HP per turn" - Deprecated as of 3.19.3, replace with "All adjacent units heal [+15] HP when healing"
    • +
    • "+[amount]% attack strength to all [mapUnitFilter] units for [amount2] turns" - Deprecated as of 3.19.8, replace with "[+amount]% Strength "
    • +
    • "Golden Age length increased by [amount]%" - Deprecated as of 3.18.17, replace with "[+amount]% Golden Age length"
    • +
    • "+[amount]% Defensive Strength for cities" - Deprecated as of 3.18.17, replace with "[+amount]% Strength for cities "
    • +
    • "[amount]% Attacking Strength for cities" - Deprecated as of 3.18.17, replace with "[+amount]% Strength for cities "
    • +
    • "[amount]% Strength for [mapUnitFilter] units which have another [mapUnitFilter] unit in an adjacent tile" - Deprecated as of 3.18.17, replace with "[amount]% Strength "
    • +
    • "Gold cost of upgrading [baseUnitFilter] units reduced by [amount]%" - Deprecated as of 3.18.17, replace with "[-amount]% Gold cost of upgrading "
    • +
    • "Double gold from Great Merchant trade missions" - Deprecated as of 3.18.17, replace with "[+100]% Gold from Great Merchant trade missions"
    • +
    • "Defensive buildings in all cities are 25% more effective" - Deprecated as of 3.18.17, replace with "[+25]% City Strength from defensive buildings"
    • +
    • "Maintenance on roads & railroads reduced by [amount]%" - Deprecated as of 3.18.17, replace with "[-amount]% maintenance on road & railroads"
    • +
    • "-[amount]% maintenance cost for buildings [cityFilter]" - Deprecated as of 3.18.17, replace with "[-amount]% maintenance cost for buildings [cityFilter]"
    • +
    • "+[amount] happiness from each type of luxury resource" - Deprecated as of 3.18.17, replace with "[+amount] Happiness from each type of luxury resource"
    • +
    • "Culture cost of adopting new Policies reduced by [amount]%" - Deprecated as of 3.18.17, replace with "[-amount]% Culture cost of adopting new Policies"
    • +
    • "[amount]% Culture cost of adopting new policies" - Deprecated as of 3.19.1, replace with "[amount]% Culture cost of adopting new Policies"
    • +
    • "Quantity of Resources gifted by City-States increased by [amount]%" - Deprecated as of 3.18.17, replace with "[+amount]% resources gifted by City-States"
    • +
    • "City-State Influence degrades [amount]% slower" - Deprecated as of 3.18.17, replace with "[-amount]% City-State Influence degradation"
    • +
    • "Happiness from Luxury Resources gifted by City-States increased by [amount]%" - Deprecated as of 3.18.17, replace with "[+amount]% Happiness from luxury resources gifted by City-States"
    • +
    • "+[amount]% [stat] from every [tileFilter/specialist/buildingName]" - Deprecated as of 3.18.17, replace with "[+amount]% [stat] from every [tileFilter/specialist/buildingName]"
    • +
    • "+[amount]% yield from every [tileFilter]" - Deprecated as of 3.18.17, replace with "[+amount]% Yield from every [tileFilter]"
    • +
    • "[stats] per turn from cities before [tech/policy]" - Deprecated as of 3.18.14, replace with "[stats] [in all cities] " OR "[stats] [in all cities] "
    • +
    • "[mapUnitFilter] units gain [amount]% more Experience from combat" - Deprecated as of 3.18.12, replace with "[amount]% XP gained from combat "
    • +
    • "[amount]% maintenance costs for [mapUnitFilter] units" - Deprecated as of 3.18.14, replace with "[amount]% maintenance costs "
    • +
    • "50% of excess happiness added to culture towards policies" - Deprecated as of 3.18.2, replace with "[50]% of excess happiness converted to [Culture]"
    • +
    • "-[amount]% food consumption by specialists [cityFilter]" - Deprecated as of 3.18.2, replace with "[-amount]% Food consumption by specialists [cityFilter]"
    • +
    • "May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] starting from the [era] at an increasing price ([amount])" - Deprecated as of 3.17.9, removed as of 3.19.3, replace with "May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] at an increasing price ([amount]) "
    • +
    • "Provides a free [buildingName] [cityFilter]" - Deprecated as of 3.17.7 - removed 3.18.19, replace with "Gain a free [buildingName] [cityFilter]"
    • +
    • "+[amount]% [stat] [cityFilter]" - Deprecated as of 3.17.10 - removed 3.18.18, replace with "[+amount]% [stat] [cityFilter]"
    • +
    • "+[amount]% [stat] in all cities" - Deprecated as of 3.17.10 - removed 3.18.18, replace with "[+amount]% [stat] [in all cities]"
    • +
    • "[amount]% [stat] while the empire is happy" - Deprecated as of 3.17.1 - removed 3.18.18, replace with "[amount]% [stat] [in all cities] "
    • +
    • "Immediately creates the cheapest available cultural building in each of your first [amount] cities for free" - Deprecated as of 3.16.15 - removed 3.18.4, replace with "Provides the cheapest [stat] building in your first [amount] cities for free"
    • +
    • "Immediately creates a [buildingName] in each of your first [amount] cities for free" - Deprecated as of 3.16.15 - removed 3.18.4, replace with "Provides a [buildingName] in your first [amount] cities for free"
    • +
    • "[mapUnitFilter] units deal +[amount]% damage" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[+amount]% Strength "
    • +
    • "+10% Strength for all units during Golden Age" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[+10]% Strength "
    • +
    • "[amount]% Strength for [mapUnitFilter] units in [tileFilter]" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[amount]% Strength "
    • +
    • "+15% Combat Strength for all units when attacking Cities" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[+15]% Strength "
    • +
    • "+[amount] Movement for all [mapUnitFilter] units" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[+amount] Movement "
    • +
    • "+1 Movement for all units during Golden Age" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[+1] Movement "
    • +
    • "[amount] Sight for all [mapUnitFilter] units" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[amount] Sight "
    • +
    • "[amount]% Spread Religion Strength for [mapUnitFilter] units" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[amount]% Spread Religion Strength "
    • +
    • "+[amount]% Production when constructing [baseUnitFilter] units [cityFilter]" - Deprecated as of 3.17.10 - removed 3.18.5, replace with "[+amount]% Production when constructing [baseUnitFilter] units [cityFilter]"
    • +
    • "+[amount]% Production when constructing [stat] buildings" - Deprecated as of 3.17.10 - removed 3.18.5, replace with "[+amount]% Production when constructing [stat] buildings [in all cities]"
    • +
    • "+[amount]% Production when constructing [constructionFilter]" - Deprecated as of 3.17.10 - removed 3.18.5, replace with "[+amount]% Production when constructing [constructionFilter] buildings [in all cities]"
    • +
    • "+[amount]% Production when constructing a [buildingName]" - Deprecated as of 3.17.10 - removed 3.18.5, replace with "[amount]% Production when constructing [buildingName] buildings [in all cities]"
    • +
    • "+[amount]% Production when constructing [constructionFilter] [cityFilter]" - Deprecated as of 3.17.10 - removed 3.18.5, replace with "[amount]% Production when constructing [constructionFilter] buildings [cityFilter]"
    • +
    • "Increases embarked movement +1" - Deprecated As of 3.16.11 - removed 3.17.11, replace with "[+1] Movement "
    • +
    • "+1 Movement for all embarked units" - Deprecated As of 3.16.11 - removed 3.17.11, replace with "[+1] Movement "
    • +
    • "Unhappiness from population decreased by [amount]%" - Deprecated As of 3.16.11 - removed 3.17.11, replace with "[-amount]% unhappiness from population [in all cities]"
    • +
    • "Unhappiness from population decreased by [amount]% [cityFilter]" - Deprecated As of 3.16.11 - removed 3.17.11, replace with "[-amount]% unhappiness from population [cityFilter]"
    • +
    • "+[amount]% growth [cityFilter]" - Deprecated As of 3.16.14 - removed 3.17.11, replace with "[+amount]% growth [cityFilter]"
    • +
    • "+[amount]% growth [cityFilter] when not at war" - Deprecated As of 3.16.14 - removed 3.17.11, replace with "[+amount]% growth [cityFilter] "
    • +
    • "-[amount]% [mapUnitFilter] unit maintenance costs" - Deprecated As of 3.16.16 - removed as of 3.17.11, replace with "[-amount]% maintenance costs "
    • +
    • "-[amount]% unit upkeep costs" - Deprecated As of 3.16.16 - removed 3.17.11, replace with "[amount]% maintenance costs "
    • +
    • "[stats] from every specialist" - Deprecated As of 3.16.16 - removed 3.17.11, replace with "[stats] from every specialist [in all cities]"
    • +
    • "[stats] if this city has at least [amount] specialists" - Deprecated As of 3.16.16 - removed 3.17.11, replace with "[stats] "
    • +
    • "+1 happiness from each type of luxury resource" - Deprecated Extremely old - used for auto-updates only, replace with "[+1] Happiness from each type of luxury resource"
    • +
    • "-33% unit upkeep costs" - Deprecated Extremely old - used for auto-updates only, replace with "[-33]% maintenance costs "
    • +
    • "-50% food consumption by specialists" - Deprecated Extremely old - used for auto-updates only, replace with "[-50]% Food consumption by specialists [in all cities]"
    • +
    • "+50% attacking strength for cities with garrisoned units" - Deprecated Extremely old - used for auto-updates only, replace with "[+50]% Strength for cities "
    • +
    • "Incompatible with [policy/tech/promotion]" - Deprecated as of 3.19.8, replace with "Only available " OR "Only available " OR "Only available "
    • +
    • "Not displayed as an available construction without [buildingName/tech/resource/policy]" - Deprecated as of 3.19.8, replace with "Only available " OR "Only available " OR "Only available " OR "Only available "
    • +
    • "Unlocked with [buildingName/tech/era/policy]" - Deprecated as of 3.19.12, replace with "Only available " OR "Only available " OR "Only available " OR "Only available "
    • +
    • "Requires [buildingName/tech/era/policy]" - Deprecated as of 3.19.12, replace with "Only available " OR "Only available " OR "Only available " OR "Only available "
    • +
    • "Cannot be built with [buildingName]" - Deprecated as of 3.19.9, replace with "Only available "
    • +
    • "Requires a [buildingName] in this city" - Deprecated as of 3.19.9, replace with "Only available "
    • +
    • "[stats] with [resource]" - Deprecated as of 3.19.7, replace with "[stats] "
    • +
    • "Not displayed as an available construction unless [buildingName] is built" - Deprecated as of 3.16.11, replace with "Not displayed as an available construction without [buildingName]"
    • +
    • "[stats] once [tech] is discovered" - Deprecated as of 3.17.10 - removed 3.18.19, replace with "[stats] "
    • +
    • "Eliminates combat penalty for attacking from the sea" - Deprecated as of 3.19.8, replace with "Eliminates combat penalty for attacking across a coast"
    • +
    • "[amount]% Bonus XP gain" - Deprecated as of 3.18.12, replace with "[amount]% XP gained from combat"
    • +
    • "Cannot enter ocean tiles until Astronomy" - Deprecated as of 3.18.6, replace with "Cannot enter ocean tiles "
    • +
    • "+[amount]% Strength when attacking" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[+amount]% Strength "
    • +
    • "+[amount]% Strength when defending" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[+amount]% Strength "
    • +
    • "[amount]% Strength when defending vs [mapUnitFilter] units" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[amount]% Strength "
    • +
    • "+[amount]% defence in [tileFilter] tiles" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[amount]% Strength "
    • +
    • "+[amount]% Strength in [tileFilter]" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[amount]% Strength "
    • +
    • "[amount] Visibility Range" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[amount] Sight"
    • +
    • "Limited Visibility" - Deprecated as of 3.17.5 - removed 3.18.5, replace with "[-1] Sight"
    • +
    • "Double movement in coast" - Deprecated As of 3.17.1 - removed 3.17.13, replace with "Double movement in [Coast]"
    • +
    • "Double movement rate through Forest and Jungle" - Deprecated As of 3.17.1 - removed 3.17.13, replace with "Double movement in [terrainFilter]"
    • +
    • "Double movement in Snow, Tundra and Hills" - Deprecated As of 3.17.1 - removed 3.17.13, replace with "Double movement in [terrainFilter]"
    • +
    • "+[amount]% Strength" - Deprecated As of 3.17.3 - removed 3.17.13, replace with "[+amount]% Strength"
    • +
    • "-[amount]% Strength" - Deprecated As of 3.17.3 - removed 3.17.13, replace with "[-amount]% Strength"
    • +
    • "+[amount]% Strength vs [combatantFilter]" - Deprecated As of 3.17.3 - removed 3.17.13, replace with "[+amount]% Strength " OR "[+amount]% Strength "
    • +
    • "-[amount]% Strength vs [combatantFilter]" - Deprecated As of 3.17.3 - removed 3.17.13, replace with "[-amount]% Strength " OR "[+amount]% Strength "
    • +
    • "+[amount]% Combat Strength" - Deprecated As of 3.17.3 - removed 3.17.13, replace with "[+amount]% Strength"
    • +
    • "+1 Visibility Range" - Deprecated Extremely old - used for auto-updates only, replace with "[+1] Sight"
    • +
    • "+[amount] Visibility Range" - Deprecated Extremely old - used for auto-updates only, replace with "[+amount] Sight"
    • +
    • "+[amount] Sight for all [mapUnitFilter] units" - Deprecated Extremely old - used for auto-updates only, replace with "[+amount] Sight "
    • +
    • "+2 Visibility Range" - Deprecated Extremely old - used for auto-updates only, replace with "[+2] Sight"
    • +
    • "Can build improvements on tiles" - Deprecated Extremely old - used for auto-updates only, replace with "Can build [Land] improvements on tiles"
    • +
    • "Science gained from research agreements +50%" - Deprecated Extremely old - used for auto-updates only, replace with "Science gained from research agreements [+50]%"
    • +
    • "Deal [amount] damage to adjacent enemy units" - Deprecated as of 3.18.17, replace with "Adjacent enemy units ending their turn take [amount] damage"
    • +
    • "Cannot be built on [tileFilter] tiles until [tech] is discovered" - Deprecated as of 3.18.5, replace with "Cannot be built on [tileFilter] tiles "
    • +
    • "[stats] on [tileFilter] tiles once [tech] is discovered" - Deprecated as of 3.17.10 - removed 3.18.19, replace with "[stats] from [tileFilter] tiles "
    • +
    • "Deal 30 damage to adjacent enemy units" - Deprecated as of 3.17.10 - removed 3.18.19, replace with "Adjacent enemy units ending their turn take [30] damage"
    • +
    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Audiovisual-Mods/index.html b/site/wiki/Audiovisual-Mods/index.html new file mode 100644 index 0000000000..343688a48e --- /dev/null +++ b/site/wiki/Audiovisual-Mods/index.html @@ -0,0 +1,1086 @@ + + + + + + + + + + + + + + + + Audiovisual Mods - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + + + + +
    +
    + + + + +

    Audiovisual Mods

    + +

    Permanent audiovisual mods

    +

    The following chapters describe possibilities that will work while a mod is active. It is either selected for the current game (during new game creation, cannot be changed after that for saved games), meaning all its rules and resources will be used. Or it is marked as 'Permanent audiovisual mod' in the mod manager (you must select it in the 'installed' column to get the checkbox). In that case only graphics and audio will be active, the rule changes will be ignored (if it contains any) unless the first way is also used.

    +

    Override built-in graphics

    +

    If a mod supplies an image with the same name and path as one included in the base game (and its atlas is up to date), and the mod is active, the mod's graphics will be used instead of the built-in one.

    +

    For example, if you include a file named "Images/OtherIcons/Link.png" in your mod, you will be overriding the little chain links icon denoting linked lines in Civilopedia.

    +

    Please note, as for adding items, your graphics should keep the size and color choices of the original, or the result may be surprising, e.g. when the game tries to tint such an image.

    +

    Supply additional graphics

    +

    Currently there are two kinds where the game has display capability but does not supply graphics itself, as described in the next paragraphs:

    +

    Adding Wonder Splash Screens

    +

    You can add wonder images to mods and they'll be displayed instead of the standard icon when a wonder is finished. The image needs to be a .png and 2:1 ratio so for example 200x100 px.

    +

    Add the images to /Images/WonderImages/. They need to be named according to the name field in Buildings.json, so for example "Temple of Artemis.png" or "Stonehenge.png"

    +

    Remember, to be compatible with mobile devices, a fresh atlas needs to be generated including these.

    +

    Adding Leader Portraits

    +

    The base game comes without Leader Portraits, but is able to display them in greetings, Civilopedia, diplomacy screens, or the nation picker. A mod can supply these, by adding their images to /Images/LeaderIcons/. The file name must correspond exactly with the leader name of a nation as defined in Nations.json, or they will be ignored.

    +

    These work best if they are square, between 100x100 and 256x256 pixels, and include some transparent border within that area.

    +

    For example, here is mod showing how to add leader portraits, which can complement the base game.

    +

    Override built-in sounds

    +

    This works like graphics, except no atlas is involved. E.g. you include a sounds/Click.mp3, it will play instead of the normal click sound. These files must stay short and small. A sound larger than 1MB when uncompressed may break or not play at all on mobile devices. Unciv tries to standardize on 24kHz sample rate, joint stereo, low-bitrate VBR (-128kbps) mp3. Only mp3 and ogg formats will be recognized (but an existing mp3 can be overridden with an ogg file).

    +

    Supply additional music

    +

    Sound files (mp3 or ogg) in a mod /music folder will be recognized and used when the mod is active. Except for context-specific music as described in the following paragraphs, tracks will play randomly from all available tracks (with a little bias to avoid close repetition of tracks). There is no overriding - a "thatched-villagers.mp3" in a mod will play in addition to and with the same likelihood as the file that the base game offers to download for you. There is no hard technical limit on bitrate or length, but large bandwidth requirements may lead to stuttering (The end of a "next turn", right before the world map is updated, and with very large maps, is the most likely to cause this).

    +

    Context-sensitive music: Overview

    +

    The Music Controller will generally play one track after another, with a pause (can be changed in options) between. Leave-game confirmation dialog is opened playback will fade out and pause and can resume when it is closed.

    +

    There are various 'triggers' in the game code initiating a choice for a new track. The new track will, if necessary, fade out the currently playing track quickly before it starts playing. Track choice involves context provided by the trigger and a random factor, and an attempt is made to not repeat any track until at least eight others have played.

    +

    Mods can provide their own music folder, and if they are active its contents will be treated exactly the same as those in the main music folder. Mods should control usage of their tracks by careful choice of file name. Mod developers can watch console output for messages logging track choice with trigger parameters or loading errors.

    +

    One track is special: The Thatched Villagers (see also credits.md). The game is able to download it if the music folder is empty, and it is played when the music volume slider is used. It is also a fallback track should certain problems occur (a broken file, however, will shut down the player until another trigger happens).

    +

    Context-sensitive music: List of Triggers

    +

    Triggers indicate context (call it intent, mood, whatever, it doesn't matter) by optionally providing a prefix and/or suffix to match against the file name. There are a few flags as well influencing choice or behaviour - one flag function is to make prefix or suffix mandatory, meaning if no available file matches the track chooser will do nothing. Otherwise, a next track will always be chosen from the available list by sorting and then picking the first entry. Sorting is done by in order of precedence: Prefix match, Suffix match, Recently played, and a random number. Therefore, as currently no triggers have an empty prefix, files matching none of the prefixes will never play unless there are less than eight files matching the requested prefix.

    +

    The current list of triggers is as follows:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DescriptionPrefixM[^M]SuffixM[^X]Flags
    Automatic next-track[^0]Ambient
    Launch game[^1]Menu
    Every 10th turn(player civ name)MPeace or War[^2]F[^F]
    New game: Select a mod(mod name)MThemeS[^S]
    New game: Pick a nation for a player(nation name)MTheme or PeaceS[^S]
    Diplomacy: Select player(nation name)MPeace or War[^3]S[^S]
    First contact[^4](civ name)MTheme or PeaceM
    War declaration[^5](civ name)MWarM
    Civ defeated(civ name)DefeatM
    Golden Age(civ name)MGoldenMN[^N]
    Wonder built(wonder name)MBuiltMN[^N]
    Tech researched(tech name)MResearchedMN[^N]
    Map editor: Select nation start location(nation name)MThemeS[^S] N[^N]
    Options: Volume slider or Default track downloadedD[^D]
    Options: Click currently playing label[^6]MAmbientS[^S]
    +

    Legend: +[^N]: Not implemented +[^M]: Prefix must match. If no matching file is found, the trigger will do nothing. +[^X]: Suffix must match. If no matching file is found, the trigger will do nothing. +[^S]: Stop after playback. No automatic next choice. +[^F]: Slow fadeout of replaced track. +[^D]: Always plays the default file. +[^0]: Whenever a track finishes and the configured silence has elapsed, an 'Ambient' track without any context is chosen. Also triggered by 'resume' (e.g. switching to another app and back on Android) +[^1]: First opening of the Main Menu (or the initial language picker). +[^2]: Whether the active player is at war with anybody. +[^3]: According to your relation to the picked player. +[^4]: Excluding City States. +[^5]: Both in the alert when another player declares War on you and declaring War yourself in Diplomacy screen. +[^6]: Yes these flags are not optimal.

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Building-locally-without-Android-Studio/index.html b/site/wiki/Building-locally-without-Android-Studio/index.html new file mode 100644 index 0000000000..f60bbe47d2 --- /dev/null +++ b/site/wiki/Building-locally-without-Android-Studio/index.html @@ -0,0 +1,791 @@ + + + + + + + + + + + + + + + + Building locally without Android Studio - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Building locally without Android Studio

    + +

    If you also have JDK 11 installed, you can compile Unciv on your own by cloning (or downloading and unzipping) the project, opening a terminal in the Unciv folder and run the following commands:

    +

    Windows

    +

    Running: gradlew desktop:run

    +

    Building: gradlew desktop:dist

    +

    Linux/Mac OS

    +

    Running: ./gradlew desktop:run

    +

    Building: ./gradlew desktop:dist

    +

    If the terminal returns Permission denied or Command not found on Mac/Linux, run chmod +x ./gradlew first. This is a one-time procedure.

    +

    If you get an error that Android SDK folder wasn't found, firstly install it by doing in terminal:

    +

    sudo apt update && sudo apt install android-sdk (Debian, Ubuntu, Mint etc.)

    +

    After that you should put its folder to the file local.properties by adding this line:

    +

    sdk.dir = /path/to/android/sdk which can be /usr/lib/android-sdk or something other.

    +

    If during the first launch it throws an error that the JDK version is wrong try this JDK installation.

    +

    Gradle may take up to several minutes to download files. Be patient. +After building, the output .JAR file should be in /desktop/build/libs/Unciv.jar

    +

    For actual development, you'll probably need to download Android Studio and build it yourself - see Contributing :)

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Civilization-related-JSON-files/index.html b/site/wiki/Civilization-related-JSON-files/index.html new file mode 100644 index 0000000000..aef744b196 --- /dev/null +++ b/site/wiki/Civilization-related-JSON-files/index.html @@ -0,0 +1,1306 @@ + + + + + + + + + + + + + + + + Civilization related JSON files - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Civilization related JSON files

    + + +

    Beliefs.json

    +

    link to original

    +

    This file contains the beliefs that can be chosen for religions in your mod.

    +

    Each belief can have the following attributes: +| attribute | Type | Optional or not | notes | +| --------- | ---- | --------------- | ----- | +| name | String | Required | Name of the belief | +| type | String | Required | The type of the belief. Valid values are: "Pantheon", "Follower", "Founder" and "Enhancer". | +| uniques | List of Strings | defaults to none | The unique abilities this belief adds to cities following it. May be chosen from the list of building uniques here, as well as the general uniques on that page | +| civilopediaText | List | Default empty | see civilopediaText chapter |

    +

    Buildings.json

    +

    link to original

    +

    This file should contain all the buildings and wonders you want to use in your mod.

    +

    Each building can have the following attributes: +| attribute | Type | Optional or not | notes | +| --------- | ---- | --------------- | ----- | +| name | String | required | Name of the building | +| cost | Integer (≥0) | defaults to 0 | Amount of production required to build the building | +| food | Integer | defaults to 0 | Food produced by the building | +| production | Integer | defaults to 0 | Production produced by the building | +| gold | Integer | defaults to 0 | etc. | +| happiness | Integer | defaults to 0 | | +| culture | Integer | defaults to 0 | | +| science | Integer | defaults to 0 | | +| faith | Integer | defaults to 0 | | +| maintenance | Integer (≥0) | defaults to 0 | Maintenance cost of the building | +| isWonder | Boolean | defaults to false | Whether this building is a global wonder | +| isNationalWonder | Boolean | defaults to false | Whether this building is a national wonder | +| requiredBuilding | String | defaults to none | A building that has to be built before this building can be built. Must be in Buildings.json | +| cannotBeBuiltWith | String | defaults to none | The building [cannotBeBuiltWith] and this building cannot exist in the same city together. Should be in Buildings.json | +| providesFreeBuilding | String | defaults to none | When the building is built, [providesFreeBuilding] is also automatically added to the city | +| requiredTech | String | defaults to none | The tech that should be researched before this building may be built. Must be in Techs.json | +| requiredResource | String | defaults to none | The resource that is consumed when building this building. Must be in TileResources.json | +| requiredNearbyImprovedResources | List of Strings | defaults to none | The building can only be built if any of the resources in this list are within the borders of this city and have been improved. Each resource must be in TileResources.json | +| replaces | String | defaults to none | The name of a building that should be replaced by this building. Must be in Buildings.json | +| uniqueTo | String | defaults to none | If supplied, only the nation with this name can build this building. Must be in Nations.json | +| xpForNewUnits | Integer | defaults to 0 | XP granted automatically to units built in this city | +| cityStrength | Integer | defaults to 0 | Strength bonus the city in which this building is built receives | +| cityHealth | Integer | defaults to 0 | Health bonus the city in which this building is built receives | +| hurryCostModifier | Integer | defaults to 0 | When this building is bought using gold or faith, the price is increased by this much percent | +| quote | String | defaults to none | If this building is a (national) wonder, this string will be shown on the completion popup | +| uniques | List of Strings | defaults to none | List of unique abilities this building has. Most of these can be found here | +| replacementTextForUniques | String | defaults to none | If provided, this string will be shown instead of all of the uniques | +| percentStatBonus | Object | defaults to none | Percentual bonus for stats provided by the building. Valid keys are the names of stats (production, gold, science, etc.), valid values are Integers (≥0) | +| greatPersonPoints | Object | defaults to none | How many great person points for each type will be generated per turn. Valid keys are the names of great people (Great Scientist, Great Engineer, etc. .), valid values are Integers (≥0) | +| specialistSlots | Object | defaults to none | Specialist slots provided by this building. Valid keys are the names of specialists (as defined in Specialists.json), valid values are Integers, the amount of slots provided for this specialist | +| civilopediaText | List | Default empty | see civilopediaText chapter |

    +

    Nations.json

    +

    Link to original

    +

    This file contains all the nations and city states, including Barbarians and Spectator.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeOptional?Notes
    nameStringRequired
    leaderNameStringDefault emptyOmit only for city states! If you want LeaderPortraits, the image file names must match exactly, including case.
    styleStringDefault emptyModifier appended to pixel unit image names
    adjectiveStringDefault emptyCurrently unused
    cityStateTypeEnumDefault absentDistinguishes Major Civilizations from City States (Cultured, Maritime, Mercantile, Militaristic)
    startBiasListDefault emptyZero or more of: terrainFilter or "Avoid [terrainFilter]". Two or more will be logically "and"-ed, and if the filters result in no choices, the entire attribute is ignored (e.g. "startBias": ["Snow","Tundra"] will never work).
    preferredVictoryTypeEnumDefault NeutralNeutral, Cultural, Diplomatic, Domination or Scientific
    startIntroPart1StringDefault emptyIntroductory blurb shown to Player on game start...
    startIntroPart2StringDefault empty... second paragraph. NO "TBD"!!! Leave empty to skip that alert.
    declaringWarStringDefault emptyanother greeting
    attackedStringDefault emptyanother greeting
    defeatedStringDefault emptyanother greeting
    introductionStringDefault emptyanother greeting
    neutralHelloStringDefault emptyanother greeting
    hateHelloStringDefault emptyanother greeting
    tradeRequestStringDefault emptyanother greeting
    innerColor3x IntegerDefault blackR, G, B for outer ring of nation icon
    outerColor3x IntegerRequiredR, G, B for inner circle of nation icon
    uniqueNameStringDefault emptyDecorative name for the special characteristic of this Nation
    uniqueTextStringDefault emptyReplacement text for "uniques". If empty, uniques are listed individually.
    uniquesListDefault emptyProperties of the civilization - see here
    citiesListDefault emptyCity names used sequentially for newly founded cities.
    civilopediaTextListDefault emptysee civilopediaText chapter
    +

    Policies.json

    +

    Link to original

    +

    This file lists the available social policies that can be "bought" with culture.

    +

    They are organized in 'branches', each branch has an 'opener', one or more 'member' policies, and a 'finisher'. Therefore this file is organized using two levels - branch and member policy. The properties of the 'opener' are defined with the branch level, while the 'finisher' has an entry on the member level which must be named as branch name + " Complete", case sensitive.

    +

    Each policy branch can have the following properties: +| Attribute | Type | Optional? | Notes | +|-----------|------|-----------|-------| +| name | String | Required | | +| era | String | Required | Unlocking era as defined in Eras.json | +| uniques | List | Default empty | List of effects, see here | +| policies | List | Default empty | List of member policies |

    +

    Each member policy can have the following properties: +| Attribute | Type | Optional? | Notes | +|-----------|------|-----------|-------| +| name | String | Required | | +| row | Integer | Required | Placement in UI, each unit approximately half the icon size | +| column | Integer | Required | Placement in UI, each unit approximately half the icon size | +| requires | List | Default empty | List of prerequisite policy names | +| uniques | List | Default empty | List of effects, see here |

    +

    Quests.json

    +

    Link to original

    +

    This file contains the Quests that may be given to major Civilizations by City States.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeOptional?Notes
    nameStringRequiredUnique identifier name of the quest, it is also shown
    descriptionStringRequiredDescription of the quest shown to players
    typeEnumDefault IndividualIndividual or Global
    influeceFloatDefault 40Influence reward gained on quest completion
    durationIntegerDefault 0Maximum number of turns to complete the quest, 0 if there's no turn limit
    minimumCivsIntegerDefault 1Minimum number of Civs needed to start the quest. It is meaningful only for type = Global
    +

    Religions.json

    +

    Link to original

    +

    This is just a list of Strings specifying all predefined Religion names. Corresponding icons must exist, that's all to it. After all, they're just containers for Beliefs.

    +

    Specialists.json

    +

    Link to original

    +

    This file should contain a list of all possible specialists that you want in your mod.

    +

    Each specialist can have the following attributes: +| attribute | type | optional or not | notes | +| --------- | ---- | --------------- | ----- | +| name | String | required | Name of the specialist | +| food | Integer | defaults to 0 | Amount of food produced by this specialist | +| production | Integer | defaults to 0 | Amount of production produced by this specialist | +| gold | Integer | defaults to 0 | etc. | +| culture | Integer | defaults to 0 | | +| science | Integer | defaults to 0 | +| faith | Integer | defaults to 0 | +| color | List of 3 Integers | required | Color of the image for this specialist | +| greatPersonPoints | Object | defaults to none | Great person points generated by this specialist. Valid keys are the names of the great person(Great Scientist, Great Merachant, etc.), valid values are Integers (≥0) |

    +

    Techs.json

    +

    Link to original

    +

    This file contains all the technologies. It is organized into an outer list of 'columns' which in turn contain one or more tech each.

    +

    Column structure

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeOptional?Notes
    columnNumberIntegerRequiredHorizontal placement in the Tech Tree.
    eraStringRequiredReferences Eras.json.
    techCostIntegerRequiredDefault cost of the techs in this column.
    buildingCostIntegerRequiredDefault cost of buildings requiring this tech.
    wonderCostIntegerRequiredDefault cost of wonders requiring this tech.
    techsList of TechsRequiredList of techs as follows - pay attention to the nesting of {} and [].
    +

    Tech structure

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeOptional?Notes
    nameStringRequiredThe name of this Technology.
    rowIntegerDefaults to 0Vertical placement in the Tech Tree, must be unique per column.
    costIntegerDefaults to column techCostThe amount of science required to research this tech.
    prerequisitesListDefault emptyA list of the names of techs that are prerequisites of this tech. Only direct prerequisites are necessary.
    quoteStringDefault emptyA nice story presented to the player when they research this tech.
    uniquesListDefault emptyProperties granted by the tech - see here.
    civilopediaTextListDefault emptysee civilopediaText chapter.
    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Coding-standards/index.html b/site/wiki/Coding-standards/index.html new file mode 100644 index 0000000000..a7cd900f86 --- /dev/null +++ b/site/wiki/Coding-standards/index.html @@ -0,0 +1,797 @@ + + + + + + + + + + + + + + + + Coding standards - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Coding standards

    + +

    As an open-source project, there will be a lot of eyes on our code.

    +

    The main purpose of having a coding standard is for the code to be as immediately readable as possible to as many potential contributors, and hence most of it focuses on defaulting to coding structures that exist in other similar languages (Java, C#) when possible.

    +

    Don't use .let{} and ?:

    +

    Kotlin is made greater for being strict with nullability. Don't let this fact confuse people new to it. These can be simply replaced by if(x!=null) which is much more readable. They all probably compile to the same bytecode anyway, so when in doubt - readability.

    +

    for(item in list) and not list.forEach{}

    +

    For loops go waaaay back, forEach doesn't. As an added bonus, I'm pretty sure that because forEach accepts a function parameter, then when debugging it won't automatically step into these lines, unlike for.

    +

    Avoid premature abstraction

    +

    There's no need to create an interface if there is only one implementation of that interface. Doing so obfuscates the actual code that's running and increases the Time To Relevant Code. If abstraction becomes necessary later, we can always do it later.

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Creating-a-custom-tileset/index.html b/site/wiki/Creating-a-custom-tileset/index.html new file mode 100644 index 0000000000..70e4db5485 --- /dev/null +++ b/site/wiki/Creating-a-custom-tileset/index.html @@ -0,0 +1,940 @@ + + + + + + + + + + + + + + + + How to make Unciv use your custom tileset - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    How to make Unciv use your custom tileset

    +

    You should read the Mods page first before proceeding

    +

    In order to add a tileset mod (yes, tilesets are just another type of mod), all you need to do is add your images under Images/Tilesets/MyCoolTilesetExample and enable the mod as a permanent visual mod - the game will recognize the tileset, and allow you to pick it in the options menu.

    +

    Let's look at the example "Grassland+Jungle+Dyes+Trading post" to learn how the game decides which images it should use for this tile:

    +
      +
    1. +

      When there is a rule variant entry in the tileset config for this tile we will use the entry.

      +
    2. +
    3. +

      Else if there is an image called "Grassland+Jungle+Dyes+Trading post" we will use it instead.

      +
    4. +
    5. +

      Otherwise, we will check if there is an image called "Grassland+Jungle" (BaseTerrain+Terrainfeatures) and "Dyes+Trading post" (Resource+Improvement) and use the remainings of it. Let's say you made an image called "Grassland+Jungle" but none called "Dyes+Trading post". In the end, we will then use the images "Grassland+Jungle", "Dyes" and "Trading post".

      +
    6. +
    +

    All these images can also use era-dependant variants if you want to change the appearance of, let's say, "Trading post" throughout the game. Just create images and add the suffix "-[era name]". +E.g. "Trading post-Classical era", "Trading post-Industrial era", etc.

    +

    It is advised to use the layered approach (1 and 3) often because it comes with a few advantages. Mainly: +- Decreased filesize (on disk, for downloads) +- Easier support for new terrains, improvements, resources, and for changing existing tiles

    +

    You should keep in mind that the default rendering order is: +BaseTerrain, TerrainFeatures, Resource, Improvement.

    +

    Tileset config

    +

    This is where tileset configs shine. +You can use these to alter the way Unicv renders tiles.

    +

    To create a config for your tileset you just need to create a new .json file under Jsons/Tilesets/. Just create a .txt file and rename it to MyCoolTilesetExample.json. You only have to add things if you want to change them. Else the default values will be used.

    +

    This is an example of such a config file that I will explain below:

    +
        "useColorAsBaseTerrain": "false",
    +    "unexploredTileColor": {"r":1,"g":1,"b":1,"a":1},
    +    "fogOfWarColor": {"r":1,"g":0,"b":0,"a":1},
    +    "ruleVariants": {
    +        "Grassland+Forest": ["Grassland","ForestForGrassland"],
    +        "Grassland+Jungle+Dyes+Trading post": ["Grassland","JungleForGrasslandBack","Dyes+Trading post","JungleForGrasslandFront"]
    +    }
    +
    +

    useColorAsBaseTerrain

    +

    A boolean value ("true" or "false"). Default value: "true"

    +

    If true all tiles will be colored in their corresponding base terrain color. This is how the "Default" tileset works.

    +

    unexploredTileColor

    +

    A color defined with normalized RGBA values. Default value: "{"r":0.24705882, "g":0.24705882, "b":0.24705882, "a":1}" (DarkGray)

    +

    Defines the color of the unexplored tiles.

    +

    fogOfWarColor

    +

    A color defined with normalized RGBA values. Default value: "{"r":0, "g":0, "b":0, "a":1}" (Black)

    +

    Defines the color of the fog of war. The color gets approximated by 60% to allow the colors of the images below to shine through.

    +

    ruleVariants

    +

    A dictionary mapping string to string[]. Default value: empty

    +

    The ruleVariants are the most powerful part of the tileset config. +With this, you can define, for a specific tile, which images and in which order these images should be used.

    +

    An example is given in the code above. For the tile "Grassland+Jungle+Dyes+Trading post" we then use the images "Grassland", "JungleForGrasslandBack", "Dyes+Trading post" and "JungleForGrasslandFront" in that order.

    +

    Nation-coloured units

    +

    Unciv can colour units according to the civilization that owns them. [PR3231]

    +

    This is used by providing multiple images per unit, each representing a coloured layer. The image suffixed with "-1" will be tinted to the civilization's inner colour, and the image suffixed with "-2" will be tinted to the civilization's outer colour. For example:

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    ImageDescriptionColour
    Archer.pngBase imageUntinted
    Archer-1.pngColour layerNation inner colour
    Arhcer-2.pngColour layerNation outer colour
    +

    The Civ Army Color Style Sheet mod by @AdityaMH and the 5Hex Tileset by @ravignir are very good practical examples of how this can be used.

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Force-rating-calculation/index.html b/site/wiki/Force-rating-calculation/index.html new file mode 100644 index 0000000000..ef2c98a448 --- /dev/null +++ b/site/wiki/Force-rating-calculation/index.html @@ -0,0 +1,940 @@ + + + + + + + + + + + + + + + + Force rating - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Force rating

    +

    Since the question has come up several times, here is a summary of how Force ratings are calculated.

    +

    Base Unit Force Evaluation

    +

    First the base unit gets a force evaluation. +If the unit has a ranged attack, the starting force is the ranged strength ^ 1.45. Otherwise the starting force is strength ^ 1.5. +This is multiplied by the unit's movement ^ 0.3. Nukes get +4000.

    +

    Then this is multiplied by a bunch of modifiers: +* 0.5 if ranged naval +* 0.5 if self-destructs when attacking +* Half the city attack bonus (So +25% if the unit has +50% when attacking cities) +* A Quarter of attack bonuses vs things other than cities +* Half the bonus "when attacking" +* Half the bonus "when defending" +* +25% if paradrop able +* -20% if needs to set up to attack +* Half the bonus from certain terrain +* +20% bonus per extra attack per turn

    +

    Individual Unit Force Evaluation

    +

    Each individual unit has a Force equal to the Base Unit Force, +* multiplied by (number of times promoted +1) ^ 0.3. +* multiplied by current health as a percentage.

    +

    Civ Force Ranking

    +

    The civs Force Ranking is based on the sum of all their units' Force Evaluation (cities are not counted). +Only half the Force of naval units is counted. +This is multiplied by a gold modifier equal to the square root of current gold, as a percentage. +The gold multiplier is constrained to be between 1 and 2, so the max multiplier is 2 which is reached at 10000 gold.

    +

    Show Me Some Numbers

    +
      +
    • Scout 13
    • +
    • Archer 19
    • +
    • Slinger 19
    • +
    • Dromon 23
    • +
    • Warrior 27
    • +
    • Maori Warrior 27
    • +
    • Brute 27
    • +
    • Bowman 29
    • +
    • Jaguar 36
    • +
    • Catapult 39
    • +
    • Composite Bowman 39
    • +
    • Galleass 41
    • +
    • Chariot Archer 42
    • +
    • War Elephant 44
    • +
    • War Chariot 45
    • +
    • Horse Archer 45
    • +
    • Trireme 46
    • +
    • Spearman 49
    • +
    • Ballista 55
    • +
    • Persian Immortal 56
    • +
    • Horseman 62
    • +
    • Hoplite 63
    • +
    • Swordsman 64
    • +
    • Chu-Ko-Nu 66
    • +
    • Quinquereme 69
    • +
    • African Forest Elephant 72
    • +
    • Battering Ram 80
    • +
    • Cataphract 80
    • +
    • Crossbowman 81
    • +
    • Longbowman 81
    • +
    • Companion Cavalry 84
    • +
    • Legion 86
    • +
    • Mohawk Warrior 86
    • +
    • Pikeman 87
    • +
    • Landsknecht 87
    • +
    • Trebuchet 88
    • +
    • Keshik 89
    • +
    • Frigate 100
    • +
    • Hwach'a 110
    • +
    • Longswordsman 118
    • +
    • Camel Archer 124
    • +
    • Samurai 126
    • +
    • Berserker 133
    • +
    • Knight 134
    • +
    • Conquistador 134
    • +
    • Mandekalu Cavalry 134
    • +
    • Caravel 134
    • +
    • Ship of the Line 139
    • +
    • Musketman 144
    • +
    • Cannon 151
    • +
    • Minuteman 154
    • +
    • Janissary 162
    • +
    • Gatling Gun 169
    • +
    • Musketeer 182
    • +
    • Tercio 182
    • +
    • Naresuan's Elephant 194
    • +
    • Lancer 204
    • +
    • Hakkapeliitta 204
    • +
    • Sipahi 218
    • +
    • Privateer 222
    • +
    • Rifleman 243
    • +
    • Carolean 243
    • +
    • Sea Beggar 244
    • +
    • Artillery 245
    • +
    • Battleship 269
    • +
    • Great War Bomber 290
    • +
    • Cavalry 300
    • +
    • Hussar 320
    • +
    • Triplane 325
    • +
    • Turtle Ship 327
    • +
    • Cossack 337
    • +
    • Norwegian Ski Infantry 345
    • +
    • Guided Missile 378
    • +
    • Carrier 408
    • +
    • Submarine 420
    • +
    • Bomber 425
    • +
    • Great War Infantry 434
    • +
    • Machine Gun 465
    • +
    • Fighter 470
    • +
    • Foreign Legion 477
    • +
    • Ironclad 486
    • +
    • Zero 508
    • +
    • Anti-Tank Gun 542
    • +
    • B17 551
    • +
    • Marine 645
    • +
    • Landship 703
    • +
    • Infantry 720
    • +
    • Nuclear Submarine 735
    • +
    • Stealth Bomber 771
    • +
    • Paratrooper 806
    • +
    • Anti-Aircraft Gun 819
    • +
    • Destroyer 870
    • +
    • Missile Cruiser 888
    • +
    • Rocket Artillery 930
    • +
    • Tank 948
    • +
    • Jet Fighter 988
    • +
    • Helicopter Gunship 992
    • +
    • Mechanized Infantry 1186
    • +
    • Panzer 1223
    • +
    • Mobile SAM 1376
    • +
    • Modern Armor 1620
    • +
    • Giant Death Robot 2977
    • +
    • Atomic Bomb 4714
    • +
    • Nuclear Missile 7906
    • +
    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/From-code-to-deployment/index.html b/site/wiki/From-code-to-deployment/index.html new file mode 100644 index 0000000000..154540822b --- /dev/null +++ b/site/wiki/From-code-to-deployment/index.html @@ -0,0 +1,882 @@ + + + + + + + + + + + + + + + + From code to deployment - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    From code to deployment

    +

    So, your code works! You've solved all the bugs and now you just need to get it out to everyone!

    +

    So, how does THAT work?

    +

    The process has two major parts, one is "Getting your code in the main repository" and the other is "Deploying versions" - as a developer, you'll be taking an active part in the first process, but the second process is on me =)

    +

    Getting your code in the main repo

    +
      +
    • First off, push your changes with Git to your own branch at https://github.com/YourUsername/Unciv.git. I hope you've been doing this during development too, but that's none of my business *sips tea*
    • +
    • Issue a pull request from https://github.com/YourUsername/Unciv - from the Pull Requests is the simplest
    • +
    • The Travis build will check that your proposed change builds properly and passes all tests
    • +
    • I'll go over your pull request and will ask questions and request changes - this is not only for code quality and standard, it's mostly so you can learn how the repo works for the next change you make =)
    • +
    • When everything looks good, I'll merge your code in and it'll enter the next release!
    • +
    +

    Deploying versions

    +

    When I'm ready to release a new version I: +* Comment "merge translations" in one of the open PRs tagged as 'mergeable translation' to trigger the translation branch creation, add a "summary" comment to trigger summary generation, merge the PR and delete the branch (so next version translation branch starts fresh) +* From my workstation - pull the latest changes and run the translation generation +* Change the versionCode and versionName in the Android build.gradle so that Google Play and F-droid can recognize that it's a different release +* Add an entry in the changelog.md done, WITHOUT hashtags, and less than 500 characters (that's the limit for Google play entries). The formatting needs to be exact or the text sent to Discord, the Github release etc. won't be complete. +* Add a tag to the commit of the version. When the Github action sees that we've added a tag, it will run a build, and this time (because of the configuration we put in the yml file file), it will: + * Pack a .jar file, which will work for every operating system with Java + * Use Linux and Windows JDKs to create standalone zips for 32 and 64 bit systems, because we can't rely on the fact that users will have a JRE + * Download Butler and use it to push the new versions to the itch.io page + * Read the changelog.md file to get the changes for the latest version + * Upload all of these files to a new release on Github, with the release notes, which will get added to the Releases page + * Send an announcement on the Discord server of the version release and release notes via webhook + * Pack, Sign, and Upload a new APK to the Google Play Console at 10% rollout +* The F-Droid bot checks periodically if we added a new tag. When it recognizes that we did, it will update the yaml file here + * When the bot next runs and sees that there's a version it doesn't have a release for, it will attempt to build the new release. The log of the build will be added here (redirects to the latest build), and the new release will eventually be available here

    +

    About Google Play publishing

    +

    +We start at a 10% rollout, after a day with no major problems go to 30%, and after another day to 100%. If you were counting that means that most players will get the new version after 2+ days. ++ ++If there were problems, we halt the current rollout, fix the problems, and release a patch version, which starts at 10% again. ++ ++Dear future me - the automation was extremely annoying guesswork to set up, so the facts you need to know are: +- There is a user at the Google Cloud Platform Account Manager called Unciv_Upload_Account. There is an access key to this account, in json, stored as the Github secret GOOGLE_PLAY_SERVICE_ACCOUNT_JSON. +- This user was granted ADMIN permissions to the Google Play (after much trial and error since nothing else seemed to work) under User > Users and Permissions. Under Manage > Account permissions, you can see that it has Admin.

    +

    Updating the wiki

    +

    Pages for the Unciv Github Wiki are kept in the main repository under /docs/wiki.

    +

    The process to edit the wiki is as follows:

    +
      +
    1. Open a pull request in the main Unciv repository that changes files under /docs/wiki.
    2. +
    3. Once the pull request is merged, an account with commit privileges on the Unciv repository leaves a comment saying "update wiki".
    4. +
    5. This comment triggers a bot to copy all the wiki files from the main repository into the Github wiki, with a link back to the PR in its commit message for credit.
    6. +
    +

    Doing things this way has several distinct advantages over using the Github Wiki web interface directly:

    +
      +
    • Changes can be proposed via PR and proofread or fact-checked.
    • +
    • A proper MarkDown editor or IDE can be used to write the wiki, bringing faster editing, clickable links while editing, better live HTML preview, and automatic detection of problems like broken links.
    • +
    • The wiki files can also be browsed at https://github.com/yairm210/Unciv/tree/master/docs/wiki.
    • +
    • Auto-generated documentation made by the build process can be placed directly in the wiki.
    • +
    +

    However, it also imposes a couple of conventions about how links should best be formatted:

    + + + + + + + + + + + + + + + + + + + + +
    Link typeFormatExample
    Inter-wikiShould begin with "./", and include ".md"../Mods.md#other
    Code or asset fileShould begin with "/", and be relative to the project root./android/assets/game.png
    +

    These formats will allow IDEs like Android studio to resolve these links and check for broken links, while also working on the Github code browser.

    +

    The bot that updates the wiki from the main repository automatically translates them into formats that are compatible with Github Wikis, which have somewhat non-standard requirements.

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Getting-Started/index.html b/site/wiki/Getting-Started/index.html new file mode 100644 index 0000000000..c4cfc5a33a --- /dev/null +++ b/site/wiki/Getting-Started/index.html @@ -0,0 +1,726 @@ + + + + + + + + + + + + + + + + Getting Started - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    + + + + +

    Getting Started

    + +

    This is a guide to editing, building, running and deploying Unciv from code

    +

    So first things first - the initial "No assumptions" setup to have Unciv run from-code on your computer!

    +
      +
    • Install Android Studio - it's free and awesome! Be aware that it's a long download!
    • +
    • Install Git, it's the way for us to work together on this project. UI is optional, Android Studio has good Git tools built in :)
    • +
    • Getting the code
    • +
    • Create a Github account, if you don't already have one
    • +
    • Fork the repo (click the "Fork" button on the top-right corner of https://github.com/yairm210/Unciv) - this will create a "copy" of the code on your account, at https://github.com/YourUsername/Unciv
    • +
    • Clone your fork with git - the location will be https://github.com/YourUsername/Unciv.git, visible from the green "Clone or download" button at https://github.com/YourUsername/Unciv
    • +
    • Load the project in Android Studio, Gradle will attempt the initial sync. If this is your first time with Android Studio, this may require you to accept the Android Build-tools licenses, which works differently on every device, so search for your OS-specific solution.
    • +
    • A new install may not be able to do the initial sync - this comes in the form of Unable to find method ''void org.apache.commons.compress.archivers.zip.ZipFile.<init>(java.nio.channels.SeekableByteChannel)'' errors when you try to sync. If you have this problem go into File > Settings > Appearance & Behavior > System Settings > Android SDK
        +
      • Click "SDK Tools"
      • +
      • Select "Show Package Details" in the bottom right
      • +
      • Choose version 30.0.3 under "Android SDK Build-Tools "
      • +
      • Click "Apply"
      • +
      +
    • +
    • In Android Studio, Run > Edit configurations.
    • +
    • Click "+" to add a new configuration
    • +
    • Choose "Application"
    • +
    • Set the module to Unciv.desktop, main class to com.unciv.app.desktop.DesktopLauncher and <repo_folder>\android\assets\ as the Working directory, OK to close the window
        +
      • If you get a ../../docs/uniques.md (No such file or directory) error that means you forgot to set the working directory!
      • +
      +
    • +
    • Select the Desktop configuration and click the green arrow button to run!
    • +
    • I also recommend going to Settings > Version Control > Commit and turning off 'Before commit - perform code analysis'
    • +
    +

    Unciv uses Gradle to specify dependencies and how to run. In the background, the Gradle gnomes will be off fetching the packages (a one-time effort) and, once that's done, will build the project!

    +

    Congratulations! Unciv should now be running on your computer! Now we can start changing some code, and later we'll see how your changes make it into the main repository!

    +

    Now would be a good time to get to know the project in general at the Project Structure overview!

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Home/index.html b/site/wiki/Home/index.html new file mode 100644 index 0000000000..6af78897b5 --- /dev/null +++ b/site/wiki/Home/index.html @@ -0,0 +1,700 @@ + + + + + + + + + + + + + + + + Home - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    + + + + +

    Home

    + +

    Welcome to the Unciv wiki!

    +

    If you're a developer, you'll probably want to start at the Getting Started page!

    +

    If you're a translator, head over to Translating!

    +

    If you're a modder, start here.

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Installing-on-macOS/index.html b/site/wiki/Installing-on-macOS/index.html new file mode 100644 index 0000000000..c044c586e5 --- /dev/null +++ b/site/wiki/Installing-on-macOS/index.html @@ -0,0 +1,788 @@ + + + + + + + + + + + + + + + + Installing on macOS - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Installing on macOS

    + +

    There is currently two ways to install UnCiv on macOS. It is recommended that you use the first method as the second one is overly complicated and the end result will be the same. Both installation methods require that you have Java 8 installed on your mac.

    +

    Installing using JAR

    +
      +
    1. If you don't already have Java 8 installed on your mac make sure you download it from the official website. Once you have downloaded the file open it and follow the instructions on screen.
    2. +
    3. Now that you have Java 8 installed it's time to download the latest UnCiv JAR. This can be done from the releases screen here on Github. Download the file called Unciv.jar.
    4. +
    5. After downloading Unciv.jar open Finder on your mac and go to the location where you chose to save the file. Right-click or Control-click the file and chose Open.
    6. +
    7. You will now be prompted with a window saying something similar to macOS cannot verify the developer of "Unciv.jar". Are you sure you want to open it? Press the Open button.
    8. +
    9. Congratulations, you have now installed UnCiv. You may want to add a shortcut to the desktop to be able to open the game more easily.
    10. +
    +

    (Sadly UnCiv dose not auto update when installing it using this method on macOS so you will need to download the latest Unciv.jar from Github every time you want to update the game.)

    +

    Installing from source

    +

    For instructions on how to install UnCiv from source see Building locally without Android Studio. It is not recommended to use this method as it achieves the same result as the first method whilst being much more complicated and prone to errors along the way.

    +

    (Sadly UnCiv dose not auto update when installing it using this method on macOS so you will need to follow these steps every time you want to update the game.)

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/JSON-files-for-mods/index.html b/site/wiki/JSON-files-for-mods/index.html new file mode 100644 index 0000000000..f45d4fab2b --- /dev/null +++ b/site/wiki/JSON-files-for-mods/index.html @@ -0,0 +1,802 @@ + + + + + + + + + + + + + + + + JSON files for mods - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    These pages are a work in progress. Information they contain may be incomplete.

    +

    The JSON files that make up mods can have many different fields, and as not all are used in the base game, this wiki page will contain the full information of each. It will also give a short explanation of the syntax of JSON files.

    +

    Table of Contents

    + +

    General Overview of JSON files

    +

    Resources: json.org, ISO standard

    +

    Almost all Unciv JSON files start with a "[" and end with a "]". In between these are different objects of the type you are describing, each of which is contained between a "{" and a "}". For example, a very simple units.json may look like:

    +
    [
    +    {
    +        "name": "Warrior",
    +        "cost": 16
    +    },
    +    {
    +        "name": "Spearman",
    +        "cost": 24,
    +        "promotions": ["Shock I", "Drill I"]
    +    }
    +]
    +
    +

    This file contains two unit objects, one for a warrior and one for a spearman. These objects have different attributes, in this case "name", "cost" and "promotions". All these attributes have a certain type, a String (text) for "name", an Integer for "cost" and a List of Strings for "promotions".

    +

    There are different types of attributes: +| type | notes | +| --------- | ----- | +| String | A word or sentence. Should be between double quotes (") | +| Integer | A number. Can be both positive or negative. Should not be between quotes | +| Boolean | A value that can either be 'true' or 'false'. Should not be between quotes | +| List of [type] | If multiple values could apply (such as with the promotions above), they should be put inside a list. Each element of the list should be written like a normal attribute, seperated by comma's, and enclosed between square braces. E.g.: ["Shock I", "Shock II"] or [1, 2, 3]. | +| Object | The most complicated type of attribute. An object is comprised of multiple attributes, each of which again has a type. These attributes have a key (the part before the ":") and a value (the part behind it). For an example, see below. |

    +

    Example of a Buildings.json adding a new "Cultural Library" building which gives +50% science and +50% culture:

    +
    [
    +    {
    +        "name": "Cultural Library"
    +        "percentStatBonus" : {"science": 50, "culture": 50}
    +    }
    +]
    +
    +

    The keys in this example are "science" and "culture", and both have the value "50".

    +

    In some sense you can see from these types that JSON files themselves are actually a list of objects, each describing a single building, unit or something else.

    +

    Information on JSON files used in the game

    +

    Many parts of Unciv are moddable, and for each there is a seperate json file. There is a json file for buildings, for units, for promotions units can have, for technologies, etc. The different new buildings or units you define can also have lots of different attributes, though not all are required. Below are tables documenting all the different attributes everything can have. Only the attributes which are noted to be 'required' must be provided. All others have a default value that will be used when it is omitted.

    +

    The individual files are described on separate pages:

    + + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Making-a-new-Civilization/index.html b/site/wiki/Making-a-new-Civilization/index.html new file mode 100644 index 0000000000..d5050c750c --- /dev/null +++ b/site/wiki/Making-a-new-Civilization/index.html @@ -0,0 +1,865 @@ + + + + + + + + + + + + + + + + Making a new Civilization - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Making a new Civilization

    +

    So you want to add your favorite civilization?

    +

    There are a few steps required, so we'll walk you through them!

    +

    Fill in your Nation info

    +

    Each civ has some basic information - what the civ name is, the leader's name, colors and city names.

    +

    In addition, each civ has flavor text when declaring war, intoduction etc.

    +

    All of these need to be filled in in Nations.json

    +

    Get your Civ icon

    +

    Each civ has an icon, like the wreath for Rome, for instant identification.

    +

    All of these icons are white on a transparent background, and are 100x100 pixels - see icon considerations for details

    +

    You'll need to put your icon in the NationIcons folder.

    +

    Same as with the nation name and leader name, the unique ability should also be put in the Nations translation file for bonus points =)

    +

    Congrats, your Civ is now fully playable!

    +

    But apart from the flavor, they are boring gameplay-wise, so now we need to add unique abilities!

    +

    Adding unique units

    +

    Units in general are added in the Units.json file, with an icon in the + UnitIcons folder.

    +

    The icon must be 200x200 pixels, white on transparent background - see icon considerations for details

    +

    Remember that these are unique units, so search for an existing unique unit to see how they replace their regular counterparts!

    +

    Adding unique buildings

    +

    Same as the units - info is in the Buildings.json file +and icons in the BuildingIcons folder, +same rules for the icons apply (200x200 pixels, icon considerations)

    +

    Civ Unique

    +

    Check out our list of uniques to see all the cool special effects you can add to your civilization!

    +

    Icon considerations

    +

    ALL icons must be legally acceptable, meaning they either come from from open sources or you act according to their licence (for Creative Commons, for instance, you have to specify the source and the creator).

    +

    Icons directly from the base game belong to Firaxis, so I'm not sure we're legally allowed to use them - please use other sources!

    +

    One source I use constantly is The Noun Project - everything there is Creative Commons or open, so they can all be used!

    +

    Credits for icons should go in the Credits page

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Map-related-JSON-files/index.html b/site/wiki/Map-related-JSON-files/index.html new file mode 100644 index 0000000000..24f15e8775 --- /dev/null +++ b/site/wiki/Map-related-JSON-files/index.html @@ -0,0 +1,1085 @@ + + + + + + + + + + + + + + + + Map related JSON files - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Map related JSON files

    + + +

    Terrains.json

    +

    This file lists the base terrains, terrain features and natural wonders that can appear on the map.

    +

    Each terrain entry can have the following properties: +| Attribute | Type | Optional? | Notes | +|-----------|------|-----------|-------| +| name | String | Required | | +| type | Enum | Required | Land, Water, TerrainFeature, NaturalWonder | +| occursOn | List | Default none | Only for terrain features and Natural Wonders: The baseTerrain it can be placed on | +| turnsInto | String | Default none | Only for Natural Wonders: After placing the Natural Wonder its base terrain is changed to this | +| weight | Integer | Default 10 | Only for Natural Wonders: relative weight it will be picked by the map generator | +| <stats> | Float | Optional | Per-turn yield or bonus yield for the tile, see Stats | +| overrideStats | Boolean | Default false | If on, a feature's yields replace any yield from underlying terrain instead of adding to it | +| unbuildable | Boolean | Default false | If true, nothing can be built here - not even resource improvements | +| impassable | Boolean | Default false | no unit can enter unless it has a special unique | +| movementCost | Integer | Default 1 | base movement cost | +| defenceBonus | Float | Default 0 | combat bonus for units being attacked here | +| RGB | List Integer * 3 | Default 'Gold' | RGB color for 'Default' tileset display | +| uniques | List | Default empty | List of effects, see here | +| civilopediaText | List | Default empty | see civilopediaText chapter |

    +

    Note that many Natural Wonders have hardcoded routines for their placement and are recognized by name (e.g. Great Barrier Reef being more than one tile).

    +

    TileImprovements.json

    +

    This file lists the improvements that can be constructed or created on a map tile by a unit (any unit having the appropriate unique).

    +

    Note that improvements have two visual representations - icon and pixel graphic in the tileset. Omitting the icon results in a horribly ugly user interface, while omitting tileset graphics will just miss out on an optional visualization. If you provide a pixel graphic for FantasyHex, please be aware of the layering system and the ruleVariants in the tileset json. A single graphic may suffice if it has lots of transparency, as it will be drawn on top of all other terrain elements.

    +

    Each improvement can have the following properties: +| Attribute | Type | Optional? | Notes | +|-----------|------|-----------|-------| +| name | String | Required | | +| terrainsCanBeFoundOn | List | Default empty | Terrains that allow this resource | +| techRequired | String | Default none | The name of the technology required to build this improvement | +| uniqueTo | String | Default none | The name of the nation this improvement is unique for | +| <stats> | Float | Optional | Per-turn bonus yield for the tile, see Stats | +| turnsToBuild | Integer | | Number of turns a worker spends building this (ignored for 'create' actions) | +| uniques | List | Default empty | List of effects, see here | +| shortcutKey | String | Default none | Keyboard binding. At the moment a single character (no function keys or Ctrl combinations) | +| civilopediaText | List | Default empty | see civilopediaText chapter |

    +
      +
    • Tiles with no terrains, but positive turns to build, can be built only when the tile has a resource that names this improvement or special uniques are used. (TODO: missing something?)
    • +
    • Tiles with no terrains, and no turns to build, are like great improvements - they're placeable. That means a unit could exist with a 'Can create [this]' unique, and that the improvement will not show in a worker's improvement picker dialog.
    • +
    • Removable Terrain features will need to be removed before building an improvement - unless the feature is named in terrainsCanBeFoundOn or the unique "Does not need removal of [terrainFeature]" is used (e.g. Camp allowed by resource).
    • +
    • Special improvements: Road, Railroad, Remove *, Cancel improvement order, City ruins, City center, Barbarian encampment - these have special meanings hardcoded to their names.
    • +
    +

    TileResources.json

    +

    This file lists the resources that a map tile can have.

    +

    Note the predefined resource types cannot be altered in json.

    +

    Note also that resources have two visual representations - icon and pixel graphic in the tileset. Omitting the icon results in a horribly ugly user interface, while omitting tileset graphics will miss out on a visualization on the map. If you provide a pixel graphic for FantasyHex, please be aware of the layering system and the ruleVariants in the tileset json. A single graphic may suffice if it has lots of transparency, as it will be drawn on top of terrain and features but below an improvement - if the single improvement graphic exists at all.

    +

    Each resource can have the following properties: +| Attribute | Type | Optional? | Notes | +|-----------|------|-----------|-------| +| name | String | Required | | +| resourceType | String | Default Bonus | Bonus, Luxury or Strategic | +| terrainsCanBeFoundOn | List | Default empty | Terrains that allow this resource | +| <stats> | Float | Optional | Per-turn bonus yield for the tile, see Stats, can be repeated | +| improvement | String | Default empty | The improvement (TileImprovements.json) for this resource | +| improvementStats | Object | Default empty | The additional yield when improved as sub-object with one or more Stats | +| revealedBy | String | Default empty | The technology name required to see, work and improve this resource | +| unique | String | Default empty | Effects, see here - at the moment only one unique may be added | +| civilopediaText | List | Default empty | see civilopediaText chapter |

    +

    Ruins.json

    +

    Link to original

    +

    This file contains the possible rewards ancient ruins give. It is not required, if omitted, the default file for the game is used, even in baseRuleSet mods.

    +

    Each of the objects in the file represents a single reward you can get from ruins. It has the following properties:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    attributeTypeoptional or notnotes
    nameStringrequiredName of the ruins. Never shown to the user, but they have to be distinct
    notificationStringrequiredNotification added to the user when this reward is chosen. If omitted, an empty notification is shown. Some notifications may have parameters, refer to the table below.
    weightInteger (≥0)defaults to 1Weight this reward should have. Higher weights result in a higher chance of it being chosen*
    uniquesList of Stringsdefaults to none[uniques]Uniques#one-time-effect) or uniques that will trigger when entering the ruins. If more than 1 unique is added, the notification will be shown multiple times due to a bug.
    excludedDifficultiesList of Stringsdefaults to NoneA list of all difficulties on which this reward may not be awarded
    +
      +
    • The exact algorithm for choosing a reward is the following:
    • +
    • Create a list of all possible rewards, with rewards with a higher weight appearing multiple times. A reward with weight one will appear once, a reward with weight two will appear twice, etc.
    • +
    • Shuffle this list
    • +
    • Try give rewards starting from the top of the list. If any of the uniques of the rewards is valid in this context, reward it and stop trying more rewards.
    • +
    +

    Notifications

    +

    Some of the rewards ruins can give will have results that are not deterministic when writing it in the JSON, so creating a good notification for it would be impossible. An example for this would be the "Gain [50]-[100] [Gold]" unique, which will give a random amount of gold. For this reason, we allow some notifications to have parameters, in which values will be filled, such as "You found [goldAmount] gold in the ruins!". All the uniques which have this property can be found below.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    uniqueparameters
    Free [] found in the ruinsThe name of the unit will be filled in the notification, including unique units of the nation
    [] population in a random cityThe name of the city to which the population is added will be filled in the notification
    Gain []-[] []The exact amount of the stat gained will be filled in the notification
    [] free random reasearchable Tech(s) from the []The notification must have placeholders equal to the number of techs granted this way. Each of the names of these free techs will be filled in the notification
    Gain enough Faith for a PantheonThe amount of faith gained is filled in the notification
    Gain enough Faith for []% of a Great ProphetThe amount of faith gained is filled in the notification
    +

    Specific uniques

    +

    A few uniques can be added to ancient ruin effects to modify when they can be earned. These are: +- "Only available after [amount] turns" +- "Hidden when religion is disabled" +- "Hidden after a great prophet has been earned"

    +

    Tileset-specific json

    +

    A mod can define new Tilesets or add to existing ones, namely FantasyHex. There is one json file per Tileset, named same as the Tileset, and placed in a subfolder named "TileSets" relative to the other json files. This is called TileSetConfig and has the following structure:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeOptional?Notes
    useColorAsBaseTerrainBooleanDefault true? WIP
    unexploredTileColorColorDefault Dark Gray{"r":0.25,"g":0.25,"b":0.25,"a":1}
    fogOfWarColorColorDefault Black{"r":0,"g":0,"b":0,"a":1}
    ruleVariantsListDefault emptysee below
    +

    ruleVariants control substitutions when layering images for a tile, they are list looking like:

    +
        "ruleVariants": {
    +        "Grassland+Forest": ["Grassland","GrasslandForest"],
    +        "Plains+Forest": ["Plains","PlainsForest"],
    +        "Plains+Jungle": ["Plains","PlainsJungle"],
    +        ...
    +    }
    +
    +

    Each line means "if the tile content is this... then combine the following png images". The key part follows a specific order and must match in its entirety, meaning "Plains+Forest" is not valid for "Plains+Forest+Deer", and when it matches no other image layering is done except roads and units (I think - WIP).

    +

    When TileSetConfig's for the same Tileset are combined, for the first three properties the last mod wins, while ruleVariants are merged, meaning only an entry with the same key overwrites an earlier entry.

    +

    Stats

    +

    Terrains, features, resources and improvements may list yield statistics. They can be one of the following: +- production, food, gold, science, culture, happiness, faith

    +

    If an object carries general stats, any combination (or none) of these can be specified. For specialized stats, they might come as sub-object in a named field. Example:

    +
            "gold": 2,
    +        "improvement": "Quarry",
    +        "improvementStats": {"gold": 1,"production": 1},
    +
    +

    The values are usually integers, though the underlying code supports floating point. The effects are, however, insufficiently tested and therefore -so far- using fractional stats is unsupported. Go ahead and thoroughly test that in a mod and help out with feedback 😁.

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Miscellaneous-JSON-files/index.html b/site/wiki/Miscellaneous-JSON-files/index.html new file mode 100644 index 0000000000..017e57db74 --- /dev/null +++ b/site/wiki/Miscellaneous-JSON-files/index.html @@ -0,0 +1,904 @@ + + + + + + + + + + + + + + + + Miscellaneous JSON files - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Miscellaneous JSON files

    + + +

    Difficulties.json

    +

    Link to original

    +

    This file defines the difficulty levels a player can choose when starting a new game.

    +

    Each difficulty level can have the following attributes: +| Attribute | Type | Mandatory | Notes | +| --------- | ---- | ------- | ----- | +| name | String | Required | Name of the difficulty level | +| baseHappiness | Integer | Default 0 | +| extraHappinessPerLuxury | Float | Default 0 | +| researchCostModifier | Float | Default 1 | +| unitCostModifier | Float | Default 1 | +| buildingCostModifier | Float | Default 1 | +| policyCostModifier | Float | Default 1 | +| unhappinessModifier | Float | Default 1 | +| barbarianBonus | Float | Default 0 | +| playerBonusStartingUnits | List of Units | Default empty | Can also be 'Era Starting Unit', maps to startingMilitaryUnit of the Eras file. All other units must be in Units.json] | +| aiCityGrowthModifier | Float | Default 1 | +| aiUnitCostModifier | Float | Default 1 | +| aiBuildingCostModifier | Float | Default 1 | +| aiWonderCostModifier | Float | Default 1 | +| aiBuildingMaintenanceModifier | Float | Default 1 | +| aiUnitMaintenanceModifier | Float | Default 1 | +| aiFreeTechs | List of Techs | Default empty | +| aiMajorCivBonusStartingUnits | List of Units | Default empty | See above | +| aiCityStateBonusStartingUnits | List of Units | Default empty | See above | +| aiUnhappinessModifier | Float | Default 1 | +| aisExchangeTechs | Boolean | | Unimplemented | +| turnBarbariansCanEnterPlayerTiles | Integer | Default 0 | +| clearBarbarianCampReward | Integer | Default 25 |

    +

    Eras.json

    +

    Link to original

    +

    This file should contain all the era's you want to use in your mod.

    +

    Each era can have the following attributes: +| attribute | Type | optional or not | notes | +| --------- | ---- | --------------- | ----- | +| name | String | required | Name of the era | +| researchAgreementCost | Integer (≥0) | defaults to 300 | Cost of research agreements were the most technologically advanced civ is in this era | +| iconRGB | List of 3 Integers | defaults to [255,255,255] | RGB color that icons for technologies of this era should have in the Tech screen | +| unitBaseBuyCost | Integer (≥0) | defaults to 200 | Base cost of buying units with Faith, Food, Science or Culture when no other cost is provided | +| startingSettlerCount | Integer (≥0) | defaults to 1 | Amount of settler units that should be spawned when starting a game in this era | +| startingSettlerUnit | String | defaults to "Settler" | Name of the unit that should be used for the previous field. Must be in Units.json | +| startingWokerCount | Integer (≥0) | defaults to 0 | Amount of worker units that should be spawned when starting a game in this era | +| startingWorkerUnit | String | defaults to "Worker" | Name of the unit that should be used for the previous field. Must be in Units.json | +| startingMilitaryUnitCount | Integer (≥0) | defaults to 1 | Amount of military units that should be spawned when starting a game in this era | +| startingMilitaryUnit | String | defaults to "Warrior" | Name of the unit that should be used for the previous field. Must be in Units.json| +| startingGold | Integer (≥0) | defaults to 0 | Amount of gold each civ should receive when starting a game in this era | +| startingCulture | Integer (≥0) | defaults to 0 | Amount of culture each civ should receive when starting a game in this era | +| settlerPopulation | Integer (>0) | defaults to 1 | Default amount of population each city should have when settled when starting a game in this era | +| settlerBuildings | List of Strings | defaults to none | Buildings that should automatically be built whenever a city is settled when starting a game in this era | +| startingObsoleteWonders | List of Strings | defaults to none | Wonders (and technically buildings) that should be impossible to built when starting a game in this era. Used in the base game to remove all wonders older than 2 era's |

    +

    ModOptions.json

    +

    This file is a little different: +- Does not exist in Vanilla ruleset +- Is entirely optional but will be created after downloading a mod

    +

    The file can have the following attributes, including the values Unciv sets (no point in a mod author setting those): +| Attribute | Type | Defaults | Notes | +|-----------|------|-----------|-------| +| isBaseRuleset | Boolean | false | Differentiates mods that change the vanilla ruleset or replace it | +| maxXPfromBarbarians | Integer | 30 | ...as the name says... | +| uniques | List | empty | Mod-wide specials, see here | +| techsToRemove | List | empty | List of Technologies to remove (isBaseRuleset=false only) | +| buildingsToRemove | List | empty | List of Buildings or Wonders to remove (isBaseRuleset=false only) | +| unitsToRemove | List | empty | List of Units to remove (isBaseRuleset=false only) | +| nationsToRemove | List | empty | List of Nations to remove (isBaseRuleset=false only) | +| lastUpdated | String | empty | Set automatically after download - Last repository update, not necessarily last content change | +| modUrl | String | empty | Set automatically after download - URL of repository | +| author | String | empty | Set automatically after download - Owner of repository | +| modSize | Integer | empty | Set automatically after download - kB in entire repository, not sum of default branch files |

    +

    Civilopedia text

    +

    Any 'thing' defined in json and listed in the Civilopedia can supply extra text, specifically for the Civilopedia. This can be used to explain special considerations better when the automatically generated display is insufficient, or for 'flavour', background stories and the like. Such text can be formatted and linked to other Civilopedia entries, within limits.

    +

    An example of the format is:

    +
            "civilopediaText": [
    +            {"text":"Ancient ruins provide a one-time random bonus when explored"},
    +            {"separator":true},
    +            {"text":"This line is red and links to the Scout including icons", "link":"Unit/Scout", "color":"red"},
    +            {"text":"A big fat header sporting a golden star", "header":1, "starred":true, "color":"#ffeb7f"},
    +        ],
    +
    +

    List of attributes - note not all combinations are valid: +|attribute|type|description| +|---------|----|-----------| +|text|String|Text to display.| +|link|String|Create link and icon, format: Category/Name or external link ('http://','https://','mailto:').| +|icon|String|Show icon without linking, format: Category/Name.| +|extraImage|String|Display an Image instead of text. Can be a path found in a texture atlas or or the name of a png or jpg in the ExtraImages folder.| +|imageSize|Float|Width in world units of the [extraImage], height is calculated preserving aspect ratio. Defaults to available width.| +|header|Integer|Header level. 1 means double text size and decreases from there.| +|size|Integer|Text size, default is 18. Use size or header but not both.| +|indent|Integer|Indent level. 0 means text will follow icons, 1 aligns to the right of all icons, each further step is 30 units.| +|padding|Float|Vertical padding between rows, defaults to 5 units.| +|color|String|Sets text color, accepts names or 6/3-digit web colors (e.g. #FFA040).| +|separator|Boolean|Renders a separator line instead of text. Can be combined only with color and size (line width, default 2).| +|starred|Boolean|Decorates text with a star icon - if set, it receives the color instead of the text.| +|centered|Boolean|Centers the line (and turns off automatic wrap).|

    +

    The lines from json will 'surround' the automatically generated lines such that the latter are inserted just above the first json line carrying a link, if any. If no json lines have links, they will be inserted between the automatic title and the automatic info. This method may, however, change in the future.

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Mods/index.html b/site/wiki/Mods/index.html new file mode 100644 index 0000000000..c63bf03e4a --- /dev/null +++ b/site/wiki/Mods/index.html @@ -0,0 +1,971 @@ + + + + + + + + + + + + + + + + Mods - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + + + + +
    +
    + + + + +

    Mods

    + +

    What's this about?

    +

    Everyone has that thing they wish could be in the game. +Unfortunately, the game only understands code, so mods are our way to give a degree of freedom to those of us who don't code.

    +

    Mods can add, replace and remove basic game definitions, such as units, nations, buildings, improvements, resources and terrains. +Games loaded with these mods will function according to the mod definition.

    +

    The game only knows how to recognize existing definitions, so you can't add new unique abilities to nations/units/buildings/etc, only play around with existing ones

    +

    There are two kinds of mods:

    +
      +
    • +

      Extension mods - these add new nations/units/buildings/resources to a base ruleset - can be either to the default ruleset, or to a base ruleset mod. Easy to do and probably the better place to get started.

      +
    • +
    • +

      Base Ruleset mods - these replace the entire existing ruleset - tech tree, units, policies, nations etc - to give an entirely different experience than the base game. These generally require quite a bit of work, but give a whole new experience, and so are the most popular.

      +
    • +
    +

    Creating and editing mods from your phone is NOT RECOMMENDED - it's much easier using a desktop device!

    +

    Audiovisual Mods

    +

    I addition to changing the rules - or even without doing so, mods can override existing graphics or sounds, or add music tracks. The game also has the ability to display graphics that are not included in the base game at all, such as leader portrait or wonder splash images, that must be provided by mods. For details, see Audiovisual Mods.

    +

    Custom tilesets are closely related, see Creating a custom tileset.

    +

    Such mods are candidates for the "Permanent audiovisual mod" switch available on the Mod Management Screen. Note that this feature includes graphics or sounds from the selected mod in all games, even those started before installing the mod. In case of a mod bringing both changed rules and audiovisuals, the 'permanent' feature will include only the media on all games, to use the rules you will still need to select the mod for a new game.

    +

    Mod names

    +

    Mods need to conform to github repo naming rules, but best stay simple and use only letters, digits, and dashes -. Dashes are automatically converted to spaces for display and use within Unciv. Many punctuation or extended unicode characters might work, but at best potential users won't find them attractive, at worst we'll refuse support when you run into problems :smiling_imp:

    +

    Mod components

    +

    Mods are located in a /mods directory, on Desktop that should be next to your .jar file.

    +

    Mods typically have 2 subfolders: +- jsons - here you should put files that alter the data of game objects, the order of the files is as in the base json files. More information on these can be found here +- Images - here you should put game images, as in the base image files. Please read the atlas chapter for important details.

    +

    In order to remove objects from the game, you'll need to create a ModOptions file in the /jsons subfolder - there's an example here

    +

    In a base ruleset mod, ALL the original objects are removed - this is done by adding a "isBaseRuleset":true configuration to your modOptions file, like so

    +

    For an example, you can refer to the example mod - just download the Example-Aliens-Mod and put it in a /mods folder next to the jar, run Unciv, start a new game, and you'll be able to enable the mod, which will allow to you pick Aliens as a playable civilization!

    +

    If you want to add a new civilization as a mod, you should check out the Civ making instructions to see what's required, or see the example Aliens mod =)

    +

    More on Images and the texture atlas

    +

    Images are combined (at runtime) into texture images with an 'atlas', so if you see "game.atlas" and "game.png" files being generated, now you know what for. Most mods will need only one pair of those, the base game has around four.

    +

    When the game runs from a packaged distribution (android, jar), the texture+atlas files alone are relevant, so you need to include them in your repository and keep them up to date. Actually omitting the original images would work for these uses, but we still recommend including them, so developers running from source can access them.

    +

    If your mod has lots of images (or large ones), the textures might 'spill' into additional texture ".png" files - 2048x2048 is the limit for a single texture pack. This is not good for performance, which is why the base game controls which kinds of images go together into one texture(+atlas). This works for mods, too: Create not only one Images folder, but several, the additional ones named "Images.xyz", where xyz will become the filename of the additional texture file (So don't use both Images and Images.game - those will clash). Look at the Unciv base game to get a better idea how that works. To minimize texture swaps, try to group them by the situation where in the game they are needed. You can distibute by folder, but having the same subfolders under several "Images.xyz" and distributing the images between them will also work.

    +

    Adding maps to mods

    +

    You can also add maps to mods, so they'll be available to players who download your mod.

    +

    A mod can also be maps-only, if all you want to do is share your maps.

    +

    When you've finished making your map in the Map Editor, save it, and it will be in the /maps folder of your game.

    +

    Copy it to a /maps folder in your mod, and you're done!

    +

    Getting your mod out there

    +

    In order to make your mod downloadable by anyone, you need to create a Github repository (instructions here)

    +

    The Images and jsons folders need to be in the root directory of the repo - see here for example.

    +

    You can then manually download the mod from within the Mod Manager in Unciv:

    +
      +
    • From Unciv's main screen, click "Mods"
    • +
    • Click "Download mod from URL", and enter the location of your Github page
    • +
    • The game will automatically download and extract your mod, and it'll be ready to use!
    • +
    +

    Once you've tested that your mod CAN be downloaded, and that it works well once downloaded, you're ready for the final stage - GETTING IT TO THE USERS AUTOMATICALLY.

    +

    In order to do this, all you need to do is:

    +
      +
    • Go to your Github page
    • +
    • Click the gear icon next to the About (top-right part of the page)
    • +
    • In 'Topics', add "unciv-mod"
    • +
    +

    When you open your app, it will query Github's list of repos with that topic, and now YOUR repo will appear there!

    +

    I have the mod, now what?

    +

    The primary use of mods is to add them when starting a new game, or configuring a map. This will mean that both the ruleset of the mod, and the images, will be in use for that specific game/map.

    +

    For mods which are primarily visual or audio, there is a second use - through the mod manager, you can enable them as permanent audiovisual mods. This means that the images, sounds (or upcoming: music) from the mod will replace the original media everywhere in the game.

    +

    Mod location for manual loading of mods

    +

    In general, you should never be manually-loading your mods - not only is this clunky, it's also more error-prone. Unless you have a very specific use-case, you probably shouldn't be doing this.

    +

    In Android, they should go into the Android/data/com.unciv.app/files/mods directory.

    +

    In Chromebook, go to "Play files", should be on the sidebar on the left side of the window under "My files". +Click the 3 vertical dots on the top right-hand corner of the window below the "X". +If the option "Show all Play folders" does not have a check next to it click it. You should see some new files that appear on your screen. +Now navigate to Android/data/com.unciv.app/files/mods

    +

    When loading a mod, it needs to be in its own folder in /mods - this is how you will work when you're editing your mod.

    +

    Other

    +

    Existing mods can be found here!

    +

    A list of uniques and how to use them can be found here!

    +

    Some images don't exist at all in the base game, but can be added in mods. For more info, see Audiovisual Mods.

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Project-structure-and-major-classes/index.html b/site/wiki/Project-structure-and-major-classes/index.html new file mode 100644 index 0000000000..12cb3d5df0 --- /dev/null +++ b/site/wiki/Project-structure-and-major-classes/index.html @@ -0,0 +1,852 @@ + + + + + + + + + + + + + + + + Project structure - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Project structure

    +

    Since LibGDX, and therefore Unciv, are built for multi-platform support, the project structure is built accordingly.

    +

    99% of the code is in the Core project, which contains all the platform-independant code.

    +

    The Desktop and Android folders contain platform-specific things, and the Android folder also contains the game Images and the all-important Assets, which are required for running from Desktop as well, so we bundle them up into the .jar file when releasing.

    +

    The Test folder contains tests that can be run manually via gradle with ./gradlew tests:test, and are run automatically by Travis for every push.

    +

    Translations

    +

    Before we get to the Classes, a word on Languages. Unciv is playable in several handfuls of languages, and there's magic to support that. Whenever you include a new string in code you will need to give it a quick evaluation - will users see it, and if so, what do I need to do to support its translations. Sometimes you may not need to do anything, sometimes you will add a line to the translation templates, and sometimes you will adapt the string formatting to support the translations. For details, see the 'Translation generation - for developers' chapter.

    +

    Major classes

    +

    Civ, and therefore Unciv, is a game with endless interconnectivity - everything affects everything else.

    +

    In order to have some semblance of order, we'll go over the main classes in the order in which they are serialized.

    +

    So yes, you can - for instance - get the center tile of a city, a TileInfo, directly from CityInfo. But delving into all the connections would only harm the point of this overview, that's what the actual code is for ;)

    +

    The Game State:

    +
      +
    • GameInfo
        +
      • CivilizationInfo
          +
        • CityInfo
        • +
        +
      • +
      • TileMap
          +
        • TileInfo
            +
          • MapUnit
          • +
          +
        • +
        +
      • +
      • RuleSet (unique in that it is not part of the game state)
      • +
      +
    • +
    +

    The UI:

    +
      +
    • MainMenuScreen
    • +
    • NewGameScreen
    • +
    • WorldScreen
    • +
    • CityScreen
    • +
    • MapEditorScreen
    • +
    • Picker Screens - TechPickerScreen, PolicyPickerScreen, ImprovementPickerScreen, PromotionPickerScreen
    • +
    +

    Game State

    +

    The Game - GameInfo

    +

    First off, let's clarify: When we say "The Game", we mean the state of the game (what turn it is, who the players are, what each one has etc) and not the UI of the game.

    +

    That is, The Game is the currently played game, not Unciv.

    +

    The game contains three major parts:

    +
      +
    • The list of the players, or civilizations - List<CivilizationInfo>
    • +
    • The map upon which the game is played - TileMap
    • +
    • The ruleset by which the game is played - RuleSet. This includes what technologies, buildings, units etc. are available, and IS NOT serialized and deserialized, but comes straight from the game files - more on that later.
    • +
    • Parameters unique to this game - difficulty, game speed, victory conditions, etc.
    • +
    +

    When we save the game, or load the game, we're actually serializing and deserializing this class, which means that the this class is the root of the entire game state.

    +

    Most objects in the "state tree" have a transient reference to their parent, meaning the tree can be traversed in-code in all directions, and frequently is.

    +

    A Civilization - CivilizationInfo

    +

    This represents one of the players of the game, and NOT a specific nation - meaning, not France, but rather "Player X who is France in this game". In another game, there will be another France.

    +

    As one of the focal points of the game, it contains a lot of important information, the most important of which are:

    +
      +
    • The list of cities the civilization has - List<CityInfo>
    • +
    • Which nation this is - references a certain Nation (part of the ruleset)
    • +
    • Various Managers for the different aspects of the civilization - PolicyManager, GoldenAgeManager, GreatPersonManager, TechManager, VictoryManager, DiplomacyManager
    • +
    +

    A City - CityInfo

    +

    This contains the information about a specific city.

    +

    Beyond basic information like name, location on map etc, the most important classes it contains are:

    +
      +
    • Calculating the yield of the city - CityStats
    • +
    • Managers for the various aspects - PopulationManager, CityConstructions, CityExpansionManager
    • +
    • The tiles controlled and worked by the city - only their locations are permanently saved in the CityInfo, the actual information is in the TileInfo in the TileMap
    • +
    +

    The map - TileMap

    +

    This contains mostly helper functions and acts as a wrapper for the list of tiles it contains

    +

    A tile - TileInfo

    +

    Each tile is comprised of several layers, and so has information for each.

    +

    Tiles have, primarily: +- A base terrain - Grassland, Hills, Desert etc. References a certain Terrain (part of the ruleset) +- An optional terrain feature - Forest, Jungle, Oasis etc. References a certain Terrain (part of the ruleset) +- An optional resource - Iron, Dye, Wheat etc. References a certain TileResource (part of the ruleset) +- An improvement built on the tile, if any. References a certain TileImprovement (part of the ruleset) +- The units that are currently in the tile - MapUnit

    +

    A unit on the map - MapUnit

    +

    Unlike buildings, Unit in Unciv has two meanings. One is a Type of unit (like Spearman), and one is a specific instance of a unit (say, a Babylonian Spearman, at a certain position, with X health).

    +

    MapUnit is a specific instance of a unit, whereas BaseUnit is the type of unit.

    +

    Main information: +- A name - references a specific BaseUnit +- Health and Movement +- Promotion status - UnitPromotions

    +

    Ruleset

    +

    So far so good - but what of everything that makes Civ, Civ? The units, the buildings, the nations, the improvements etc?

    +

    Since these things remain the same for every game, these are not saved on a per-game basis, but rather are saved in json files in Unciv's asset folder.

    +

    Each class in the game state that saves one of these will reference it by name, and when the game is running it will check the Ruleset to find the relevant information for that object.

    +

    The various objects are: +- Technology - referenced mainly in CivilizationInfo.TechManager +- Nations - referenced mainly in CivilizationInfo +- Policy - referenced mainly in CivilizationInfo.PolicyManager (seeing a pattern here?) +- Building - referenced mainly in CityInfo.ConstructionManager +- BaseUnit - referenced mainly in MapUnit +- Promotion - referenced mainly in MapUnit +- Terrain - referenced mainly in TileInfo +- TileResource - referenced mainly in TileInfo +- TileImprovement - referenced mainly in TileInfo

    +

    There are also Translations in the Ruleset, but they technically have nothing to do with the game state but rather with the UI display.

    +

    The information for all of these is in json files in android\assets\jsons

    +

    UI

    +

    UncivGame is the 'base' class for the UI, from which everything starts, but it itself doesn't do much.

    +

    When we change a screen, we're changing a value in UncivGame, the interesting stuff happens in the screens themselves.

    +

    The main menu - MainMenuScreen

    +

    This is what the user sees when first entering the game. It acts as a hub to loading games, adding mods, options etc, without loading an actual game upfront - this allows us to differentiate between "User can't enter game" and "User can't load game" problems

    +

    Starting a new game - NewGameScreen

    +

    This is basically a giant setting screen for GameOptions and MapOptions classes, divided into:

    +
      +
    • GameOptionsTable - game speed, mods, etc
    • +
    • MapOptionsTable - either from preexisting map file or generated, in which case: size, map generation type, etc.
    • +
    • PlayerPickerTable - What civs are in the game and who controls them
    • +
    +

    The World Screen - WorldScreen

    +

    90% of the game is spent on this screen, so naturally it's the fullest, with the most things happening.

    +

    This is the main hub of the game, with all other screens being opened from it, and closing back to reveal it.

    +

    Most notable are: +* The map itself - a TileMapHolder - with each of the rendered tiles being a TileGroup +* The information panels - WorldScreenTopBar for stats and resources, UnitTable for the currently selected unit, TileInfoTable or the currently selected tile, BattleTable for battle simulation, and NotificationsScroll for the notifications +* The minimap - MinimapHolder +* Buttons linking to other screens - to the TechPickerScreen, EmpireOverviewScreen, and PolicyPickerScreen +* The almighty Next Turn button

    +

    The city screen - CityScreen

    +

    The second-most important screen.

    +

    Notable parts: +* the City Stats table - should definitely be its own class come to think of it +* The construction list and current construction (bottom left) - ConstructionsTable +* Existing buildings, specialists and stats drilldown - CityInfoTable

    +

    Others

    +

    A few words need to be said about the NextTurn process, but there isn't really a good place for it so I'll put it here.

    +

    We clone the GameInfo and use a "new" GameInfo for each turn because of 2 reasons.

    +

    The first is multithreading and thread safety, and the second is multiplayer reproducibility.

    +

    The first point is pretty basic. The NextTurn needs to happen in a separate thread so that the user can still have a responsive game when it's off doing stuff. Stuff in the GameInfo changes on NextTurn, so if you're rendering that same GameInfo, this could cause conflicts. Also, after NextTurn we generally autosave, and if stuff changes in the state while we're trying to serialize it to put it in the save file, that's Not Fun. A single clone solves both of these problems at once.

    +

    The second point is less obvious. If we use our mutable state, changing stuff in place, then what happens when we're playing in Multiplayer? Multiplayer is based upon the fact that you can receive an entire game state and go from there, and in fact the move to multiplayer was what made the whole "clone" thing necessary (on the way it also solved the aforementioned threading problems)

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Regions/index.html b/site/wiki/Regions/index.html new file mode 100644 index 0000000000..bab7c28f3c --- /dev/null +++ b/site/wiki/Regions/index.html @@ -0,0 +1,826 @@ + + + + + + + + + + + + + + + + Regions - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Regions

    +

    The Concept

    +

    During the generation of a random map (only; not pre-made maps) the map is split into a number of regions equal to the number of major civs. Each region gets classified according to its prevalent terrain, or if unable to be classified is called a "hybrid" region. +The region type corresponds to the start bias of the civs as they are distributed. +The region type also determines start placement and what luxuries will appear in the region.

    +
    Example + +![](https://user-images.githubusercontent.com/63475501/140308518-ad5a2f50-d5f1-4467-a296-3a67f6d0b007.png) + +
    + +

    How to define region behavior in your mod

    +

    The game will work without any extra json definitions, but if you want the region system to work well when generating maps for your mod, these are the relevant uniques to define.

    +

    Terrains.json

    +

    "Always Fertility [amount] for Map Generation", "[amount] to Fertility for Map Generation" - these determine how good a terrain is for purposes of dividing land up fairly. The numbers are arbitrary but should reflect the relative value of the terrains.

    +

    "A Region is formed with at least [amount]% [simpleTerrain] tiles, with priority [amount]", +"A Region is formed with at least [amount]% [simpleTerrain] tiles and [simpleTerrain] tiles, with priority [amount]" - these determine the rules for when a region is classified as eg a "desert" region. Terrains are evaluated in ascending priority order, so in the base ruleset tundra regions are checked first. +"A Region can not contain more [simpleTerrain] tiles than [simpleTerrain] tiles" - a useful compliment to the sum-of-two-terrains criterium above, if both terrains are in and of themselves terrain types. So in the base ruleset a large enough sum of jungle and forest allows a region to be classified as jungle, but only if there is more jungle than forest. +"Base Terrain on this tile is not counted for Region determination" - for terrain features that are unremovable or otherwise dominate the tile. Used for Hills in the base ruleset. +A region not fulfilling any criteria is classified as "Hybrid"

    +

    "Considered [terrainQuality] when determining start locations" - where "terrainQuality" is one of "Food", "Production", "Desirable", "Undesirable". Usually used together with the "" or "" to determine what terrain is attractive when determining start locations. Note: if there are none of these for a terrain, the game will use the base stats of the terrain to guess a quality, but if there are any, the game will assume that they are complete.

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Translating/index.html b/site/wiki/Translating/index.html new file mode 100644 index 0000000000..4cb7ff6dd1 --- /dev/null +++ b/site/wiki/Translating/index.html @@ -0,0 +1,945 @@ + + + + + + + + + + + + + + + + Translating - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + + + + +
    +
    + + + + +

    Starting out

    +

    The translation files are at /android/assets/jsons/translations

    +

    If you're adding a new language, you'll need to create a new file ('Create a new file' to the right of the folder name in the UI), and copy into it the contents of template.properties

    +

    If you're adding stuff to an existing language, simply start editing the file!

    +

    You don't need to download anything, all translation work can be done on the Github website :)

    +

    When you feel that you're ready to add your translation to the game, you'll need to create a merge request, which takes your changes and puts them into the main version of the game - it's pretty straightforward once you do it

    +

    Pitfalls

    +
      +
    • +

      If a translation template (the stuff to the left of "=") contains square brackets, you will have to include each of them verbatim in your translation, but you can move them. Upper/lower case is relevant! e.g. All [personFilter] are cool can be translated as Tous les [personFilter] sont cool, but not as Tous les [personnages] sont cool, and neither as Nous sommes vraiment cool. Failing this is the main cause of your PR's showing up with red "x"es and "checks failed".

      +
    • +
    • +

      Blanks: Watch out for blanks at the start of a line or two of them before the equals sign. If you got such a line - those blanks are part of the translation key and must not be deleted on the left side, and you should probably also include them in your translation (unless your language doesn't need spaces to separate things).

      +
    • +
    • +

      Changes in the templates: When we find a typo in the english texts and fix it, or marginally change a wording, the template changes. Often the old template will not be automatically fixed in the existing translations, because it's a lot of work and in most cases the developers cannot be sure the translation is still correct. For you, that might look like your translations are simply disappearing with an update. In such a case, you have the option to use github's history to look up old versions, copy the old translation, place it where the new template now says "requires translation" - and proofread and adapt it to the new english version. The history link for each file is in the top right area and has a nice round clock icon.

      +
    • +
    +

    Wait, what just happened?

    +

    Like most open-source projects, Unciv is developed at Github, so if you don't have a user you'll first have to create one. The way Github works is the following:

    +
      +
    1. +

      You create a 'fork' repo, i.e. copy, of Unciv that belongs to your user (myUser/Unciv)

      +
    2. +
    3. +

      You make changes to your copy. These changes are called a 'commit'.

      +
    4. +
    5. +

      You make a pull request, which is basically asking for the changes you made on myUser/Unciv to be merged into the main repo (yairm210/Unciv)

      +
    6. +
    +

    When you ask to 'edit' a file in yairm210/Unciv, these stages happen automatically - but it's important to understand what's happening behind the scenes do you understand where the changes actually are!

    +

    Why not use a crowdsourcing translation website like <...>?

    +
      +
    1. +

      Testing. Currently, translations undergo a number of tests for verification. This allows some language changes to be accepted and others not, and it's all in the same platform with the same tests. External translation tools don't allow for this.

      +
    2. +
    3. +

      History and revisions. This is what Git was made for, and nothing like it exists in the world. I'm not exaggerating.

      +
    4. +
    5. +

      Release cycle. We release versions weekly. If we need to take information from an external website every time, and for many that I've checked - you need to download the info as a csv or something and convert it. Every extra step hurts.

      +
    6. +
    7. +

      Discussions. Most crowdsourcing translation websites don't allow for discussions and corrections on translations. Github does.

      +
    8. +
    9. +

      Mass changes. If we're changing the source of the translation but want to keep the various destinations (say, we change "Gold from trade routes +[amount]%" to "+[amount]% Gold from trade routes"), if all the translation files are in Git we can do that in 1 minute. If it's external, this varies greatly.

      +
    10. +
    +

    Other notes

    +

    Make sure that you make the changes in the 'master' branch in your repo!

    +

    Each untranslated phrase will have a "requires translation" line before it, so you can quickly find them. You don't need to remove them yourself if you don't want to - they will be automatically removed the next time we rebuild the file.

    +

    Do as much as you're comfortable with - it's a big game with a lot of named objects, so don't feel pressured into doing everything =)

    +

    Note that Right-to-Left languages such as Arabic and Hebrew are not supported by the framework :/

    +

    Translation generation - for developers

    +

    The automatic template generation

    +

    Before releasing every version, we regenerate the translation files.

    +

    Sometimes, new strings (names, uniques, etc) are added in the json files. In order to not have to add every single one to the translation files manually, we have a class - TranslationFileWriter - that, for every language:

    +
      +
    • Goes over the template.properties and copies translation lines
    • +
    • For every json file in the jsons folder
        +
      • Selects all string values - both in objects, and in arrays in objects
      • +
      • Generates a 'key = value' line
      • +
      +
    • +
    +

    This means that every text that ISN'T in the jsons needs to be added manually to the template.properties in order to be translated! +That also means if you've been adding new json structures you (or someone) should check TranslationFileWriter and see if it is able to cope with them.

    +

    Rules for templates added manually

    +

    Building a new UI and doing something like popup.add("Hello world".toLabel()) is a typical case: This is not contained in json data, so you'll have to add the template to template.properties yourself. For this example, adding Hello world = somewhere in a line of its own could suffice.

    +

    Note the space at the end - it's absolutely required, and see to it your editor does not destroy your work. If you want to make sure, use Android Studio for git integration, but edit the file in an external editor, then run the unit tests locally before pushing. (to do: add link for instructions how to do that)

    +

    Leading spaces on a translation line or more than one space between the text and the = would mean these spaces are a key part of the string to be translated. That can work, but be warned: translators often overlook that those spaces are a required part of both template and translation, so if you can do without, then doing without is safer.

    +

    Translation templates can use placeholders, and there's two varieties: [] and {}. Square ones take precedence over curly ones, and nesting works only with a single level of curly nested inside one level of square. I both cases the symbols themselves ([]{}) are removed by the translation engine.

    +

    Square brackets [] mean the outer and inner components are both translated individually. The outer template will use alias names inside the brackets - example: Your code outputs "Everyone gains [5000] gold!", then the translation template should be "Everyone gains [amount] gold! = ". The translation engine would translate the "Everyone gains [] gold!" and "5000" individually and reassemble them - of course, the number is simply passed through. But in other cases that could be e.g. a Unit name that would be translated, and you could trust that translations for units are already handled just fine. Note that uniques often use the feature, but it is in no way limited to them. It it makes life easier for translators, use it.

    +

    Curly brackets {} are simpler - the contents within the brackets are translated individually, while the outer parts are passed through verbatim. Example: "+$amount${Fonts.gold} {Gold}".toLabel() - note the first ${} is a kotlin template while the second pair becomes part of the string. It tells the translation engine to ignore the numbers and the symbol but to translate the single word "Gold".

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Translations,-mods,-and-modding-freedom-in-Open-Source/index.html b/site/wiki/Translations,-mods,-and-modding-freedom-in-Open-Source/index.html new file mode 100644 index 0000000000..05fa50a7ad --- /dev/null +++ b/site/wiki/Translations,-mods,-and-modding-freedom-in-Open-Source/index.html @@ -0,0 +1,907 @@ + + + + + + + + + + + + + + + + Translations, mods, and modding freedom in Open Source - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Unciv is, at its core, a remake of Civ V, meaning mechanics-wise there's almost by definition not much place for innovation. +In terms of UI, there's nothing here that hasn't been done dozens of times, with far greater polish. +However, there is one area where Unciv is groundbreaking: in its accessibility of translations, the possibility space of its mods, and the relationship between them.

    +

    Translations

    +

    The translation process

    +

    So let's start with translation. Surely this is a solved problem, right? Source text + language = translated text, and this information needs to be in a file so the game can read it. What makes us different from, for example, Firaxis?

    +

    There are a couple of things, but the most significant is that this is an open-source game, and thus the translations are open-source as well. +This means translators are both amateurs and not obligated to translate, so if translating is difficult, they simply won't.

    +

    Amateurs can make mistakes, which is why it's vital that mistakes are easy to spot. That means that formats like "translation key" - e.g. DIPLOMACY_GREETING = Siamo lieti di fare la vostra conoscenza. are much less effective than A pleasure to meet you. = Siamo lieti di fare la vostra conoscenza. This format lends itself both the easier translation (it's immediately obvious what needs to be translated) and actual collaboration.

    +

    A common suggestion that we get (by people with little familiarity with the project) is to "use a website for translation". This is not bad advice for a small open source game, but there are multiple disadvantages that (for now) no translation website provides enough advantage to outweigh:

    +
      +
    1. +

      Testing. Currently, translations undergo a number of tests for verification - more on that later! This allows some language changes to be accepted and others not, and it's all in the same platform with the same tests. External translation tools don't allow for this.

      +
    2. +
    3. +

      History and revisions. This is what Git was made for, and nothing like it exists in the world. By itself this would not

      +
    4. +
    5. +

      Release cycle. We release versions semiweekly, and if we needed to upload changes to the translation website for every in-game change, and download them for every release, that's extra work. For some websites this is automate-able - for most it is not.

      +
    6. +
    7. +

      Discussions. Most crowdsourcing translation websites don't allow for discussions and corrections on translations. Github makes every translation collaborative work.

      +
    8. +
    9. +

      Mass changes. If we're changing the source of the translation but want to keep the various destinations (say, we change "Gold from trade routes +[amount]%" to "+[amount]% Gold from trade routes"), if all the translation files are in Git we can do that in 1 minute. If it's external, this varies greatly.

      +
    10. +
    +

    Here are some ways that we managed to go wrong in the past:

    +
      +
    • +

      Putting all languages into the same file ("one big translation dictionary") - when multiple people edit this file for different languages, they can conflict with each other. Separate to different files for simpler management.

      +
    • +
    • +

      Using json - json is great for machines, but less so for humans, who can easily make mistakes. Json format is surprisingly finnicky, miss a closing " and the whole file is now unreadable.

      +
    • +
    +

    The format we decided to go for is one file per language, delimited by " = " for visual separation, in a .properties file. Lines starting in # are considered comments, so we can add comments for translators.

    +

    Building the translation files

    +

    As stated, Unciv releases versions semiweekly, and very often these changes include new objects or new UI elements. How do we keep all translation files up to date?

    +

    In Unciv, all object data is stored in json format. This allows us to iterate on all objects, regardless of type, and extract the various text fields (strings or lists of strings). We avoid duplication by saving all translation texts we've already added, and use the existing translations to populate the "value" for each translation "key" we found in the json files.

    +

    Since we rebuild the entire translation file every time, there's currently no way for translators to retain their own comments for future translators. +But on the other hand, since for each line that we add we already know if it's translated or not, this allows us to add a # Requires translation line before every non-translated line, which helps translators for languages that are almost fully translated to easily locate the new or changed terms for translation with ctrl+f (and of course this marking will disappear the next time we rebuild the file).

    +

    Since there are UI texts that are not part of any specific object (like "Start new game"), we have a separate template.properties file for texts to translate that are not in the json files. Unlike adding objects, where the developer doesn't need to address the translation files at all since it's all linked, when adding UI elements with new texts devs need to remember to add the texts to template.properties file.

    +

    Translation placeholders

    +

    This is all well and good for specific text-to-text translations, but what about translating "A Temple has been built in Rome"? The same template could potentially be any building name, or any city name!

    +

    We do this with placeholders, which looks something like this: [construction] has been built in [cityName] = [cityName] ha costruito [construction]. +As you can see, the placement of the parameters can change between languages, so we have to name all parameters.

    +

    This also means that there can be explicitly wrong translations - if any parameter that appears in the source does not appear in the translated version, we won't be able to display this in-game! This is one of the translation tests that we mentioned earlier - when a translator opens a PR, the game undergoes build & test via the Github Actions, and will notify on failures. Finding the text that warns of the failure within the action output is currently mostly done by devs, but I hope to be able to automate this too someday.

    +

    To translate a text like "[Temple] has been built in [Rome]", therefore, we need to: +- Find the relevant translation (we do this by erasing all text between square brackets in input and finding the relevant translation text) +- Map placeholder names to input text (construction = Temple, cityName = Rome) +- Replace placeholders in translation with TRANSLATED input text (in [cityName] ha costruito [construction], replace "[cityName]" with translation of "Rome", and "[construction]" with translation of "Temple")

    +

    Translating mod data

    +

    The translation generation reads information from "a ruleset", i.e. the set of jsons defining the game's objects. +Every mod is also a ruleset, either replacing or adding to the base ruleset defined in the game. +This means that the same translation generation that we do for the base game can also be applied to mods, and so each modder can decide (from within the game) to generate translation files for his mod, and since mods are uploaded to Github to be widely available as part of the mod release methodology, translators will be able to translate those files the exact same way that they translate Unciv's base ruleset.

    +

    Uniques

    +

    Moddable unique effects

    +

    Every object in Unciv can include "uniques" - a list of strings, each granting a unique effect that is not applicable for every object of its type.

    +

    For example, the Palace building has the unique "Indicates the capital city", and the settler has the unique "Founds a new city". +This allows us to share effects between multiple units, and to avoid hardcoding and allow modders to add any effect to any object.

    +

    Here too we encounter the problem of "generic" uniques - how can we have these effects grant a building, some stats, etc, using the same unique for all objects? Why, with placeholders of course! For example, one building has "Requires a [Library] in all cities", where "Library" can be replaced with any other building for similar effects. We can then extract the parameters from the unique at runtime, to know how to resolve the unique's effects.

    +

    Since the translation template is the same as the unique template, these uniques are instantly translatable as well!

    +

    We do have a slight problem, though - since translation texts come directly from the json files, and the json files have "Requires a [Library] in all cities", how do we tell the translators not to directly translate "Library" but the take the parameter name verbatim? +Well, 95% of translation parameters fit nicely into a certain type - units, buildings, techs, terrains etc. So we can search for an object with than name, and since we find a Library building, we can put "Requires a [buildingName] in all cities = " as our translation line.

    +

    Filters

    +

    As time went on, we noticed that many of our "uniques" weren't so unique after all. Many were the same but with slightly different conditions. One affects all cities, one only coastal cities, and one only the city the building is built in. One affects Mounted units, one affects wounded units, one affects all water units, etc. We started compiling these conditions into "filters", which limited the number of uniques while expanding their range considerably.

    +

    Take the following example unique for a building: "[+1 Food] from [Deer] tiles [in this city]".

    +

    In its "placeholder" form, this is "[stats] from [tileFilter] tiles [cityFilter]". +stats can accept any list of stats, e.g. '-2 Gold, +1 Science', '+3 Culture', etc. +tileFilter can accept any number of tile parameters (base terrain e.g. 'Plains', terrain type eg. 'Land'/'Water', terrain features e.g. 'Forest', improvements e.g. 'Mine', resources e.g. 'Iron'. +cityFilter can accept 'in this city', 'in all cities', 'in capital', 'in coastal cities', etc.

    +

    There are also filters for units, all acceptable values are documented here.

    +

    Unique management with Enums

    +

    The further along we go, the more generic the uniques become, and the more of them there are. +Older uniques become new ones, by being merged or made more generic, and the older ones are deprecated. Deprecation notices are put on Discord, but a one-time message is easy to miss, and if you come back after a while you don't know what's changed. +Modders discover during gameplay that the values they put for uniques were incorrect.

    +

    All these problems are solved with a single solution - since all uniques are defined by their text, we can create an enum with ALL existing uniques, which lets us:

    +
      +
    • Find all usages of a unique in the IDE instantly
    • +
    • Mark deprecated uniques as such using @Deprecated("as of <versionNumber">) for devs (and modders!)
    • +
    • Compare uniques using enum values, which is faster
    • +
    +

    What's more, with a little bit of autodetection magic, we can determine the type of the parameter using its text. +Using the above example, "[stats] from [tileFilter] tiles [cityFilter]", we can tell by the names of the parameters what each one is supposed to be,. +We can then check at loading time for each unique, if its parameter values matches the parameter type it's supposed to have, which lets us catch incorrect parameters. +The "autodetection" of parameter types for translations can also be fed from here, leading to much more accurate translation texts - instead of detecting from an example (e.g. "Requires a [Library] in all cities" from the json), we now use a dev-inputted value like "Requires a [buildingName] in all cities". This allows us to accept multiple types, like for e.g. "Requires [buildingName/techName/policyName]".

    +

    Deprecated values can be detected due to the @Deprecated annotation, and can be displayed to the modders when loading the mod, together with the correct replacement.

    +

    Conditionals

    +

    Beyond the existing filters for units, buildings, tiles etc, there are some conditions that are global. For example, uniques that take effect when the empire is happy; when a tech has been researched; when the empire is at war; etc. +Rather than being 'build in' to specific uniques, these conditions can be seen as extensions of existing uniques and thus globally relevant.

    +

    For example, instead of "[+1 Production] [in all cities] when empire is happy", we can extract the conditional to "[+1 Production] [in all cities] ". This does two things: +A. Turns the 'extra' unique back into a regular "[stats] [cityFilter]" unique +B. Turns the conditional into an extra piece that can be added onto any other unique

    +

    Conditionals have a lot of nuance, especially regarding translation and ordering, so work in that field is more gradual.

    +

    What's next?

    +

    We have yet to fully map all existing uniques and convert all textual references in the code to Enum usages, and have yet to extract all conditionals from their uniques.

    +

    We already have a map of what uniques can be put on what objects - it won't take much to add that check as well and warn against uniques that are put on the wrong sorts of objects.

    +

    Once we build the full inventory of the uniques, instead of the wiki page that needs to be updated manually we'll be able to generate a list of all acceptable uniques and their parameters directly from the source of truth. Put that in a webpage, add hover-links for each parameter type, generate and upload to github.io every version, and watch the magic happen.

    +

    We'll also be able to notify modders if they use "unknown" uniques.

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Uniques/index.html b/site/wiki/Uniques/index.html new file mode 100644 index 0000000000..2e6bcd662f --- /dev/null +++ b/site/wiki/Uniques/index.html @@ -0,0 +1,1067 @@ + + + + + + + + + + + + + + + + Uniques - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Uniques

    + + +

    Overview

    +

    Every type of object has some traits that are shared across all, or most, objects of its kind. For example, a building's stat increase, cost and required tech; a unit's type, movement and attack; a resource's type, improvement and bonus stats from improvement. All such traits have their own fields in the said object types.

    +

    But there are also other traits, that are only in a small subset of objects will have. Units that can see submarines from more than one tile away, or can move after attacking, or has a combat bonus against a certain other type of unit. Buildings that give a free great person, or improve stats dependent on the population of a city, or provide extra yield to certain tiles. These traits cannot be given their own fields due to the huge number of them.

    +

    Instead, every special trait that an object has is encoded into a single parameter: the list of unique traits, or "uniques".

    +

    In the json files, this looks something like "uniques": ["Requires a [Market] in all cities", "Cost increases by [30] per owned city"].

    +

    As seen in the above example, in order to provide flexibility and generalization, Uniques have certain parameters, marked by the fact that they are inside square braces. These parameters can be changed, and the game will recognize the text inside them and act accordingly.

    +

    A list of all available uniques can be found here.

    +

    Generated Documentation

    +

    This part of the wiki is human-edited and partially out of date. However, we now have automatically generated documentation, complete for all Uniques that have been updated to the new UniqueType system. It is part of the main source tree and can be found here.. This version should always be up-to-date with the uniques and conditionals currently supported in the game.

    +

    Unique locations

    +

    Most uniques are "Global uniques" - meaning, they can be put in one of these places: +- Nation uniques - Always active for a specific Nation +- Policy uniques - Active once the policy has been chosen +- Building uniques - Active once the building has been constructed in any city +- Tech uniques - Active once the tech has been researched +- Era uniques - Active once in the specified era +- Religion uniques - Founder & Enhancer beliefs from your religion

    +

    Most uniques are ongoing - they describe something continuous. Some, however, are one-time actions (free technology, free unit, etc) - these cannot be put in a Nation unique, since unlike the other categories, there is no specific time to activate them. Such uniques will be marked in the documentation as "one time effect".

    +

    Parameter types

    +

    Parameters come in various types, and will be addressed as such inside the [square brackets].

    +
      +
    • amount - This indicates a whole number, possibly with a + or - sign, such as "2", "+13", or "-3".
    • +
    • unitName, buildingName, improvementName etc - Rather self explanatory. Examples: "Warrior", "Library", and "Mine", accordingly.
    • +
    • stat - This is one of the 7 major stats in the game - "Gold", "Science", "Production", "Food", "Happiness", "Culture" and "Faith". Note that the stat names need to be capitalized!
    • +
    • stats, tileFilter, unitFilter, cityFilter, constructionFilter/buildingFilter - these are more complex and are addressed individually
    • +
    +

    stats

    +

    This indicates a text comprised of specific stats and is slightly more complex.

    +

    Each stats is comprised of several stat changes, each in the form of "+{amount} {stat}", where 'stat' is one of the seven major stats mentioned above. +For example: "+1 Science".

    +

    These can be strung together with ", " between them, for example: "+2 Production, +3 Food".

    +

    A full example would be, for the "[stats] from every [buildingName]" unique:

    +

    "[+1 Culture, +1 Gold] from every [Barracks]"

    +

    tileFilter

    +

    TileFilters are split up into two parts: terrainFilters and improvementFilters. TerrainFilters only check if the tile itself has certain characteristics, while the improvementFilters only checks the improvement on a tile. Using the tileFilter itself will check both of these.

    +

    terrainFilters allow us to specify tiles according to a number of different aspects:

    +
      +
    • A filter names a specific json attribute (by name):
        +
      • Base terrain
      • +
      • Terrain features
      • +
      • Base terrain uniques
      • +
      • Terrain feature uniques
      • +
      • Resource
      • +
      • Natural wonder
      • +
      +
    • +
    • Or the filter is a constant string choosing a derived test:
        +
      • "All"
      • +
      • "Water", "Land"
      • +
      • "Coastal" (at least one direct neighbor is a coast)
      • +
      • "River" (as in all 'river on tile' contexts, it means 'adjacent to a river on at least one side')
      • +
      • "Open terrain", "Rough terrain" (note all terrain not having the rough unique is counted as open)
      • +
      • "Friendly Land" - land belonging to you, or other civs with open borders to you
      • +
      • "Foreign Land" - any land that isn't friendly land
      • +
      • "Enemy land" - any land belonging to a civ you are at war with
      • +
      • "Water resource", "Strategic resource", "Luxury resource", "Bonus resource"
      • +
      • "Natural Wonder" (as opposed to above which means testing for a specific Natural Wonder by name, this tests for any of them)
      • +
      +
    • +
    +

    Please note all of these are case-sensitive.

    +

    Also note: Resource filters depend on whether a viewing civ is known in the context where the filter runs. Water and specific tests require a viewing civ, and if the resource needs a tech to be visible, that tech to be researched by the viewing civ. The other resource category tests can succeed without a known viewing civ only for resources not requiring any tech. So - test your mod!

    +

    So for instance, the unique "[stats] from [tileFilter] tiles [cityFilter]" can match several cases: +- "[+2 Food] from [Lakes] tiles [in this city]" +- "[+1 Gold] from [Water] tiles [in all cities]" +- "[+1 Production] from [Forest] tiles [in all coastal cities]"

    +

    Please note that using resources is most use cases, but not in combat ones.

    +

    This is due to the fact that resources can be visible to some civs while invisible to others - so if you're attacking with a +10% combat bonus from Coal, while the enemy can't see coal, it could get weird.

    +

    improvementFilters only check for the improvements on a tile. The following are implemented: +- improvement name (Note that "Road" and "Railroad" do work as improvementFilters, but not as tileFilters at the moment.) +- "All" +- "Great Improvements", "Great" +- "All Road" - for Roads & Railroads

    +

    unitFilter

    +

    unitFilters allow us to activate uniques for specific units, based on:

    +
      +
    • unit name
    • +
    • unit type - e.g. Melee, Ranged, WaterSubmarine, etc.
    • +
    • "Land", "Water", "Air"
    • +
    • "land units", "water units", "air units"
    • +
    • "non-air" for non-air non-missile units
    • +
    • "Military", "military units"
    • +
    • "Civilian", "civilian units"
    • +
    • "All"
    • +
    • "Melee"
    • +
    • "Ranged"
    • +
    • "Nuclear Weapon"
    • +
    • "Great Person", "Great"
    • +
    • "Embarked"
    • +
    • "Wounded", "wounded units"
    • +
    • "Barbarians", "Barbarian"
    • +
    • "City-State"
    • +
    • Any exact unique the unit has
    • +
    • Any exact unique the unit type has
    • +
    • Any combination of the above (will match only if all match). The format is "{filter1} {filter2}" and can match any number of filters. For example: "[{Military} {Water}]" units, "[{Wounded} {Armor}]" units, etc. No space or other text is allowed between the "[" and the first "{".
    • +
    +

    cityFilter

    +

    cityFilters allow us to choose the range of cities affected by this unique:

    +
      +
    • "in this city"
    • +
    • "in all cities"
    • +
    • "in other cities"
    • +
    • "in all coastal cities"
    • +
    • "in capital"
    • +
    • "in all non-occupied cities" - all cities that are not puppets and don't have extra unhappiness from being recently conquered
    • +
    • "in all cities with a world wonder"
    • +
    • "in all cities connected to capital"
    • +
    • "in all cities with a garrison"
    • +
    • "in non-enemy foreign cities" - In all cities owned by civs other than you that you are not at war with
    • +
    • "in foreign cities"
    • +
    • "in annexed cities"
    • +
    • "in holy cities"
    • +
    • "in City-State cities"
    • +
    • "in cities following this religion" - Should only be used in pantheon/follower uniques for religions
    • +
    • "in all cities in which the majority religion is a major religion"
    • +
    • "in all cities in which the majority religion is a enhanced religion"
    • +
    +

    constructionFilter

    +

    ConstructionFilters allow us to activate uniques while constructing certain buildings or units. +For units, the UnitFilter is called. For Buildings, the following options are implemented:

    +
      +
    • "All"
    • +
    • "Buildings", "Building"
    • +
    • "Wonders", "Wonders"
    • +
    • "National Wonder"
    • +
    • "World Wonder" -- All wonders that are not national wonders
    • +
    • building name
    • +
    • The name of the building it replaces (so for example uniques for libraries will apply to paper makers as well)
    • +
    • an exact unique the building has (e.g.: "spaceship part")
    • +
    • "Culture", "Gold", etc. if the building is "stat-related" for that stat. Stat-related buildings are defined as one of the following:
    • +
    • Provides that stat directly (e.g. +1 Culture)
    • +
    • Provides a percentage bonus for that stat (e.g. +10% Production)
    • +
    • Provides that stat as a bonus for resources (e.g. +1 Food for Wheat)
    • +
    • Provides that stat per some amount of population (e.g. +1 Science for every 2 population [cityFilter])
    • +
    +

    Conditionals

    +

    Some uniques also allow for the placing of conditionals. These are conditions that need to be met for the unique to be active. In the unique "[+10]% Growth \<when at war>", the <when at war> part is a conditional, denoted by the pointy brackets. Making a building with this unique will provide a 10% Growth boost to cities with this building, but only as long as the empire is at war.

    +

    Multiple conditionals can be applied to the same unique, for example, you can have a promotion with the following unique: +"[+33]% Strength \<vs [Armored] units> \<in [Open terrain] tiles>" +Which will only apply the strength boost when fighting armored units in open terrain.

    +

    This system is currently in development, so only a small amount of conditionals exist, and only a few uniques can have conditionals for now. It will be expanded greatly, improving the amount of combinations that can be made and therefore the amount of different uniques that exist. +Uniques that support conditionals will be denoted with a "©" sign for now. +"Quantity of Resources gifted by City-States increased by 100%" - Replaced with "Quantity of Resources gifted by City-States increased by [amount]%"

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/Unit-related-JSON-files/index.html b/site/wiki/Unit-related-JSON-files/index.html new file mode 100644 index 0000000000..bc64e0ac83 --- /dev/null +++ b/site/wiki/Unit-related-JSON-files/index.html @@ -0,0 +1,888 @@ + + + + + + + + + + + + + + + + Unit related JSON files - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    + + + + +

    Unit related JSON files

    + + +

    Units.json

    +

    Link to original

    +

    This file should contain a list of all the units, both military and civilian, that you want to use in your mod.

    +

    Each unit can have the following attributes: +| attribute | Type | optional or not | notes | +| --------- | ---- | -------- | ----- | +| name | String | required | The name of the units (required) | +| unitType | String | required | The type of the unit. Must be in UnitTypes.json | +| cost | Integer (≥0) | defaults to 0 | The amount of production required to build this unit | +| movement | Integer (≥0) | defaults to 0 | The amount of movement points the unit has by default | +| strength | Integer (≥0) | defaults to 0 | The melee attack and defensive strength of the unit. If this and rangedStrength are ommited or 0, the unit will be a civilian | +| rangedStrength | Integer (≥0) | defaults to 0 | The ranged attack strength of the unit. If omitted, the unit cannot ranged attack | +| range | Integer (≥0) | defaults to 2 | The default range from which ranged attacks can be preformed | +| interceptRange | Integer (≥0) | defaults to 0 | Air units attacking within in this range will be intercepted | +| requiredTech | String | defaults to none | The tech required to build this unit. Must be in Techs.json | +| obsoleteTech | String | defaults to none | After researching this tech, the unit can no longer be build. Must be in Techs.json | +| requiredResource | String | defaults to none | Resource that is consumed by building this unit. Must be in TileResources.json | +| upgradesTo | String | defaults to none | Unit that this unit can upgrade to when it is available. Must be in Units.json | +| replaces | String | defaults to none | If this unit is unique to a nation, this is the unit it replaces. Must be in Units.json | +| uniqueTo | String | defaults to none | The nation that this unit is unique to. Must be in Nations.json | +| hurryCostModifier | Integer | defaults to 0 | If this unit is bought for gold/faith, it's price is increased by so much percent | +| promotions | List of Strings | defaults to none | A list of all the promotions the unit automatically receives upon being built. Each promotion must be in UnitPromotions.json | +| uniques | List of Strings | defaults to none | A list of the unique abilities this unit has. A list of almost all uniques can be found here | +| replacementTextForUniques | String | defaults to none | If provided, this will be displayed instead of the list of uniques. Can be used for better formatting. | +| attackSound | String | defaults to none | The sound that is to be played when this unit attacks. For possible values, see sounds +| civilopediaText | List | Default empty | see civilopediaText chapter |

    +

    UnitPromotions.json

    +

    Link to original

    +

    This file lists the available unit promotions.

    +

    Each promotion must have an icon, except progressions ending in " I", " II", " III" (no IV V VI allowed) are rendered by looking up an icon without those suffixes and adding stars.

    +

    Remember, promotions can be "bought" with XP, but also granted by the unit type, buildings, wonders and such. They are preserved when a unit upgrades, therefore special properties of nation unique units that can be inherited when they upgrade should be in a promotion, not uniques/stats in the units json (example: Slinger withdraw).

    +

    Each promotion can have the following properties: +| Attribute | Type | Optional? | Notes | +|-----------|------|-----------|-------| +| name | String | Required | See above for "I, II, III" progressions | +| prerequisites | List | Default empty | Prerequisite promotions | +| effect | String | Default empty | Deprecated, use uniques instead | +| unitTypes | List | Default empty | The unit types for which this promotion applies as specified in UnitTypes.json | +| uniques | List | Default empty | List of effects, see here | +| civilopediaText | List | Default empty | see civilopediaText chapter |

    +

    UnitTypes.json

    +

    Link to original

    +

    This optional file is used for defining new types of units. The names of these can be used in unitFilters, and these types determine what domain the unit moves in: over land, over water or through the air. If the file is ommitted, the following are automatically added: +Civilian, Melee, Ranged, Scout, Mounted, Armor, Siege, WaterCivilian, WaterMelee, WaterRanged, WaterSubmarine, WaterAircraftCarrier, Fighter, Bomber, AtomicBomber, and Missile.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    attributeTypeoptional or notnotes
    nameStringrequiredThe name of the unit type
    movementTypeStringrequiredThe domain through which the unit moves. Allowed values: "Water", "Land", "Air"
    uniquesList of Stringdefaults to noneA list of the unique abilities every unit of this type has. A list of almost all uniques can be found here
    +

    Sounds

    +

    Standard values are below. The sounds themselves can be found here.

    +
      +
    • arrow, artillery, bombard, bombing, cannon, chimes, choir, click, coin, construction, elephant, fortify, gdrAttack, horse, jetgun, machinegun, metalhit, missile, nonmetalhit, nuke, paper, policy, promote, setup, shipguns, shot, slider, swap, tankshot, throw, torpedo, upgrade, whoosh.
    • +
    +

    Mods can add their own sounds, as long as any new value in attackSound has a corresponding sound file in the mod's sound folder, using one of the formats mp3, ogg or wav (file name extension must match codec used). Remember, names are case sensitive. Small sizes strongly recommended, Unciv's own sounds use 24kHz joint stereo 8-bit VBR at about 50-100kBps.

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/_Footer/index.html b/site/wiki/_Footer/index.html new file mode 100644 index 0000000000..3cb33b33fc --- /dev/null +++ b/site/wiki/_Footer/index.html @@ -0,0 +1,697 @@ + + + + + + + + + + + + + + + + Footer - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    + + + + +

    Footer

    + +

    To edit this wiki, open a pull request against the files under /docs/wiki in the main Unciv repository. (Details)

    + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/site/wiki/_Sidebar/index.html b/site/wiki/_Sidebar/index.html new file mode 100644 index 0000000000..74dfbce9bd --- /dev/null +++ b/site/wiki/_Sidebar/index.html @@ -0,0 +1,725 @@ + + + + + + + + + + + + + + + + [Home](.) - My Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + \ No newline at end of file