GeoGet

Complete geocaching solutions

User Tools

Site Tools


user:skript:varsubst

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
user:skript:varsubst [2011/01/04 09:24]
gord
user:skript:varsubst [2021/10/10 10:14] (current)
mikrom
Line 3: Line 3:
  
 ===== Autor ===== ===== Autor =====
-  * **[[http://​www.geocaching.com/​profile/?​u=Gordici|gord]] , [[gord@atlas.cz|Gord]]** - specifikace,​ programování,​ dohadování se s Medwynem (to je obcas horší než něco naprogramovat ​;-) ) +  * **[[http://​www.geocaching.com/​profile/?​u=Gordici|gord]] , [[gord@atlas.cz|Gord]]** - specifikace,​ programování, dokumentace, dohadování se s Medwynem (to je občas ​horší než programování ​;-) ) 
-  * **[[http://​www.geocaching.com/​profile/?​u=Medwyn_cz|Medwyn_cz]] , [[medwyn@seznam.cz|Medwyn_cz]]** - nápad, specifikace,​ kibicování. Na konci vývoje si i trochu ušpinil ruce od Pascalu.+  * **[[http://​www.geocaching.com/​profile/?​u=Medwyn_cz|Medwyn_cz]] , [[medwyn@seznam.cz|Medwyn_cz]]** - nápad, specifikace,​ kibicování, dokumentace. Na konci vývoje si i trochu ušpinil ruce od Pascalu.
  
 | Pokud se Vám doplněk líbí, kliknutím na tlačítko Donate můžete přispět na jeho vývoj. | ~~PAYPAL business="​kopecky@klfree.net"​ message="​Prispevek na skript: varsubst"​~~ | | Pokud se Vám doplněk líbí, kliknutím na tlačítko Donate můžete přispět na jeho vývoj. | ~~PAYPAL business="​kopecky@klfree.net"​ message="​Prispevek na skript: varsubst"​~~ |
  
-Peníze na PayPal by přišly pouze Medwynovi, a to není fér. Raději nám napište email a domluvíme se na jiném způsobu příspěvku,​ třeba převodu na účet.+Peníze na PayPal by přišly pouze Medwynovi, a to není fér. Oba autoři na knihovně tvrdě makali. Raději nám napište email a domluvíme se na jiném způsobu příspěvku,​ třeba převodu na účet.
  
 ===== Automatická instalace ===== ===== Automatická instalace =====
Line 14: Line 14:
  
 ===== Diskuze ===== ===== Diskuze =====
-Diskuze o tomto skriptu se nachází na stránkách [[http://​www.geocaching.cz/​forum/​|Geocaching.cz]].+Diskuze o tomto skriptu se nachází na stránkách [[http://​www.geocaching.cz/​forum/​viewthread.php?​forum_id=20&​thread_id=17224|Geocaching.cz]].
  
-===== Funkce ​===== +===== Uživatelská dokumentace ​===== 
-Voláním knihovních funkcí (viz níže) dojde k náhradě proměnných ve tvaru **%JMENO%** ​išlusnou textovou hodnotouProměnné jsou vyhodnocovány podle hodnot ​instanci třídy **TGeo** (informace o bodu - keši) nebo **TWpt** (informace o doplňkovém bodu - final, parkoviště,​ ...) a podle globálních proměnných GeoGetu (např. GEGOGET_Datadir má proměnnou %GGDATADIR%).+Tato část textu je určena ​edevším pro uživatele GeoGetuRespektive pro uživatele těch skriptů GeoGetu, které využívají funkcí knihovny VarSubst. Odstavce ​jsou však povinnou četbou ​pro programátory skriptů.
  
-Všechny ​řádky začínající znakem # jsou považovány za komentář ​ignorovány.+<WRAP round important>​ 
 +Protože se jedná o knihovnu, není možné ji použít samostatně. Jako každá jiná knihovna i tato slouží programátorům (v tomto případě programátorům skriptů pro GeoGet) k tomu, aby zjednodušila jejich práci. Programátor ​začleněním knihovny do svého skriptu použije její funkce ​případně poskytne nějaké to klikátko k tomu, aby uživatel sám mohl upravovat šablony používané programátorovým skriptem. 
 +</​WRAP>​
  
-Všechny vstupní texty (šablonadatabázové hodnoty) jsou v kódování UTF-8výstup je volitelně v UTF-8 nebo Win-1250Uživatelské funkce musí mít výstup ​kódován v UTF-8.+==== Proč knihovna existuje ==== 
 +Knihovna je odpovědí na poptávku po //úžasně konfigurovatelných exportech//​. Každý by chtěl ve své navigaci vidět něco jinéhojinak seřazenéhojinak nadepsaného,​ jinak obarveného... (a to nejčastěji závislosti na lunární fázi měsíce a velikosti bot autora keše :-) ). 
 +Programátoři exportních skriptů však nemohou tyto požadavky vyslyšet a vyhovět každému.  
 +Posláním knihovny je umožnit maximální možnou konfiguraci s minimálním množstvím práce na obou frontách. Každý uživatel si nakonfiguruje ​výstup ​sám. A autor exportního skriptů má (relativní) klid.
  
-Knihovna ​zpracovává vstupní ​text následujícím způsobem:​ +==== Co knihovna dělá ==== 
-  - volá všechny uživatelské funkce, které byly registrované s příznakem bBefore +Knihovna ​dokáže prohledat ​text, najít ​něm nějaké vzory a přetransformovat je do vzorů jiných. V podstatě jde o nahrazování ​proměnných (Variables SubstitutionVarSubst).
-  - nahradí proměnné (s výjimkou proměnných pro listing) +
-  - nahradí logické proměnné +
-  - provede funkce REPLACE +
-  - nahradí TAGy (funkce TAG, IFTAG) +
-  - provede funkce ROT13 REVERSE +
-  - zpracuje podmíněné nahrazení funkcí IF +
-  - volá všechny uživatelské funkce, které byly registrované bez íznaku bBefore +
-  - náhrada ​proměnných ​pro listing ​(LISTINGLONGLISTING,​ SHORTLISTING) +
-  - provede funkci REPLACEFULL ​+
  
-Náhrada listingu je posunuta až na koncec zpracování proto, aby se co nejméně pracovalo s dlouhými texty a tím se zvýšila rychlost. Text listingu již není třeba dál zpracovávat,​ takže vlastně ani není důvod k tomu, aby se to dělalo dříve. Jediné, co by snad mohlo být potřeba udělat, je nahradit nějaký konstatntní text v listingu jiným textem a to lze realizovat funkcí REPLACEFULL.+Vysvětlíme si to raději na příkladu.
  
-===== Veřejné funkce knihovny ===== +Chtěli bychom do popisu bodu v navigaci generovat text "Bod typu **Traditional Cache** od autora **Novoročník** založen dne **1.1.2001**"​.
-Použití knihovny spočívá ve volání nekteré z knihovních funkcíTěch obsahuje knihovna celou řadu, ale jen některé z nich jsou určené k volání mimo knihovnu (veřejné funkce)Seznam veřejných funkcí:+
  
-<​code ​delphi>function VarSubstGeo(geo:​TGeo;​ sTemplate:​string;​ bAnsi:​boolean;​ var sOutput:​string):​ boolean;</​code> ​+Knihovně tedy předáme přibližně takto formátovaný text, říkejme mu šablona: 
 +<​code>​ 
 +  Bod typu <​b>​%TYPE%</​b>​ od autora <​b>​%AUTHOR%</​b>​ založen dne <​b>​%HIDDEN%</​b>​ 
 +</​code>​
  
-  * Nahrazuje proměnné hodnotami z hlavního bodu (keš, waymark) ​+Kromě textu je knihovně předán i GC kód kešeale o to se uživatel většinou nemusí starat.
  
-<code delphi>​function VarSubstWpt(wpt:TWpt; sTemplate:​string;​ bAnsi:​boolean;​ var sOutput:​string):​ boolean;</code> +Knihovna vrátí text upravený do tvaru: 
-  ​* Nahrazuje proměnné hodnotami z WPT bodu (parkoviště,​ stage of multi=cache, ​...)+<​code>​ 
 +  ​Bod typu <​b>​Traditional Cache</​b>​ od autora <​b>​Novoročník</​b>​ založen dne <b>1.1.2001</​b>​ 
 +</​code>​
  
-<code delphi>​function VarSubstAddFunctionReplaceGeo(fce:​VarSubst_TypeReplaceFunc;​bBefore:​boolean):​boolean;</​code>​ +==== Jak to knihovna dělá ==== 
-  * Registruje uživatelskou funkci pro nahrazování ​proměnných podle TGeo.+Knihovna zná nějaká klíčová slova (viz dále, přehled možných vzorů), na která vnitřní logika reaguje a zpracuje je. 
 +Zpracování probíhá pomocí vyhledávání vzorů, jejich interpretace a nahrazování. Taková sranda něco stojí, v našem případě je to čas. A možná trocha oxidu uhličitého,​ který produkují elektrárny při výrobě elektřiny.
  
-<code delphi>​function VarSubstAddFunctionReplaceWpt(fce:​VarSubst_TypeReplaceFunc;​bBefore:​boolean):​boolean;</​code>​ +==== Jak se s knihovnou pracuje ==== 
-  * Registruje uživatelskou funkci pro nahrazování proměnných podle TWpt.+Uživatelé nepracují přímo s knihovnou, ale spíše se skriptem, který knihovnu využívá.
  
-<code delphi>​function VarSubstDelFunctionReplace(fce:​VarSubst_TypeReplaceFunc):​boolean;</​code>​ +Skripty většinou používají nějaké šablony uložené v textových souborech. Šablony obsahují příkazy pro knihovnu VarSubst. Při spuštění skriptu je šablona načtena a pro každý skriptem zpracovávaný bod jsou provedeny náhrady vzorů z šablony za skutečné hodnoty. 
-  * Ruší registraci uživatelské funkce+Takto zpracované výstupy jsou pak skriptem dále zpracovány (třeba zapsány do GPX souboru určeného pro navigaci).
  
-<code delphi>​procedure VarSubstDlgTemplateFile(sCaptionIDsPathFileTemplatestartDir:​string);</​code>​ +Pokud si chce uživatel skriptu změnit formát výstupustačí mu najít tu správnou šablonu a upravit si ji. Nic mu nebrání takové úpravy dělat v jeho oblíbeném textovém editoruale protože se jedná o častý úkonpřipravili jsme pro něj grafický editor šablon, který takové úpravy hodně zjednodušuje.
-  * Poskytuje formulář pro testování ​šablony.+
  
-<code delphi>​procedure VarSubstDlgTemplateString(sCaption,​ ID, sTemplate, startDir:​string);</​code>​ +V každém skriptu může být editor vyvoláván různými způsoby. Nejjednodušší cestou je přidat volbu na otevření editoru do menu pluginy přímo v GeoGetu. Skript [[poigarmin|POI Garmin]] tak například publikuje do menu pluginy položku **POI Garmin - editor ​šablon**.
-  * Poskytuje formulář pro testování ​šablony.+
  
-<code delphi>​function VarSubstEncode(str:string):string;</​code>​ +|{{:user:skript:​varsubst:​formular.png?​500|Ukázka editoru}}| 
-  * Nahrazuje nebezpečné znaky, které brání správnému zpracování funkcí. Funkce najde uplatnění v uživatelských funkcích. ​+ **Ukázka editoru** ​ | 
  
-Ve funkcích jsou použity následující parametry:+V levé části okna je vidět šablona, v pravé potom výstup po jejím zpracování. 
 +Šablonu lze postupně upravovat, prohlížet si výstup na různých bodech a následně si ji, pokud se úpravy povedly, uložit.
  
-<box 95% right #f8f8f8 #f8f8f8 #f8f8f8 #​f8f8f8>​ +Náhled ovšem nezobrazuje přesně výsledek takjak je vidět na cílovém zařízení,​ ale jen text, který je cílovému zařízení předán. Uživatel se tedy musí alespoň ​základech orientovat ​v příslušném formátu dat. 
-|TGeo|struktura naplněná informacemi o konkrétním bodu (keši)| + 
-|TWpt|struktura naplněná informacemi o doplňkovém bodu| +Výsledek práce šablony je možné jediným tlačítkem zobrazit ve webovém prohlížeči. Při každé další aplikaci knihovny na upravenou šablonu (tlačítko Obnovit) ​je automaticky upraven HTML soubor, se kterým byl spuštěn prohlížeč,​ a pak stačí ​prohlížeči jen znovu načíst zobrazený soubor ​(tlačítko Obnovit, F5). 
-|sTemplate|vstupní text s šablonou obsahující nahrazované proměnné (čeština v UTF-8). Šablona obsahuje jména proměnných a funkcíkteré knihovna vyhodnocuje a najradi ​je vyhodnoceným textem. (Pokud má výsledný ​text obsahovat znak %, musí být šabloně vypsán jako HTML entita &​perc;​.)| + 
-|sOutput|výstupní text, kterém jsou proměnné nahrazeny ​příslušnými hodnotamiVýsledné kódování ​češtiny je podle proměnné bAnsi UTF-8 nebo Win-1250.| +**ID** definuje ID bodu (keše nebo WPT), jehož hodnoty budou použity pro vyhodnocení šablony. To, zda se jedná o ID bodu nebo WPT, knihovna rozlišuje sama podle toho, zda se jí příslušné ID podaří najít mezi body - pokud ne, hledá ID mezi doplňkovými body
-|bAnsi|požadavek ​na překódování výstupu do kódování ANSI (Win-1250). Místo hodnot ​**true** a **false** lze použít samopopisné konstanty **VARSUBST_ANSI** a **VARSUBST_UTF**.| + 
-|fce|uživatelem definovaná funkcekterá realizuje nahrazování nad rámec knihovních funkcí| +Při úpravách šablon je možné využít seznamuvybrat z něj požadovanou proměnnou nebo funkci a její kostru vložit do šablony. ​(Velikost formuláře lze plynule měnit a tím lze zvětšit i pole s popisem vkládaného vzoru proměnné takaby byl vidět celý.) 
-|bBefore|požadavek na použití uživatelské funkce před nahrazením knihovnou ​(napřed bude na vstupní ​šablonu aplikovaná uživatelem definovaná funkceaž na její výsledek bude plikováno standardní nahrazení knihovnou)| + 
-</box>+<WRAP round info> 
 +Samozřejmě chápeme, že práce se šablonami může být někdy dosti složitá. Pokud nevíte, jak získat svůj vysněný výstup, kontaktujte autora skriptu, nebo rovnou autory knihovny VarSubst. Jistě Vám rádi poradí, pokud budou mít trochu času. 
 +</WRAP>
  
-<box round 95% #​DEE7EC>​ +==== Přehled možných vzorů v šabloně ==== 
-:!: Použití neveřejných funkcí může vést k nečekaným výsledkům - až ke kolapsu, protože tyto funkce předpokládají nejakou inicializaci,​ sekvenci volání ​podobně, což je zajištěno jen použitím veřejných funkcí**Důrazně volání neveřejných funkcí nedoporučuji.** +Následuje výčet možných vzorů, které mohou šablony obsahovat ​které dokáže knihovna zpracovat ​nahradit.
-</​box>​+
  
-===== Seznam nahrazovaných proměnných =====+=== Komentář ​=== 
 +Všechny řádky začínající znakem # jsou považovány za komentář a jsou ignorovány. Ve výstupu nebudou zahrnuty.
  
-<​box ​96% right #f8f8f8 #f8f8f8 #f8f8f8 #f8f8f8>+=== Seznam nahrazovaných proměnných === 
 +<WRAP round box>
 |%NAME%, %WPTNAME%|jméno bodu| |%NAME%, %WPTNAME%|jméno bodu|
 |%FAMILY%|typ bodu (první 2 znaky: GC, WM, ...)| |%FAMILY%|typ bodu (první 2 znaky: GC, WM, ...)|
 |%ID%, %WPTID%|identifikátor bodu (GC12345)| |%ID%, %WPTID%|identifikátor bodu (GC12345)|
-|%GUID%, %WPTGUID%|plný ​identifiktor ​bodu používaný v URL na geocaching.com|+|%GUID%, %WPTGUID%|plný ​identifikátor ​bodu používaný v URL na geocaching.com|
 |%AUTHOR%|autor (vlastník) bodu| |%AUTHOR%|autor (vlastník) bodu|
 |%TYPE%, %WPTTYPE%|typ bodu (Traditional,​ Multi cache, Letterbox hybrid, ...)| |%TYPE%, %WPTTYPE%|typ bodu (Traditional,​ Multi cache, Letterbox hybrid, ...)|
-|%TYPEID%, %WPTTYPEID%|jeden znak identifikace typu (T=traditional, M=multi, H=letterbox hybrid, C=CITO, E=event, L=locationless, V=virtual, W=webcam, O=Other, G=Earth, I=Wherigo, U=mystery/Unknown, Y=Lost and Found Event Cache, F=Final, P=Parking, Q=Question ​and answer, S=Stage of multi-cache)|+|%TYPEID%, %WPTTYPEID%|jeden znak identifikace typu (T=Traditional Cache, M=Multi-cache, H=Letterbox Hybrid, C=Cache In Trash Out Event, E=Event Cache, L=Locationless (Reverse) Cache, V=Virtual Cache, W=Webcam Cache, O=Other, G=Earthcache, I=Wherigo ​Cache, U=Unknown ​Cache, Y=Lost and Found Event Cache, F=Final ​Location, P=Parking ​Area, Q=Question ​to Answer, S=Stages ​of a Multicache, T=Trailhead,​ R=Reference Point)|
 |%SIZE%|velikost (Micro, ...)| |%SIZE%|velikost (Micro, ...)|
-|%SIZEID%|jeden znak velikost (M=mikro, S=small, R=regular, L=large, V=virtual, O=jiná, N=neurčeno)|+|%SIZEID%|jeden znak velikost (M=Micro, S=Small, R=Regular, L=Large, V=Virtual, O=Other, N=Not chosen)|
 |%DIFFICULTY%|obtížnost (1 ... 5)| |%DIFFICULTY%|obtížnost (1 ... 5)|
 |%DIFFID%|jeden znak obtížnosti (1,​A,​2,​B,​3,​C,​4,​D,​5)| |%DIFFID%|jeden znak obtížnosti (1,​A,​2,​B,​3,​C,​4,​D,​5)|
Line 101: Line 104:
 |%HIDDEN%|datum vytvoření bodu ve tvaru DD.MM.RRRR| |%HIDDEN%|datum vytvoření bodu ve tvaru DD.MM.RRRR|
 |%COORDINATE%,​ %WPTCOORDINATE%|souřadnice bodu ve tvaru N SS°MM.mmm E SSS°MM.mmm| |%COORDINATE%,​ %WPTCOORDINATE%|souřadnice bodu ve tvaru N SS°MM.mmm E SSS°MM.mmm|
-|%CORRECTEDCOORDINATE%|korigované souřadnice bodu (=souradnice ​finálky) ve tvaru N SS°MM.mmm E SSS°MM.mmm|+|%CORRECTEDCOORDINATE%|korigované souřadnice bodu (=souřadnice ​finálky) ve tvaru N SS°MM.mmm E SSS°MM.mmm|
 |%LAT%, %WPTLAT%|zeměpisná délka ve tvaru SS,dddddd| |%LAT%, %WPTLAT%|zeměpisná délka ve tvaru SS,dddddd|
 |%LON%, %WPTLON%|zeměpisná šířka ve tvaru SSS,dddddd| |%LON%, %WPTLON%|zeměpisná šířka ve tvaru SSS,dddddd|
Line 123: Line 126:
 |%WPTPREFIXID%|prefix bodu| |%WPTPREFIXID%|prefix bodu|
 |%WPTDESCRIPTION%|popis bodu| |%WPTDESCRIPTION%|popis bodu|
-</box>+</WRAP>
  
 Jak je vidět z předchozího výčtu, nahrazované proměnné odpovídají položkám, které databáze GeoGetu uchovává k jednotlivým bodům. To je důležité si uvědomit zejména při tvorbě šablony. Ne všechny položky jsou k dispozici pro všechny typy bodů (keš versus doplňující waypoint). Nicméně při náhradě pro WP knihovna vyhledá i mateřský bod (keš) a pokud je to třeba, použije příslušné hodnoty z jeho definice. Pokud se však budete snažit použít proměnnou %WPT*% na mateřském bodě (keši), logicky k náhradě nedojde, jelikož pro keš není taková proměnná definována. Jak je vidět z předchozího výčtu, nahrazované proměnné odpovídají položkám, které databáze GeoGetu uchovává k jednotlivým bodům. To je důležité si uvědomit zejména při tvorbě šablony. Ne všechny položky jsou k dispozici pro všechny typy bodů (keš versus doplňující waypoint). Nicméně při náhradě pro WP knihovna vyhledá i mateřský bod (keš) a pokud je to třeba, použije příslušné hodnoty z jeho definice. Pokud se však budete snažit použít proměnnou %WPT*% na mateřském bodě (keši), logicky k náhradě nedojde, jelikož pro keš není taková proměnná definována.
Line 133: Line 136:
 **&​uvozovky&​** bude nahrazeno uvozovkami. Jak je zmíněno na více místech tohoto návodu, uvozovky slouží jako omezovač parametrů ve funkcích. Proto by uvozovky mimo tento účel být neměly. Pokud má výsledek obsahovat uvozovky, je třeba je v šabloně nahradit právě tímto textem. **&​uvozovky&​** bude nahrazeno uvozovkami. Jak je zmíněno na více místech tohoto návodu, uvozovky slouží jako omezovač parametrů ve funkcích. Proto by uvozovky mimo tento účel být neměly. Pokud má výsledek obsahovat uvozovky, je třeba je v šabloně nahradit právě tímto textem.
  
-===== Seznam globálních proměnných GeoGetu ​===== +=== Seznam globálních proměnných GeoGetu === 
-<​box ​95% right #f8f8f8 #f8f8f8 #f8f8f8 #f8f8f8>+<WRAP round box>
 |%GGDATADIR%|datový adresář GeoGetu| |%GGDATADIR%|datový adresář GeoGetu|
-|%GGSCRIPTDIR%|adresář GeoGetu, v kterém jsou očekávány ​scripty|+|%GGSCRIPTDIR%|adresář GeoGetu, v kterém jsou očekávány ​skripty|
 |%GGDBNAME%|jméno databáze GeoGetu| |%GGDBNAME%|jméno databáze GeoGetu|
 |%GGVER%|verze GeoGetu| |%GGVER%|verze GeoGetu|
 |%GGOWNER%|uživatel GeoGetu| |%GGOWNER%|uživatel GeoGetu|
 |%CRLF%|odřádkování| |%CRLF%|odřádkování|
-</box>+</WRAP>
  
-Knihovna nahrazuje jen ty proměnné, jejichž použití může mít v šablonách nějaký přínos. Zdaleka tedy nejsou k dispozici všechny globální proměnné GeoGetu, které může použít ​script. Pokud se opravdu ukáže potřeba náhrady neobsluhované proměnné, lze k tomu účelu využít uživatelské funkce.+Knihovna nahrazuje jen ty proměnné, jejichž použití může mít v šablonách nějaký přínos. Zdaleka tedy nejsou k dispozici všechny globální proměnné GeoGetu, které může použít ​skript. Pokud se opravdu ukáže potřeba náhrady neobsluhované proměnné, lze k tomu účelu využít uživatelské funkce. Anebo nás přesvědčit,​ abychom náhradu proměnné přidali přímo do knihovny.
  
-===== Seznam logických proměnných ​===== +=== Seznam logických proměnných === 
-<​box ​95% right #f8f8f8 #f8f8f8 #f8f8f8 #f8f8f8>+<WRAP round box>
 |%HAVEFINAL%|**true**,​ pokud má keš finálku| |%HAVEFINAL%|**true**,​ pokud má keš finálku|
 |%ISDISABLED%|**true**,​ pokud má bod status Disabled| |%ISDISABLED%|**true**,​ pokud má bod status Disabled|
Line 155: Line 158:
 |%HAVELISTING%|**true**,​ pokud má bod neprázdný popis| |%HAVELISTING%|**true**,​ pokud má bod neprázdný popis|
 |%HAVEATTACHMENT%|**true**,​ pokud má bod nějaký přiložený soubor| |%HAVEATTACHMENT%|**true**,​ pokud má bod nějaký přiložený soubor|
-|%HAVERTFATTACHMENT%|**teue**, pokud má bod nějaký přiložený *.rtf soubor|+|%HAVERTFATTACHMENT%|**true**, pokud má bod nějaký přiložený *.rtf soubor|
 |%WPTISUSERWAYPOINT%|**true**,​ pokud byl WPT vytvořen či upraven uživatelem| |%WPTISUSERWAYPOINT%|**true**,​ pokud byl WPT vytvořen či upraven uživatelem|
 |%WPTISFINAL%|**true**,​ pokud se jedná o bod s finálovými souřadnicemi| |%WPTISFINAL%|**true**,​ pokud se jedná o bod s finálovými souřadnicemi|
-|%WPTISEMPTYCOORD%|**true**,​ pokud souřadníce ​bodu jsou nulové| +|%WPTISEMPTYCOORD%|**true**,​ pokud souřadnice ​bodu jsou nulové| 
-</box>+</WRAP>
  
 Logické proměnné vracejí text **true** nebo **false** jako string. Tento string je možné testovat v podmíněném nahrazování. Logické proměnné vracejí text **true** nebo **false** jako string. Tento string je možné testovat v podmíněném nahrazování.
  
-===== Seznam funkcí ​===== +=== Seznam funkcí === 
-Obsluha funkcí je aplikovaná až po všech prostých náhradách,​ může tedy využívat jejich výsledku. Je možné například testovat existenci ​finalních ​souřadnic a v závislosti na tom souřadnice vypsat nebo místo nich napsat nějaký jiný text. +Obsluha funkcí je aplikovaná až po všech prostých náhradách,​ může tedy využívat jejich výsledku. Je možné například testovat existenci ​finálních ​souřadnic a v závislosti na tom souřadnice vypsat nebo místo nich napsat nějaký jiný text. 
  
-Všechny parametry použité ve funkcích jsou textové ​žetězy a je nutné je uzavřít do uvozovek. Oddělovačem parametrů je oproti běžným zvyklostem středník. Obecný tvar volání funkcí je +Všechny parametry použité ve funkcích jsou textové ​řetězce a je nutné je uzavřít do uvozovek. Oddělovačem parametrů je oproti běžným zvyklostem středník. Obecný tvar volání funkcí je 
  
 <​code>​ <​code>​
Line 172: Line 175:
 </​code>​ </​code>​
  
-Je-li parametem ​operátor porovnání,​ není uzavřen v uvozovkách a ani není oddělen středníky od ostatních parametrů. Mezery (obecně bílé znaky) mezi parametry jsou nevýznamné.+Je-li parametrem ​operátor porovnání,​ není uzavřen v uvozovkách a ani není oddělen středníky od ostatních parametrů. Mezery (obecně bílé znaky) mezi parametry jsou nevýznamné.
  
 Knihovna poskytuje následující funkce: Knihovna poskytuje následující funkce:
Line 182: Line 185:
   * náhrada textem podle toho, zda bod má nastavený TAG příslušné kategorie a hodnoty nebo nemá   * náhrada textem podle toho, zda bod má nastavený TAG příslušné kategorie a hodnoty nebo nemá
  
-<​code>​ +<​code>​%IF("​str1"​ op "​str2";​ "​pravdivý text"; "​nepravdivý text"​)%</​code>​ 
-  ​%IF("​str1"​ op "​str2";​ "​pravdivý text"; "​nepravdivý text"​)% +  * náhrada textem podle platnosti zadané podmínky. Funkce test vyhodnocuje porovnáním ​řetězců s ohledem na velikost písmen. Jako operátor **op** mohou být použity =, <>, >=, <=.
-</​code>​ +
-  * náhrada textem podle platnosti zadané podmínky. Funkce test vyhodnocuje porovnáním ​stringů s ohledem na velikost písmen. Jako operátor **op** mohou být použity =, <>, >=, <=.+
    
 <​code>​%ROT13("​str"​)%</​code>​ <​code>​%ROT13("​str"​)%</​code>​
Line 193: Line 194:
   * obrátí pořadí znaků ve stringu   * obrátí pořadí znaků ve stringu
  
-<​code>​%REPLACE("​str"​,"​vzor"​,"​náhrada"​)%</​code>​+<​code>​%REPLACE("​str"​;"​vzor"​;"​náhrada"​)%</​code>​
   * každý výskyt //vzor// ve vstupním textu //str// nahradí textem //​náhrada//​. Funkce je vyhodnocována po aplikaci standardních náhrad (viz [[user:​skript:​varsubst#​funkce|tabulky pořadí zpracování]] na začátku)   * každý výskyt //vzor// ve vstupním textu //str// nahradí textem //​náhrada//​. Funkce je vyhodnocována po aplikaci standardních náhrad (viz [[user:​skript:​varsubst#​funkce|tabulky pořadí zpracování]] na začátku)
  
-<​code>​%REPLACEFULL("​str"​,"​vzor"​,"​náhrada"​)%</​code>​+<​code>​%REPLACEFULL("​str"​;"​vzor"​;"​náhrada"​)%</​code>​
   * funkce je identická s předchozí funkcí, ale volá se až úplně na konci zpracování jako [[user:​skript:​varsubst#​funkce|poslední funkce před návratem]] ​   * funkce je identická s předchozí funkcí, ale volá se až úplně na konci zpracování jako [[user:​skript:​varsubst#​funkce|poslední funkce před návratem]] ​
  
-Funkce REPLACE a IF mohou být do sebe vnořeny (funkce může obsahovat samu sebe, tzv. rekurze), vyhodnocují se vždy od poslední k první. U ostatních funkcí postrádá rekurze smyslu, proto není implementovaná.+Funkce REPLACE a IF mohou být do sebe vnořeny (funkce může obsahovat samu sebe, tzv. rekurze), vyhodnocují se vždy od poslední k první. U ostatních funkcí postrádá rekurze smyslu, proto není implementována.
  
-<box round 100% #DEE7EC+<WRAP round important
-:!: Zejména při vnořování funkcí a jejich rekurzi je velmi **důležité dát pozor na použití uvozovek**. Každý textový řetěz vstupující do funkce jako parametr musí být uzavřen v uvozovkách. Pokud není, bude chápán jako číslo, a to může způsobit v nejlepším případě nečekaný výsledek, v horším případě neprovedení náhrady nebo možná i kolaps. Vnořování ​funcí ​do parametrů jiných funkcí je možné, ale přehlednost parametrů s každým vnořením dramaticky klesá. Je důležité si uvedomit, že funkce se vyhodnocují //od poslední funkce// a podle toho také kontrolovat uvozovky u textových parametrů. Je-li parametrem výsledek vnořené funkce, musí být celá funkce uzavřena v uvozovkách.+Zejména při vnořování funkcí a jejich rekurzi je velmi **důležité dát pozor na použití uvozovek**. Každý textový řetěz vstupující do funkce jako parametr musí být uzavřen v uvozovkách. Pokud není, bude chápán jako číslo, a to může způsobit v nejlepším případě nečekaný výsledek, v horším případě neprovedení náhrady nebo možná i kolaps. Vnořování ​funkcí ​do parametrů jiných funkcí je možné, ale přehlednost parametrů s každým vnořením dramaticky klesá. Je důležité si uvědomit, že funkce se vyhodnocují //od poslední funkce// a podle toho také kontrolovat uvozovky u textových parametrů. Je-li parametrem výsledek vnořené funkce, musí být celá funkce uzavřena v uvozovkách.
  
-<​code>​ +<​code>​%IF("​str1"<>"​str2";​ "​%IF(int1=int2;"​platí vnější i vnitřní test"; "​platí vnější, neplatí vnitřní test"​)%";​ "​neplatí vnější test"​)%</​code>​
-%IF("​str1"<>"​str2";​ "​%IF(int1=int2;"​platí vnější i vnitřní test"; "​platí vnější, neplatí vnitřní test"​)%";​ "​neplatí vnější test"​)%+
  
 +Vidíte, že na první a zřejmě ani na druhý pohled není zcela patrné, k čemu se které uvozovka vztahuje.
 +</​WRAP>​
 +
 +=== Uživatelské vzory a funkce ===
 +Kromě základních vzorů a funkcí, o kterých píšeme výše, může být funkcionalita knihovny rozšířena i o další vzory.
 +Knihovna totiž poskytuje programátorovi možnost přidat ke standardním vzorům i své vzory vlastní.
 +
 +Jelikož každý skript si může vložit vzory různé, není možno zde vypsat přesný seznam dostupných funkcí. Ten by měl být k dispozici na stránkách skriptů, nikoliv zde.
 +
 +Přesto je však možno zjistit, o jaké vzory byla knihovna rozšířena. V grafickém editoru šablon, ve vysouvacím seznamu vzorů, jsou na konci zobrazeny i rozšiřující vzory přidané programátorem volajícího skriptu.
 +
 +==== Ukázka šablon ====
 +Takto může vypadat relativně pokročilá šablona, která je použitelná se skriptem [[poigarmin|POI Garmin]]. Kromě standardních knihovních funkcí využívá i vlastní vzory.
 +
 +**Listing bodu:**
 +<code none point.description.poigarmin.varsubst.template.txt>​
 +# GeoGet, http://​www.geoget.cz
 +# Šablona pro knihovnu VarSubst, http://​www.geoget.cz/​doku.php/​user:​skript:​varsubst
 +# Součást exportu POI Garmin, http://​www.geoget.cz/​doku.php/​user:​skript:​poigarmin
 +#
 +# Autor: medwyn_cz, http://​www.geocaching.com/​profile/?​u=medwyn_cz
 +#
 +# Šablonu můžete libovolně upravovat. Při aktualizacích exportu na vyšší verze jsou přepisovány
 +# šablony uložené v adresáři "​templates_bundled"​. Žádná šablona z adresáře "​templates"​ NEBUDE
 +# aktualizací ovlivněna. Nemusíte se tedy bát, že aktualizací přijdete o své změny.
 +#
 +########## Varování o důležitých skutečnostech - začátek listingu
 +Bod typu <​b>​%TYPE%</​b>​ od autora <​b>​%AUTHOR%</​b>​ založen dne <​b>​%HIDDEN%</​b><​hr>​
 +%IF("​%ISOWNER%"​="​true";"<​font color=BLUE><​b>​Jste vlastník tohoto bodu!</​b></​font><​br><​br>";""​)%
 +%IF("​%ISFOUND%"​="​true";"<​font color=#​038914><​b>​Bod jste již našel (%FOUND%).</​b></​font><​br><​br>";""​)%
 +%IF("​%ISARCHIVED%"​="​true";"<​font color=RED><​b>​Bod je archivovaný.</​b></​font><​br><​br>";"​%IF("​%ISDISABLED%"​="​true";"<​font color=RED><​b>​Bod je dočasně nepřístupný.</​b></​font><​br><​br>";""​)%"​)%
 +%IF("​%LOGSTATHASISSUES%"​="​true";"<​font color=RED><​b>​Od posledního nálezu bylo na bodu několik podezřelých logů:</​b></​font>​ (%LOGSTAT%).<​br><​br>";""​)%
 +%IF("​%CONTAINSHIGHLIGHTWORD%"​="​true";"<​font color=RED><​b>​V listingu byla zvýrazněna definovaná klíčová slova!</​b></​font><​br><​br>";""​)%
 +<​b>​ID:</​b>​ %ID%<​br>​
 +### Pro keše vypíšeme více informací
 +%IF("​%FAMILY%"​="​GC";"<​b>​Obtížnost:</​b>​ %DIFFICULTY%<​br><​b>​Terén:</​b>​ %TERRAIN%<​br><​b>​Velikost:</​b>​ %SIZE%<​br>";""​)%
 +### Výpis obsahu tagů, pokud existují
 +%IFTAG("​favorites";"";"<​b>​Oblíbená:</​b>​ %TAG("​favorites"​)%x<​br>";""​)%
 +%IFTAG("​Elevation";"";"<​b>​Nadmořská výška:</​b>​ %TAG("​Elevation"​)% m.n.m.<​br>";""​)%
 +%IFTAG("​Hodnoceni";"";"<​b>​Hodnocení:</​b>​ %TAG("​Hodnoceni"​)% (%TAG("​Hodnoceni-Pocet"​)%)<​br>";""​)%
 +%IFTAG("​attribute";"";"<​b>​Atributy:</​b>​ %TAG("​attribute"​)%<​br>";""​)%
 +%IFTAG("​Bookmark";"";"<​b>​Bookmarky:</​b>​ %TAG("​Bookmark"​)%<​br>";""​)%
 +%IFTAG("​BestOf";"";"<​b>​BestOf:</​b>​ %TAG("​BestOf"​)%<​br>";""​)%
 +%IFTAG("​CWG";"";"<​b>​CWG:</​b>​ %TAG("​CWG"​)%<​br>";""​)%
 +%IFTAG("​PocketQuery";"";"<​b>​PocketQuery:</​b>​ %TAG("​PocketQuery"​)%<​br>";""​)%
 +%IFTAG("​FTF";"";"<​b>​FTF:</​b>​ %TAG("​FTF"​)%<​br>";""​)%
 +%IFTAG("​import";"";"<​b>​Importováno z:</​b>​ %TAG("​import"​)%<​br>";""​)%
 +<​b>​Aktualizováno:</​b>​ %UPDATED%<​br>​
 +%IF("​%FAMILY%"​="​GC";"<​b>​Naposledy nalezena:</​b>​ %LASTFOUND%";""​)%
 +### Poznámka z GeoGetu.
 +%IF("​%COMMENT%"<>"";"<​br><​b>​Poznámka:</​b><​br>​%REPLACE("​%COMMENT%";"&​CRLF&";"<​br>"​)%";""​)%
 +%IF("​%HINT%"<>"";"<​br><​b>​Hint:</​b>​ %REVERSE("​%REPLACE("​%HINT%";"&​CRLF&";"<​br>"​)%"​)%";""​)%
 +########## Listing keše
 +#### Pro WM předřadíme Visit Instructions
 +%IF("​%FAMILY%"​="​WM";"<​hr><​b>​Podmínky logu:</​b>​ %WMVISITINSTRUCTIONS%";""​)%
 +#### A nyni samotný listing
 +%IF("​%HAVELISTING%"​="​true";"<​hr>​%SHORTLISTING%<​br>​%LONGLISTING%";""​)%
 +########## Seznam waypointů
 +%IF("​%HAVEWAYPOINT%"​="​true";"<​hr>​%WAYPOINTS%";""​)%
 +########## Poslední logy na keši
 +%IF("​%HAVELOG%"​="​true";"<​hr>​%LOGS%";""​)%
 </​code>​ </​code>​
  
-Vidíte, žna první a ejmě ani na druhý pohled není zcela patrné, k čemu se které uvozovka vztahuje+**Jméno bodu:** 
-</box>+<code none point.name.poigarmin.varsubst.template.txt>​ 
 +# GeoGethttp://​www.geoget.cz 
 +# Šablona pro knihovnu VarSubst, http://​www.geoget.cz/​doku.php/​user:​skript:​varsubst 
 +# Součást exportu POI Garmin, http://​www.geoget.cz/​doku.php/​user:​skript:​poigarmin 
 +
 +# Autor: medwyn_cz, http://​www.geocaching.com/​profile/?​u=medwyn_cz 
 +
 +# Šablonu můžete libovolně upravovat. Při aktualizacích exportu ​na vyšší verze jsou přepisovány 
 +# šablony uložené v adresáři "​templates_bundled"​. Žádná šablona ​adresáře "​templates"​ NEBUDE 
 +# aktualizací ovlivněna. Nemusíte ​se tedy bát, že aktualizací přijdete o své změny. 
 +
 +
 +%REPLACEFULL("​%IF("​%FAMILY%"​="​GC";"​%TYPEID%%SIZEID%%DIFFID%%TERRID% ";""​)%%IF("​%ISOWNER%"​="​true";"​O";""​)%%IF("​%ISFOUND%"​ = "​true";"​F";""​)%%IF("​%ISARCHIVED%"​ = "​true";"​A";"​%IF("​%ISDISABLED%"​ = "​true";"​D";""​)%"​)% %NAME%";" ​ ";"​ ")% 
 +
 +# Celé jméno je obaleno ve funkci REPLACEFULL. Jejím úkolem je odstranit dvojité mezery, 
 +# které by mohly ve jménu vzniknout 
 +</code>
  
 +==== Poznámky, známé problémy ====
 +<WRAP round important>​
 +Zásadním problémem je použití uvozovek. Uvozovky omezují textové parametry, ale uvnitř těchto parametrů mohou být další proměnné či funkce, které opět mohou obsahovat v parametrech textové řetězy ohraničené uvozovkami, ... Po nahrazení sice vždy uvozovky //zmizí//, ale pro identifikaci funkcí a jejich parametrů jsou velmi důležité. Je proto třeba jim věnovat zvýšenou pozornost.
 +</​WRAP>​
  
-===== Uživatelské funkce ===== +<WRAP round important>​ 
-Uživatelské funkce slouží k tomu, aby si uživatel mohl definovat vlastní funkce, které budou použity přnahrazování. Může tedy definovat obsluhu vlastních ​proměnných, specifické zacházení s texty (napřomezení délky výstupního textu) a další pro něj užitečné funkcekteré nezajišťuje knihovna.+Je důležité konstruovat šablonu s ohledem na pořadí nahrazování proměnných ​a vyhodnocování funkcíPokud bude šablona sestavena chybně, nedojde ke správnému vyhodnocení a ve výsledku zůstanou vidět //podivné konstrukce//​. 
 +</​WRAP>​
  
-Oproti ​ímé obsluze voláním vlastní funkce uvnitř svého scriptu mají uživatelské funkce tu výhodu, ​že jsou aplikovány ​na šablony ​současně s ostatními knihovními funkcemiPřínosem by měla být lepší čitelnost kódu scriptu a jeho snadnější údržba.+<WRAP round help> 
 +Čas - ano, zpracování pomocí knihovny je nepochybně pomalejší než jednoúčelově na míru ušitý skript. Ovšem produktivita programátorských prací dle našeho mínění minimálně vyváží časovou ztrátu způsobenou pomalejším zpracováním exportu. Příkladem budiž export [[user:​skript:​poigarmin|POI Garmin]]. Dříve napsaný speciální skript zpracovával Gordových asi 24000 keší + 5000 waymarků ​ibližně 12 minut. Předěláním exportu na použití této knihovny se sice zpracování prodloužilo na cca 14 minut, ale kterýkoli uživatel si snadnou úpravou ​šablony ​může export upravit sobě na míruZ uživatelského hlediska použití knihovny přináší větší hodnotu než je ztráta způsobená delším zpracováním. (Pro přesnost dodáváme, že těch 12 minut je údaj po zrychlovací kúře, kterou skript prodělal. Verze, která byla rozšířena mezi uživateli, tutéž dávku zpracovávala cca 25 minut, takže i s použitím šablony je to vlastně časová úspora. :-) Všechno se dá zdůvodnit.
 +</​WRAP>​
  
-==== Požadavky na uživatelské funkce ​====+===== Programátorská dokumentace ===== 
 + 
 +==== Funkce ==== 
 +Voláním knihovních funkcí (viz níže) dojde k náhradě proměnných ve tvaru **%JMENO%** příslušnou textovou hodnotou. Proměnné jsou vyhodnocovány podle hodnot v instanci třídy **TGeo** (informace o bodu - keši) nebo **TWpt** (informace o doplňkovém bodu - final, parkoviště,​ ...) a podle globálních proměnných GeoGetu (např. GEGOGET_DATADIR má proměnnou %GGDATADIR%). 
 + 
 +Všechny řádky začínající znakem # jsou považovány za komentář a ignorovány. 
 + 
 +Všechny vstupní texty (šablona, databázové hodnoty) jsou v kódování UTF-8, výstup je volitelně v UTF-8 nebo Win-1250. Případné zaregistrované uživatelské funkce musí mít výstup kódován v UTF-8. 
 + 
 +Knihovna zpracovává vstupní text následujícím způsobem:​ 
 +  - volá všechny uživatelské funkce, které byly registrované s příznakem bBefore 
 +  - nahradí proměnné (s výjimkou proměnných pro listing) 
 +  - nahradí logické proměnné 
 +  - provede funkce REPLACE 
 +  - nahradí TAGy (funkce TAG, IFTAG) 
 +  - provede funkce ROT13 a REVERSE 
 +  - zpracuje podmíněné nahrazení funkcí IF 
 +  - volá všechny uživatelské funkce, které byly registrované bez příznaku bBefore 
 +  - náhrada proměnných pro listing (LISTING, LONGLISTING,​ SHORTLISTING) 
 +  - provede funkci REPLACEFULL  
 + 
 +<WRAP round info> 
 +Náhrada listingu je posunuta až na konec zpracování proto, aby se co nejméně pracovalo s dlouhými texty a tím se zvýšila rychlost. Text listingu již většinou není třeba dál zpracovávat,​ takže vlastně ani není důvod k tomu, aby se to dělalo dříve. Jediné, co by snad mohlo být potřeba udělat, je nahradit nějaký konstantní text v listingu jiným textem a to lze realizovat funkcí REPLACEFULL. 
 +</​WRAP>​ 
 + 
 +==== Veřejné funkce knihovny ==== 
 +Použití knihovny spočívá ve volání některé z knihovních funkcí. Těch obsahuje knihovna celou řadu, ale jen některé z nich jsou určené k volání mimo knihovnu (veřejné funkce). Seznam veřejných funkcí: 
 + 
 +<code delphi>​function VarSubstGeo(geo:​TGeo;​ sTemplate:​string;​ bAnsi:​boolean;​ var sOutput:​string):​ boolean;</​code>​ 
 +  * Nahrazuje proměnné hodnotami z hlavního bodu (keš, waymark)  
 + 
 +<code delphi>​function VarSubstWpt(wpt:​TWpt;​ sTemplate:​string;​ bAnsi:​boolean;​ var sOutput:​string):​ boolean;</​code>​ 
 +  * Nahrazuje proměnné hodnotami z WPT bodu (parkoviště,​ stage of multi=cache,​ ...) 
 + 
 +<code delphi>​function VarSubstAddFunctionReplaceGeo(fce:​VarSubst_TypeReplaceFunc;​bBefore:​boolean):​boolean;</​code>​ 
 +  * Registruje uživatelskou funkci pro nahrazování proměnných podle TGeo. 
 + 
 +<code delphi>​function VarSubstAddFunctionReplaceWpt(fce:​VarSubst_TypeReplaceFunc;​bBefore:​boolean):​boolean;</​code>​ 
 +  * Registruje uživatelskou funkci pro nahrazování proměnných podle TWpt. 
 + 
 +<code delphi>​function VarSubstDelFunctionReplace(fce:​VarSubst_TypeReplaceFunc):​boolean;</​code>​ 
 +  * Ruší registraci uživatelské funkce 
 + 
 +<code delphi>​procedure VarSubstDlgTemplateFile(sCaption,​ ID, sPathFileTemplate,​ startDir:​string);</​code>​ 
 +  * Poskytuje formulář pro testování šablony. 
 + 
 +<code delphi>​procedure VarSubstDlgTemplateString(sCaption,​ ID, sTemplate, startDir:​string);</​code>​ 
 +  * Poskytuje formulář pro testování šablony. 
 + 
 +<code delphi>​function VarSubstDlgTemplateStringNoSave(caption,​id,​sTemplate:​ string) : String;</​code>​ 
 +  * Funkce, která zobrazí formulář na editaci a testování šablony. Návratovou hodnotou je nově upravená šablona. Ve formuláři jsou skryty ovládací prvky pro přímé ukládání do souboru.  
 + 
 +<code delphi>​function VarSubstEncode(str:​string):​string;</​code>​ 
 +  * Nahrazuje nebezpečné znaky, které brání správnému zpracování funkcí. Funkce najde uplatnění v uživatelských funkcích.  
 + 
 +Ve funkcích jsou použity následující parametry:​ 
 + 
 +<WRAP round box> 
 +|TGeo|struktura naplněná informacemi o konkrétním bodu (keši)| 
 +|TWpt|struktura naplněná informacemi o doplňkovém bodu| 
 +|sTemplate|vstupní text s šablonou obsahující nahrazované proměnné (čeština v UTF-8). Šablona obsahuje jména proměnných a funkcí, které knihovna vyhodnocuje a nahradí je vyhodnoceným textem. (Pokud má výsledný text obsahovat znak %, musí být v šabloně vypsán jako HTML entita &​perc;​.)| 
 +|sOutput|výstupní text, v kterém jsou proměnné nahrazeny příslušnými hodnotami. Výsledné kódování češtiny je podle proměnné bAnsi v UTF-8 nebo Win-1250.| 
 +|bAnsi|požadavek na překódování výstupu do kódování ANSI (Win-1250). Místo hodnot **true** a **false** lze použít jednoznačné konstanty **VARSUBST_ANSI** a **VARSUBST_UTF**.| 
 +|fce|uživatelem definovaná funkce, která realizuje nahrazování nad rámec knihovních funkcí| 
 +|bBefore|požadavek na použití uživatelské funkce před nahrazením knihovnou (napřed bude na vstupní šablonu aplikovaná uživatelem definovaná funkce, až na její výsledek bude aplikováno standardní nahrazení knihovnou)| 
 +</​WRAP>​ 
 + 
 +<WRAP round important>​ 
 +Použití neveřejných funkcí (tedy prohlédnutí zdrojového kódu knihovny a volání funkcí, které nejsou uvedeny v seznamu výše) může vést k nečekaným výsledkům - až ke kolapsu, protože tyto funkce předpokládají nějakou inicializaci,​ sekvenci volání a podobně, což je zajištěno jen použitím veřejných funkcí. **Důrazně volání neveřejných funkcí nedoporučujeme.** 
 +</​WRAP>​ 
 + 
 +==== Uživatelské funkce ==== 
 +Uživatelské funkce slouží k tomu, aby si programátor mohl definovat vlastní funkce, které budou použity při nahrazování. Může tedy definovat obsluhu vlastních proměnných,​ specifické zacházení s texty (např. omezení délky výstupního textu) a další pro něj užitečné funkce, které nezajišťuje knihovna. 
 + 
 +Vlastní funkce si programátor zaregistruje u knihovny, a ta je poté bude v patřičných okamžicích volat. 
 + 
 +Oproti přímé obsluze voláním vlastní funkce uvnitř svého skriptu mají uživatelské funkce tu výhodu, že jsou aplikovány na šablony současně s ostatními knihovními funkcemi. Přínosem by měla být lepší čitelnost kódu skriptu a jeho snadnější údržba. 
 +Rovněž takováto struktura umožňuje uživatelům skriptů používat grafický editor šablon včetně rozšíření a zjednodušuje tak práci na všech frontách. 
 + 
 +=== Požadavky na uživatelské funkce ===
 Knihovna definuje dva typy uživatelských funkcí: Knihovna definuje dva typy uživatelských funkcí:
  
Line 226: Line 389:
 </​code>​ </​code>​
  
-Oba typy se ší jen typem bodu se vstupními daty pro aplikaci dat na šablonu. Z deklarace typu je zřejmé, že funkce musí vracet string (v kódování UTF-8), který je výsledkem její činnosti na vstupní šabloně (rovněž v kódování UTF-8). Funkce tedy aplikuje své postupy na vstupní string **sTemplate** a výsledek vrátí. S tímto výsledkem pak bude volaná případná další uživatelská funkce.+Oba typy se liší jen typem bodu se vstupními daty pro aplikaci dat na šablonu. Z deklarace typu je zřejmé, že funkce musí vracet string (v kódování UTF-8), který je výsledkem její činnosti na vstupní šabloně (rovněž v kódování UTF-8). Funkce tedy aplikuje své postupy na vstupní string **sTemplate** a výsledek vrátí. S tímto výsledkem pak bude volaná případná další uživatelská funkce. 
 + 
 +Uživatelská funkce většinou bude realizovat nějakou náhradu uživatelem definované textové konstanty. Nejčastěji tak budou v implementaci uživatelské funkce používány funkce k nahrazení textu textem jiným - **ReplaceString**,​ **RegexReplace**. 
 + 
 +Příklad jednoduché uživatelské funkce: 
 +<code delphi>​ 
 +{Funkce nahrazuje vzor %MYOWNLISTING% za listing zpracovaný funkcí MyOwnEditation} 
 +function UzivatelskaFunkce(geo:​TGeo;​sTemplate:​string):​ string; 
 +begin 
 +  Result:​=sTemplate;​ 
 +  if(pos('​%MYOWNLISTING%',​Result)>​0) //​testování,​ zda je je v šabloně obsažen vzor. VÝRAZNĚ urychluje zpracování  
 +    then Result:​=ReplaceString(Result,'​%MYOWNLISTING%',​VarSubstEncode(MyOwnEditation(geo.LongDescription)));​ //Náhrada všech výskytů vzoru cílovou hodnotou . POZOR, jakýkoliv vkládaný text musí být v kódování UTF-8! 
 +end; 
 +</​code>​
  
-Uživatelská funkce většinou bude realizovat nějakou náhradu uživatelem definované textové konstanty. ​Je velmi vhodné, aby tato textová konstanta dodržela formát %JMENO% a v případě funkce %FJM0NO_FUNKCE()%. Není to sice nezbytně nutné, ale udrží se tím alespoň jakási čitelnost šablony a navíc tento formát umožní ​ve formuláři vkládat tento text výběrem ze seznamu. Pokud formát dodržen nebude, konstanta a její popis sice v seznamu zobrazen bude, ale nebude možné ji do šablony vložit.+Je velmi vhodné, aby tato textová konstanta dodržela formát %JMENO% a v případě funkce %JMENO_FUNKCE()%. Není to sice nezbytně nutné, ale udrží se tím alespoň jakási čitelnost šablony a navíc tento formát umožní ​v editačním ​formuláři vkládat tento text výběrem ze seznamu ​vzorů. Pokud formát dodržen nebude, konstanta a její popis sice v seznamu zobrazen bude, ale nebude možné ji do šablony vložit.
  
-:!: Pokud uživatelská funkce nahrazuje nějaký text v šabloně, před vlastní náhradou by na text měla použít funkci **VarSubsEncode**, která převede nebezpečné znaky tak, aby nebránily následnému správnému zpracování. Ale pozor, tato funkce **nesmí** být použita na celou šablonu, protože nahrazuje mj. i uvozovky, takže následující zpracování by správně nerozeznalo parametry funkcí jako %IF(..)% a další. Pokud bude uživatelská funkce volaná až po náhradách knihovnou, není třeba funkci //​VarSubstEncode//​ volat.+<WRAP round info> 
 +Pokud uživatelská funkce nahrazuje nějaký text v šabloně, před vlastní náhradou by na text měla použít funkci **VarSubstEncode**, která převede nebezpečné znaky tak, aby nebránily následnému správnému zpracování. Ale pozor, tato funkce **nesmí** být použita na celou šablonu, protože nahrazuje mj. i uvozovky, takže následující zpracování by správně nerozeznalo parametry funkcí jako %IF(..)% a další. Pokud bude uživatelská funkce volaná až po náhradách knihovnou, není třeba funkci //​VarSubstEncode//​ volat. 
 +</​WRAP>​
  
-==== Registrace funkce a použití ​====+=== Registrace ​uživatelské ​funkce a použití ===
 Každá uživatelská funkce, která má být použita, musí být napřed knihovnou registrována. K registraci slouží jedna z funkcí Každá uživatelská funkce, která má být použita, musí být napřed knihovnou registrována. K registraci slouží jedna z funkcí
  
 <code delphi> <code delphi>
-function VarSubstAddFunctiondReplaceGeo(fce:​VarSubst_TypeReplaceFuncGeo;​aText:​TStrins;​bBefore:​boolean):​boolean;​ +function VarSubstAddFunctiondReplaceGeo(fce:​VarSubst_TypeReplaceFuncGeo;​aText:​TStrings;​bBefore:​boolean):​boolean;​ 
-function VarSubstAddFunctiondReplaceWpt(fce:​VarSubst_TypeReplaceFuncWpt;​aText:​TStrins;​bBefore:​boolean):​boolean;​+function VarSubstAddFunctiondReplaceWpt(fce:​VarSubst_TypeReplaceFuncWpt;​aText:​TStrings;​bBefore:​boolean):​boolean;​
 </​code>​ </​code>​
  
 Z názvu funkcí jasně vyplývá, že se samostatně registrují funkce obsluhující hlavní bod (keš, waymark, ...) a funkce obsluhující doplňkové body (WPT). Protože struktury obsahující příslušná data jsou pro oba typy bodů odlišné, je nutné je registrovat samostatně. **Chybná registrace způsobí kolaps.** Z názvu funkcí jasně vyplývá, že se samostatně registrují funkce obsluhující hlavní bod (keš, waymark, ...) a funkce obsluhující doplňkové body (WPT). Protože struktury obsahující příslušná data jsou pro oba typy bodů odlišné, je nutné je registrovat samostatně. **Chybná registrace způsobí kolaps.**
  
-Vysvětleme si druhý parametr: jedna registrovaná funkce může obsluhovat několik proměnných nebo funkcí. Protože formulář pro úpravu šablony nabízí seznam proměnných a funkcí pro snadné vložení jakéhosi vzoru, je třeba jako informaci o uživatelské funkci předat i tento vzor a popis tak, aby uživatel mohl vybrat správný řádek. Proto seznam všech funkcí nahrazovaných proměnných a jejich popis je součástí 2. parametru. Řekněme, že máme funkci, která obsluhuje proměnné ''​%TEST1%''​ a ''​%TEST2%''​. Pak funkce bude registrovana ​takto:+Vysvětleme si druhý parametr: jedna registrovaná funkce může obsluhovat několik proměnných nebo funkcí. Protože formulář pro úpravu šablony nabízí seznam proměnných a funkcí pro snadné vložení jakéhosi vzoru, je třeba jako informaci o uživatelské funkci předat i tento vzor a popis tak, aby uživatel mohl vybrat správný řádek. Proto seznam všech funkcí nahrazovaných proměnných a jejich popis je součástí 2. parametru. Řekněme, že máme funkci, která obsluhuje proměnné ''​%TEST1%''​ a ''​%TEST2%''​. Pak funkce bude registrována ​takto:
  
 <code delphi> <code delphi>
Line 250: Line 428:
 begin begin
   Result:​=sTemplate;​   Result:​=sTemplate;​
 +  ...
 end; end;
  
- ...+  ​...
   fUser:​=@UzivatelskaFunkce;​   fUser:​=@UzivatelskaFunkce;​
   aPopis.Add('​%TEST1% - testovaci funkce'​);​   aPopis.Add('​%TEST1% - testovaci funkce'​);​
Line 259: Line 438:
 </​code>​ </​code>​
  
-Třetí parametr informuje knihovnu o tom, zda registrovaná funkce má být volaná **před** nebo **po** ​stadnardních ​náhradách knihovními funkcemi.+Třetí parametr informuje knihovnu o tom, zda registrovaná funkce má být volaná **před** nebo **po** ​standardních ​náhradách knihovními funkcemi.
  
 V nečetných případech může být užitečné registraci funkce zrušit. K tomu slouží funkce V nečetných případech může být užitečné registraci funkce zrušit. K tomu slouží funkce
Line 270: Line 449:
 Po jejich použití již nebude knihovna příslušnou uživatelskou funkci volat a popis jí obsluhovaných konstant %JMENO% zmizí i ze seznamu nabízeném ve formuláři pro úpravu šablony. Po jejich použití již nebude knihovna příslušnou uživatelskou funkci volat a popis jí obsluhovaných konstant %JMENO% zmizí i ze seznamu nabízeném ve formuláři pro úpravu šablony.
  
-Pokud se v průběhu práce volajícího ​scriptu ​nemění uživatelské funkce, není třeba rušit registrace uživatelských funkcí. K odregistraci dojde automaticky ukončením nadřízeného volajícího ​scriptu.+Pokud se v průběhu práce volajícího ​skript ​nemění uživatelské funkce, není třeba rušit registrace uživatelských funkcí. K odregistraci dojde automaticky ukončením nadřízeného volajícího ​skriptu.
  
-===== Testování šablon ​===== +==== Testování ​a úprava ​šablon ==== 
-K testování šablon poskytuje knihovna dvě procedury.+K testování ​a úpravě ​šablon poskytuje knihovna dvě procedury.
  
 <code delphi> <code delphi>
Line 280: Line 459:
 </​code>​ </​code>​
  
-Obě procedury zobrazí formulář, na kterém je současně zobrazena šablona i výsledek aplikace knihovních a registrovaných uživatelských funkcí na šablonu. Procedury se liší jedině vstupním parametrem, který předává buďto cestu a jméno souboru se šablonou nebo přímo šablonu. **ID** definuje ID bodu (keše nebo WPT), jehož hodnoty budou použity pro vyhodnocení šablony. To, zda se jedná o ID bodu nebo WPT, knihovna rozlišuje sama podle toho, zda se jí příslušné ID podaří najít mezi body - pokud ne, hledá ID mezi doplňkovými body. +Obě procedury zobrazí formulář, na kterém je současně zobrazena šablona i výsledek aplikace knihovních a registrovaných uživatelských funkcí na šablonu. Procedury se liší jedině vstupním parametrem, který předává buďto cestu a jméno souboru se šablonou nebo přímo šablonu.
- +
-Formulář umožňuje měnit text šablony a změněnou šablonu uložit do souboru. +
- +
-:!: Jestliže mají být aplikovány i uživatelské funkce, je třeba je registrovat před voláním funkce pro robrazení formuláře. +
- +
-{{:​user:​skript:​varsubst:​formular.jpg|}} +
- +
-Součástí instalace knihovny je i jednoduchý script, který pouze zavolá knihovní funkci pro zobrazení formuláře. Běžný uživatel tak má možnost upravit si šablonu dodávanou jako součást jiného scriptu svým potřebám. Náhled ovšem nezobrazuje přesně výsledek tak, jak je vidět na cílovém zařízení,​ ale jen text, který je cílovému zařízení předán. Uživatel se tedy musí alespoň v základech orientovat v příslušném formátu dat. +
- +
-Při úpravách šablon je možné využít seznamu, vybrat z něj požadovanou proměnnou nebo funkci a její kostru vložit do šablony. (Velikost formuláře lze plynule měnit a tím lze např. zvětšit pole s popisem vkládaného vzoru proměnné tak, aby byl vidět celý.) +
- +
-Výsledek práce šablony je možné jediným tlačítkem zobrazit ve webovém prohlížeči. Při každé další aplikaci knihovny na upravenou šablonu je automaticky upraven HTML soubor, s kterým byl spuštěn prohlížeč,​ a pak stačí v prohlížeči jen aktualizovat zobrazený soubor.+
  
 +<WRAP round important>​
 +Jestliže mají být aplikovány i uživatelské funkce, je třeba je registrovat před voláním funkce pro zobrazení formuláře.
 +</​WRAP>​
  
-===== Knihovna jako Include nebo Unit =====+==== Knihovna jako Include nebo Unit ====
 Knihovna je připravena ve dvou verzích. Je možné prostě includovat soubor ​ Knihovna je připravena ve dvou verzích. Je možné prostě includovat soubor ​
  
Line 308: Line 478:
 </​code>​ </​code>​
  
-Výhodou unit je bezproblémová práce s formulářem.+na prvním ​řádku klientského skriptu.
  
-===== Ukázka použití knihovny ===== +Výhodou unit je bezproblémová práce s formulářem, je tedy doporučeno používat tuto cestu.
-Musíme odlišit použití knihovny běžným uživatelem a programátorem. Běžný uživatel knihovnu využívá zprostředkovaně a jediné, co může potřebovat, je úprava šablony. K tomuto účelu slouží makra dodávaná s makry, které knihovnu využívají. Takové makro není součástí instalace knihovny a to zejména z toho důvodu, že dost dobře není možné jím registrovat uživatelské funkce, které jsou tvůrcům knihovny neznámé. Bez registrace funkcí by činnost knihovny nebyla úplná, proto je rozumné to nechat na autorech scriptů.+
  
-Programátor má úlohu obtížnější. Musíkromě činností běžných pro exportní scriptyzajistit následující činnosti:+==== Ukázka použití knihovny ==== 
 +Úlohou programátorakterý chce používat tuto knihovnuje:
  
-  - začlenit knihovnu do svého ​scriptu ​(příkazem uses nebo include)+  - začlenit knihovnu do svého ​skriptu ​(příkazem uses nebo include)
   - vytvořit potřebnou šablonu nebo šablony   - vytvořit potřebnou šablonu nebo šablony
   - pokud je to nutné, vytvořit a registrovat uživatelské funkce   - pokud je to nutné, vytvořit a registrovat uživatelské funkce
-  - v kódu exportního scriptu ​volat knihovní funkce pro aplikaci náhrad na šablonu nebo šablony +  - v kódu skriptu ​volat knihovní funkce pro aplikaci náhrad na šablonu nebo šablony 
-  - měl by vytvořit ​makrokteré ​uživateli umožní upravit a otestovat šablonu+  - vytvořit ​skript či jinak publikovat přístup k formulářikterý ​uživateli umožní upravit a otestovat šablonu
  
 Za velmi jednoduchou ukázku nechť slouží následující kód Za velmi jednoduchou ukázku nechť slouží následující kód
  
 <code delphi> <code delphi>
- +uses VarSubstUnit;     //​pouziti knihovny jako unit 
-//uses VarSubsUnit;     //​pouziti knihovny jako unit - zatim nefunguje pro problem s CRLF +//{$I VarSubst.lib.pas} ​  //​vlozeni knihovniho souboru pro preklad soucasne se skriptem
-{$I VarSubst.lib.pas} ​  //​vlozeni knihovniho souboru pro preklad soucasne se scriptem+
  
 var sTemplateGeo:​string;​ var sTemplateGeo:​string;​
 +var iErr:​Integer;​
 ... ...
 function MyReplace(input:​string):​ string; function MyReplace(input:​string):​ string;
 begin begin
   ...   ...
-  Result:​=ReplaceString(input,'​%MY_TEXT%',​VarSubstEncode('​nahrazujici text'​));​+  ​if(pos('​%MY_TEXT%',​Result)>​0) 
 +    then Result:​=ReplaceString(input,'​%MY_TEXT%',​VarSubstEncode('​nahrazujici text'​)); ​ 
 +    //POZOR, jakykoliv vkladany text musi byt v kodovani UTF-8!
   ...   ...
 end; end;
Line 345: Line 517:
   //nacteni sablony   //nacteni sablony
   sTemplate:​=FileToString(sPathFile);​   sTemplate:​=FileToString(sPathFile);​
-  ... +  ... 
 +  iErr := 0; 
 end;  end; 
 ... ...
 procedure PluginWork; procedure PluginWork;
-var iErr:​Integer;​ 
 begin begin
   ...    ... 
Line 357: Line 529:
 end; end;
  
 +procedure PluginStop;
 +begin
 +  if iErr > 0 then ShowMessage('​Pri zpracovani sablon doslo k chybe'​); ​
 +end; 
 </​code>​ </​code>​
-    
  
 +==== Nastavení a konfigurace ====
 +Knihovna neobsahuje žádné konfigurační parametry, které by měly být uživatelsky přístupné. Obsahuje ale některé konstanty, které nastavují velikosti polí. Jejich velikost jsme zvolili jako rozumné maximum, ale může se ukázat, že pro speciální použití některá hodnota nebude dostatečná. Ve zdrojovém kódu je na začátku knihovny definice konstant a uživatel si může pro svoji potřebu tyto hodnoty upravit. Rozhodně by k tomu nemělo docházet nějak houfně - to by spíš ukazovalo na chybný algoritmus použití knihovny nebo na naši špatnou implementaci některé z funkcí. Pokud pocítíte potřebu si tyto konstanty pro své použití upravovat, raději nás kontaktujte s dotazem.
  
 +===== Seznam skriptů, které používají tuto knihovnu =====
 +{{topic>​uses_varsubst}}
  
-===== Nastavení a konfigurace ===== +Pokud jste narazili ​na skript, který knihovnu ​používá, ale není zde uvedenkontaktujteprosímautory.
-Knihovna neobsahuje žádné konfigurační parametry, které by měly být uživatelsky přístupné. Obsahuje ale některé konstanty, které nastavují velikosti polí. Jejich velikost jsme zvolili jako rozumné maximum, ale může se ukázat, že pro speciální použití některá hodnota nebude dostatečná. Ve zdrojovém kódu je na začátku knihovny definice konstant a uživatel si může pro svoji potřebu tyto hodnoty upravit. Rozhodně by k tomu nemělo docházet nějak houfně - to by spíš ukazovalo na chybný algoritmus použití knihovny nebo na naši špatnou implementaci některé z funkcí. +
- +
-===== Poznámky, známé problémy ===== +
-:!: Zásadním problémem je použití uvozovek. Uvozovky omezují textové parametry, ale uvnitř těchto parametrů mohou být další proměnné či funkce, které opět mohou obsahovat v parametrech textové řetězy ohraničené uvozovkami, ... Po nahrazení sice vždy uvozovky //zmizí//, ale pro identifikaci funkcí a jejich parametrů jsou velmi důležité. Je proto třeba jim věnovat zvýšenou pozornost. +
- +
-:!: Je důležité konstruovat šablonu s ohledem na pořadí nahrazování proměnných a vyhodnocování funkcí. ​Pokud bude šablona sestaveny chybně, nedojde ke správnému vyhodnocení a ve výsledku zůstanou vidět //podivné konstrukce//​. +
- +
-:?: Čas - ano, zpracování pomocí knihovny je nepochybně pomalejší než jednoúčelově ​na míru ušitý script. Ovsem produktivita programátorských prací dle našeho mínění minimálně vyváží časovou ztrátu způsobenou pomalejším zpracováním exportu. Příkladem budiž export [[user:skript:​poigarmin|POI Garmin]]. Dříve napsaný speciální script zpracovával mých asi 24000 keší + 5000 waymarků přibližně 12 minut. Předěláním exportu na použití této knihovny se sice zpracování prodloužilo na cca 14 minut, ale kterýkoli uživatel si snadnou úpravou šablony může export upravit sobě na míru. Z uživatelského hlediska použití knihovny přináší větší hodnotu než je ztráta způsobená delším zpracováním. (Pro přesnost dodámže těch 12 minut je údaj po zrychlovací kúřekterou script prodělal. Verzekterá byla rozšířena mezi uživateli, tutéž dávku zpracovávala cca 25 minut, takže i s použitím šablony je to vlastně časová úspora. :-) Všechno se dá zdůvodnit.)+
  
 ===== Stažení ===== ===== Stažení =====
-/* Povinná sekce */ +<WRAP round download
-<box round 95% #DEE7EC+Stáhnout aktuální verzi: ~~DOWNLOAD varsubst-*.gip highest~~ 
-:!: Stáhnout aktuální verzi: ~~DOWNLOAD varsubst-*.gip highest~~ +</WRAP>
-</box> +
- +
-/* V této sekci není třeba nic měnit, pokud se budete držet následujících pravidel: +
- * - skript musí být distribuován v podobě balíčku [[:​user:​skripty:​autor:​gip|gip]] +
- * - balíček musí být pojmenován jako varsubst-čísloverze.gip +
- * - čísloverze obsahuje pouze číslice a tečky (např. 2.11.0.1) +
- * - balíček je uložen jako příloha ke stránce. POZOR! Balíček Je nutno uložit do jmenného prostoru stránky, tedy user:​skript:​varsubst:​varsubst-čísloverze.gip +
- */+
  
 ==== Seznam dostupných verzí ==== ==== Seznam dostupných verzí ====
-/* Povinná sekce */ 
 {{filelist>​varsubst:​*.gip&​style=table&​tableheader=1&​tableshowdate=1&​sort=mtime}} {{filelist>​varsubst:​*.gip&​style=table&​tableheader=1&​tableshowdate=1&​sort=mtime}}
- 
-/* V této sekci rovněž není třeba nic měnit, pokud se budete držet výše vypsaných pravidel */ 
  
 ===== Seznam změn ===== ===== Seznam změn =====
-/Povinná sekce *+** 1.1.1.1 (2011/05/17** 
-=== 1.1 (2011/01/03=== +   ​* ​Opravena drobná chyba, která měla za následek problém při použití příkazů %COORDINATE%,​ %CORRECTEDCOORDINATE% a %WPTCOORDINATE%,​ pokud bylo jako výstupní formátování použito UTF8.
-   ​* ​Úvodní verze          ​+
  
-/* Pokud je seznam změn již moc dlouhý */ 
 <hidden onHidden=":?:​ **Zobrazit změny ve starších verzích**"​ onVisible="​Skrýt změny ve starších verzích">​ <hidden onHidden=":?:​ **Zobrazit změny ve starších verzích**"​ onVisible="​Skrýt změny ve starších verzích">​
-=== 0.(Datum=== +** 1.1.1 (2011/01/24** 
-   * Případné dřívější verze. Pokud je seznam změn příliš dlouhý, je vhodné starší verze skrýt pomocí tagu hidden. Pro jejich zobrazení bude muset uživatel kliknout na tlačítko ​**Zobrazit změny ve starších verzích**  +   * Přidána nová funkce ​**VarSubstDlgTemplateStringNoSave**(caption,​id,​sTemplate:​ string) : String; 
-</​hidden>​+   * Editační formulář - Přidána možnost skrýt pravé výstupní podokno 
 +   * Přesunuto do podsložky \lib\VarSubst ​
  
-/Seznam tagů. Tagy můžete stránce ​idělit buď ručně na následující ​řádcenebo pomocí zatržítek v zápatí editačního okna */ +   Oprava implementace ​evodu výsledného navráceného řetězce do ANSI kódování 
-{{tag>skript ggp lib ggc gge}}+   * Opravena chyba v implementaci nahrazování proměnné %GGSCRIPTDIR% 
 +   * Editační formulář - při zavírání se zobrazí dotazzda si přejete upravenou šablonu uložit 
 +   Další drobné úpravy a opravy  
 + 
 +** 1.1 (2011/01/03) ** 
 +   * Úvodní verze. Pracovali jsme na ní ve volných chvílích přes půl roku.    
 +</hidden>
  
 +{{tag>​author_Gord author_medwyn skript lib}}
user/skript/varsubst.1294129497.txt.gz · Last modified: 2011/01/04 00:00 (external edit)