summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--context/data/context.properties61
-rw-r--r--scripts/context/perl/mptopdf.pl8
-rw-r--r--scripts/context/ruby/base/tex.rb25
-rw-r--r--scripts/context/ruby/base/texutil.rb37
-rw-r--r--scripts/context/ruby/ctxtools.rb73
-rw-r--r--scripts/context/ruby/rlxtools.rb4
-rw-r--r--scripts/context/ruby/rscortool.rb63
-rw-r--r--scripts/context/ruby/rsfiltool.rb340
-rw-r--r--scripts/context/ruby/rslibtool.rb114
-rw-r--r--scripts/context/ruby/runtools.rb14
-rw-r--r--scripts/context/ruby/texexec.rb36
-rw-r--r--scripts/context/ruby/texmfstart.rb108
-rw-r--r--scripts/context/ruby/www/admin.rb215
-rw-r--r--scripts/context/ruby/www/common.rb80
-rw-r--r--scripts/context/ruby/www/dir.rb155
-rw-r--r--scripts/context/ruby/www/exa.rb386
-rw-r--r--scripts/context/ruby/www/lib.rb1391
-rw-r--r--scripts/context/ruby/www/login.rb13
-rw-r--r--scripts/context/ruby/wwwclient.rb677
-rw-r--r--scripts/context/ruby/wwwserver.rb292
-rw-r--r--scripts/context/ruby/wwwwatch.rb464
-rwxr-xr-xscripts/context/stubs/mswin/texmfstart.bat2
-rwxr-xr-xscripts/context/stubs/unix/ctxtools2
-rwxr-xr-xscripts/context/stubs/unix/ctxtools.bat2
-rwxr-xr-xscripts/context/stubs/unix/exatools2
-rwxr-xr-xscripts/context/stubs/unix/exatools.bat2
-rwxr-xr-xscripts/context/stubs/unix/makempy2
-rwxr-xr-xscripts/context/stubs/unix/makempy.bat2
-rwxr-xr-xscripts/context/stubs/unix/mpstools2
-rwxr-xr-xscripts/context/stubs/unix/mpstools.bat2
-rwxr-xr-xscripts/context/stubs/unix/mptopdf2
-rwxr-xr-xscripts/context/stubs/unix/mptopdf.bat2
-rwxr-xr-xscripts/context/stubs/unix/pdftools2
-rwxr-xr-xscripts/context/stubs/unix/pdftools.bat2
-rwxr-xr-xscripts/context/stubs/unix/pstopdf2
-rwxr-xr-xscripts/context/stubs/unix/pstopdf.bat2
-rwxr-xr-xscripts/context/stubs/unix/runtools2
-rwxr-xr-xscripts/context/stubs/unix/runtools.bat2
-rwxr-xr-xscripts/context/stubs/unix/texexec2
-rwxr-xr-xscripts/context/stubs/unix/texexec.bat2
-rwxr-xr-xscripts/context/stubs/unix/texfont2
-rwxr-xr-xscripts/context/stubs/unix/texfont.bat2
-rwxr-xr-xscripts/context/stubs/unix/texmfstart.bat2
-rwxr-xr-xscripts/context/stubs/unix/textools2
-rwxr-xr-xscripts/context/stubs/unix/textools.bat2
-rwxr-xr-xscripts/context/stubs/unix/texutil2
-rwxr-xr-xscripts/context/stubs/unix/texutil.bat2
-rwxr-xr-xscripts/context/stubs/unix/tmftools2
-rwxr-xr-xscripts/context/stubs/unix/tmftools.bat2
-rwxr-xr-xscripts/context/stubs/unix/xmltools2
-rwxr-xr-xscripts/context/stubs/unix/xmltools.bat2
-rw-r--r--tex/context/base/cont-new.tex2
-rw-r--r--tex/context/base/context.tex2
-rw-r--r--tex/context/base/core-job.tex15
-rw-r--r--tex/context/base/core-mat.tex35
-rw-r--r--tex/context/base/core-uti.tex10
-rw-r--r--tex/context/base/core-ver.tex4
-rw-r--r--tex/context/base/enco-ini.tex3
-rw-r--r--tex/context/base/lang-ini.tex28
-rw-r--r--tex/context/base/meta-fig.tex17
-rw-r--r--tex/context/base/regi-utf.tex4
-rw-r--r--tex/context/base/rlxtools.rlx11
-rw-r--r--tex/context/base/spec-tpd.tex7
-rw-r--r--tex/context/base/supp-fil.tex2
-rw-r--r--tex/context/base/supp-mps.tex10
-rw-r--r--tex/context/base/syst-ext.tex2
-rw-r--r--tex/context/base/syst-xtx.tex13
-rw-r--r--tex/context/base/xtag-xsl.tex2
-rw-r--r--tex/context/interface/keys-cz.xml2
-rw-r--r--tex/context/interface/keys-de.xml2
-rw-r--r--tex/context/interface/keys-en.xml2
-rw-r--r--tex/context/interface/keys-fr.xml2
-rw-r--r--tex/context/interface/keys-it.xml2
-rw-r--r--tex/context/interface/keys-nl.xml2
-rw-r--r--tex/context/interface/keys-ro.xml2
-rw-r--r--tex/context/patterns/lang-de.pat4164
-rw-r--r--tex/context/patterns/lang-deo.pat4074
77 files changed, 12823 insertions, 212 deletions
diff --git a/context/data/context.properties b/context/data/context.properties
index 68cd5a419..f99bde78a 100644
--- a/context/data/context.properties
+++ b/context/data/context.properties
@@ -79,23 +79,22 @@ name.context.texexec=texmfstart texexec $(name.texexec.flag.pdfopen)
name.context.texshow=texmfstart texshow
name.context.purge=texmfstart ctxtools --purge --all
name.context.update=texmfstart ctxtools --update
-#name.context.examplap=texmfstart --file=examplap.pdf --program=context --browser
name.context.examplap=texmfstart --browser --file=http://localhost:8061/exalogin
name.context.showcase=texmfstart --file=showcase.pdf --program=context
+name.context.backend=pdf
+
name.example.xmlcheck=tidy -quiet -utf8 -xml -errors
-name.example.examplez=texmfstart examplez.rb
name.metafun.mptopdf=texmfstart mptopdf.pl
-# name.context.exampler=cmd /c start /min "Local Example Service" texmfstart exampler.rb --continue
-# name.context.exampler=texmfstart exampler.rb --continue > /tmp/exampler.log &
+# wwwserver --start --port=8061 --url=http://localhost:8061 --forcetemp --direct
if PLAT_WIN
- name.context.exampler=cmd /c start /min "Local Example Service" texmfstart exaserver.rb --start --port=8061
+ name.context.wwwserver=cmd /c start /min "Local Example Service" texmfstart wwwserver.rb --direct
if PLAT_GTK
- name.context.exampler=texmfstart exaserver.rb --start --port=8061 > /tmp/exampler.log &
+ name.context.wwwserver=texmfstart wwwserver.rb --direct > ~/context-wwwserver.log &
# Commands: help info, e:\websites\www.pragma-ade.com\showcase.pdf / todo: manuals
@@ -132,11 +131,11 @@ command.compile.*.fo=$(name.example.xmlcheck) $(FileNameExt)
#command.compile.subsystem.$(file.patterns.metafun)=1
#command.compile.subsystem.$(file.patterns.example)=1
-command.build.$(file.patterns.context)=$(name.context.texexec) --pdf $(FileNameExt)
-# command.build.$(file.patterns.metafun)=$(name.context.texexec) --pdf --mptex $(FileNameExt)
+command.build.$(file.patterns.context)=$(name.context.texexec) --$(name.context.backend) $(FileNameExt)
+# command.build.$(file.patterns.metafun)=$(name.context.texexec) --$(name.context.backend) --mptex $(FileNameExt)
command.build.$(file.patterns.metafun)=$(name.metafun.mptopdf) $(FileNameExt)
-command.build.$(file.patterns.example)=$(name.context.texexec) --pdf --xml $(FileNameExt)
-command.build.*.fo=$(name.context.texexec) --pdf $(name.texexec.flag.pdfopen) --xml --use=foxet $(FileNameExt)
+command.build.$(file.patterns.example)=$(name.context.texexec) --$(name.context.backend) --xml $(FileNameExt)
+command.build.*.fo=$(name.context.texexec) --$(name.context.backend) $(name.texexec.flag.pdfopen) --xml --use=foxet $(FileNameExt)
command.build.subsystem.$(file.patterns.context)=1
command.build.subsystem.$(file.patterns.metafun)=1
@@ -176,9 +175,9 @@ command.name.1.$(file.patterns.context)=Process TeX file
command.name.1.$(file.patterns.metafun)=Process METAPOST File
command.name.1.$(file.patterns.example)=Process XML File
-command.1.$(file.patterns.context)=$(name.context.texexec) --pdf $(FileNameExt)
-command.1.$(file.patterns.metafun)=$(name.context.texexec) --pdf --mptex $(FileNameExt)
-command.1.$(file.patterns.example)=$(name.context.texexec) --pdf --xml $(FileNameExt)
+command.1.$(file.patterns.context)=$(name.context.texexec) --$(name.context.backend) $(FileNameExt)
+command.1.$(file.patterns.metafun)=$(name.context.texexec) --$(name.context.backend) --mptex $(FileNameExt)
+command.1.$(file.patterns.example)=$(name.context.texexec) --$(name.context.backend) --xml $(FileNameExt)
command.1.subsystem.$(file.patterns.context)=1
command.1.subsystem.$(file.patterns.metafun)=1
@@ -263,24 +262,28 @@ command.name.7.$(file.patterns.context)=Generate Listing
command.name.7.$(file.patterns.metafun)=Generate Listing
command.name.7.$(file.patterns.example)=Generate Listing
-command.7=$(name.context.texexec) --pdf --list --result=$(FileName) $(FileNameExt)
-command.7.$(file.patterns.context)=$(name.context.texexec) --pdf --list --result=$(FileName) $(FileNameExt)
-command.7.$(file.patterns.metafun)=$(name.context.texexec) --pdf --list --result=$(FileName) $(FileNameExt)
-command.7.$(file.patterns.example)=$(name.context.texexec) --pdf --list --result=$(FileName) $(FileNameExt)
+command.7=$(name.context.texexec) --$(name.context.backend) --list --result=$(FileName) $(FileNameExt)
+command.7.$(file.patterns.context)=$(name.context.texexec) --$(name.context.backend) --list --result=$(FileName) $(FileNameExt)
+command.7.$(file.patterns.metafun)=$(name.context.texexec) --$(name.context.backend) --list --result=$(FileName) $(FileNameExt)
+command.7.$(file.patterns.example)=$(name.context.texexec) --$(name.context.backend) --list --result=$(FileName) $(FileNameExt)
command.7.subsystem=1
command.7.subsystem.$(file.patterns.context)=1
command.7.subsystem.$(file.patterns.metafun)=1
command.7.subsystem.$(file.patterns.example)=1
-# 8 : available
+# 8 : reserved
-command.name.8=Example Service
-command.name.8=Example Service
-command.name.8=Example Service
+command.name.8.$(file.patterns.context)=
+command.name.8.$(file.patterns.metafun)=
+command.name.8.$(file.patterns.example)=
+command.8.$(file.patterns.context)=
+command.8.$(file.patterns.metafun)=
+command.8.$(file.patterns.example)=
-# 9 : available
+# 9 : reserved
+command.name.9=
command.name.9.$(file.patterns.context)=
command.name.9.$(file.patterns.metafun)=
command.name.9.$(file.patterns.example)=
@@ -293,9 +296,9 @@ command.9.$(file.patterns.example)=
command.name.10.$(file.patterns.context)=Process and Arrange
command.name.10.$(file.patterns.metafun)=Process and Arrange
command.name.10.$(file.patterns.example)=Process and Arrange
-command.10.$(file.patterns.context)=$(name.context.texexec) --arrange --pdf $(FileNameExt)
-command.10.$(file.patterns.metafun)=$(name.context.texexec) --arrange --pdf --mptex $(FileNameExt)
-command.10.$(file.patterns.example)=$(name.context.texexec) --arrange --pdf --xml $(FileNameExt)
+command.10.$(file.patterns.context)=$(name.context.texexec) --arrange --$(name.context.backend) $(FileNameExt)
+command.10.$(file.patterns.metafun)=$(name.context.texexec) --$(name.context.backend) --mptex $(FileNameExt)
+command.10.$(file.patterns.example)=$(name.context.texexec) --arrange --$(name.context.backend) --xml $(FileNameExt)
command.10.subsystem.$(file.patterns.context)=1
command.10.subsystem.$(file.patterns.metafun)=1
command.10.subsystem.$(file.patterns.example)=1
@@ -332,10 +335,10 @@ command.name.13.$(file.patterns.context)=Example Service
command.name.13.$(file.patterns.metafun)=Example Service
command.name.13.$(file.patterns.example)=Example Service
-command.13=$(name.context.exampler)
-command.13.$(file.patterns.context)=$(name.context.exampler)
-command.13.$(file.patterns.metafun)=$(name.context.exampler)
-command.13.$(file.patterns.example)=$(name.context.exampler)
+command.13=$(name.context.wwwserver)
+command.13.$(file.patterns.context)=$(name.context.wwwserver)
+command.13.$(file.patterns.metafun)=$(name.context.wwwserver)
+command.13.$(file.patterns.example)=$(name.context.wwwserver)
# Editor: syntax highlighting
diff --git a/scripts/context/perl/mptopdf.pl b/scripts/context/perl/mptopdf.pl
index b5d4bc15d..f85c36891 100644
--- a/scripts/context/perl/mptopdf.pl
+++ b/scripts/context/perl/mptopdf.pl
@@ -88,17 +88,17 @@ if (($pattern eq '')||($Help)) {
$rest .= " $mplatexswitch" ;
}
if ($MetaFun) {
- $mpbin = 'mpost --progname=mpost --mem=metafun' ;
+ $mpbin = "mpost --progname=mpost --mem=metafun" ;
} else {
- $mpbin = 'mpost --mem=mpost' ;
+ $mpbin = "mpost --mem=mpost" ;
}
} else {
if ($Latex) {
$rest .= " $texlatexswitch" ;
}
- $mpbin = 'texexec --mptex $PassOn' ;
+ $mpbin = "texexec --mptex $PassOn" ;
}
- print "\n$program : running '$command'" ;
+ print "\n$program : running '$mpbin'\n" ;
my $error = system ("$mpbin $rest $pattern") ;
if ($error) {
print "\n$program : error while processing mp file\n" ;
diff --git a/scripts/context/ruby/base/tex.rb b/scripts/context/ruby/base/tex.rb
index 165d370f9..1e1b67f0f 100644
--- a/scripts/context/ruby/base/tex.rb
+++ b/scripts/context/ruby/base/tex.rb
@@ -50,6 +50,10 @@ class Array
end
end
+ def join_path
+ self.join(File::PATH_SEPARATOR)
+ end
+
end
class TEX
@@ -164,16 +168,22 @@ class TEX
@@extrastringvars = []
def booleanvars
- [@@booleanvars,@@extrabooleanvars].flatten
+ [@@booleanvars,@@extrabooleanvars].flatten.uniq
end
def stringvars
- [@@stringvars,@@extrastringvars].flatten
+ [@@stringvars,@@extrastringvars].flatten.uniq
end
def standardvars
- @@standardvars
+ [@@standardvars].flatten.uniq
end
def knownvars
- @@knownvars
+ [@@knownvars].flatten.uniq
+ end
+ def allbooleanvars
+ [@@booleanvars,@@extrabooleanvars].flatten.uniq
+ end
+ def allstringvars
+ [@@stringvars,@@extrastringvars,@@standardvars,@@knownvars].flatten.uniq
end
def setextrastringvars(vars)
@@ -517,7 +527,8 @@ class TEX
end
mpsformats.each do |mpsformat|
report("generating mps format #{mpsformat}")
- command = [quoted(mpsengine),prognameflag(progname),iniflag,tcxflag,mpsformat,mpsmakeextras(mpsformat)].join(' ')
+ # command = [quoted(mpsengine),prognameflag(progname),iniflag,tcxflag,mpsformat,mpsmakeextras(mpsformat)].join(' ')
+ command = [quoted(mpsengine),iniflag,tcxflag,mpsformat,mpsmakeextras(mpsformat)].join(' ')
report(command) if getvariable('verbose')
system(command)
end
@@ -1185,7 +1196,7 @@ class TEX
if mpsengine && mpsformat && progname then
ENV["MPXCOMMAND"] = "0" unless mpx
# command = [quoted(mpsengine),prognameflag(progname),formatflag(mpsengine,mpsformat),tcxflag,runoptions(mpsengine),filename,mpsprocextras(mpsformat)].join(' ')
- command = [quoted(mpsengine),"-progname=mpost",formatflag(mpsengine,mpsformat),tcxflag,runoptions(mpsengine),mpname,mpsprocextras(mpsformat)].join(' ')
+ command = [quoted(mpsengine),formatflag(mpsengine,mpsformat),tcxflag,runoptions(mpsengine),mpname,mpsprocextras(mpsformat)].join(' ')
report(command) if getvariable('verbose')
system(command)
true
@@ -1285,7 +1296,7 @@ class TEX
report("fixing backend map path for #{backend}") if getvariable('verbose')
ENV['backend'] = backend ;
ENV['progname'] = backend unless validtexengine(backend)
- ENV['TEXFONTMAPS'] = ".;\$TEXMF/fonts/map/{#{backend},pdftex,dvips,}//"
+ ENV['TEXFONTMAPS'] = ['.',"\$TEXMF/fonts/map/{#{backend},pdftex,dvips,}//"].join_path
else
report("unable to fix backend map path") if getvariable('verbose')
end
diff --git a/scripts/context/ruby/base/texutil.rb b/scripts/context/ruby/base/texutil.rb
index 0529f0ca1..89f5e5385 100644
--- a/scripts/context/ruby/base/texutil.rb
+++ b/scripts/context/ruby/base/texutil.rb
@@ -51,12 +51,21 @@ class TeXUtil
@logger = logger
end
+ def report(str)
+ @logger.report("fatal error in plugin (#{str}): #{$!}")
+ puts("\n")
+ $@.each do |line|
+ puts(" #{line}")
+ end
+ puts("\n")
+ end
+
def reset(name)
if @plugins.include?(name) then
begin
eval("#{name}").reset(@logger)
rescue Exception
- @logger.report("fatal error in resetting plugin")
+ report("resetting")
end
else
@logger.report("no plugin #{name}")
@@ -89,7 +98,7 @@ class TeXUtil
begin
eval("#{name}").reader(@logger,data.flatten)
rescue Exception
- @logger.report("fatal error in plugin reader #{name} (#{$!})")
+ report("reading")
end
else
@logger.report("no plugin #{name}")
@@ -107,7 +116,7 @@ class TeXUtil
begin
eval("#{p}").writer(@logger,handle)
rescue Exception
- @logger.report("fatal error in plugin writer #{p} (#{$!})")
+ report("writing")
end
end
end
@@ -117,7 +126,7 @@ class TeXUtil
begin
eval("#{p}").processor(@logger)
rescue Exception
- @logger.report("fatal error in plugin processor #{p} (#{$!})")
+ report("processing")
end
end
end
@@ -127,7 +136,7 @@ class TeXUtil
begin
eval("#{p}").finalizer(@logger)
rescue Exception
- @logger.report("fatal error in plugin finalizer #{p} (#{$!})")
+ report("finalizing")
end
end
end
@@ -211,8 +220,12 @@ class TeXUtil
end
def replace(str)
- str.gsub(@rexa) do
- @rep[$1.escaped]
+ if @rexa then
+ str.gsub(@rexa) do
+ @rep[$1.escaped]
+ end
+ else
+ str
end
end
@@ -226,11 +239,11 @@ class TeXUtil
def remap(str)
s = str.dup
-if true then # numbers are treated special
- s.gsub!(/(\d+)/o) do
- $1.rjust(10,'a') # rest is b .. k
- end
-end
+ if true then # numbers are treated special
+ s.gsub!(/(\d+)/o) do
+ $1.rjust(10,'a') # rest is b .. k
+ end
+ end
if @rexa then
s.gsub!(@rexa) do
@rep[$1.escaped]
diff --git a/scripts/context/ruby/ctxtools.rb b/scripts/context/ruby/ctxtools.rb
index 2092b346c..2104eebf7 100644
--- a/scripts/context/ruby/ctxtools.rb
+++ b/scripts/context/ruby/ctxtools.rb
@@ -181,7 +181,7 @@ class Commands
if @commandline.option("pipe") then
print version
else
- report("context version: #{version}")
+ report("context version: #{version} (#{filename})")
end
end
@@ -789,10 +789,10 @@ class String
def markbraces
level = 0
self.gsub(/([\{\}])/o) do |chr|
- if chr == '{'
+ if chr == '{' then
level = level + 1
chr = "((+#{level}))"
- elsif chr == '}'
+ elsif chr == '}' then
chr = "((-#{level}))"
level = level - 1
end
@@ -803,13 +803,13 @@ class String
def unmarkbraces
self.gsub(/\(\(\+\d+?\)\)/o) do
"{"
- end.gsub(/\(\(\-\d+?\)\)/o) do
+ end .gsub(/\(\(\-\d+?\)\)/o) do
"}"
end
end
def getargument(pattern)
- if self =~ /(#{pattern})\s*\(\(\+(\d+)\)\)(.*?)\(\(\-\2\)\)/ then # no /o
+ if self =~ /(#{pattern})\s*\(\(\+(\d+)\)\)(.*?)\(\(\-\2\)\)/m then # no /o
return $3
else
return ""
@@ -843,6 +843,7 @@ class Language
@language = language
@filenames = filenames
@remapping = Array.new
+ @demapping = Array.new
@unicode = Hash.new
@encoding = encoding
@data = ''
@@ -867,6 +868,9 @@ class Language
def remap(from, to)
@remapping.push([from,to])
end
+ def demap(from, to)
+ @demapping.push([from,to])
+ end
def load(filenames=@filenames)
begin
@@ -906,6 +910,11 @@ class Language
@data = @data.withargument(what) do |content|
report("converting #{what}")
report("")
+ @demapping.each_index do |i|
+ content.gsub!(@demapping[i][0], @demapping[i][1])
+ end
+ content.gsub!(/\\delete\{.*?\}/o) do '' end
+ content.gsub!(/\\keep\{(.*?)\}/o) do $1 end
done = false
@remapping.each_index do |i|
from, to, m = @remapping[i][0], @remapping[i][1], 0
@@ -1242,24 +1251,24 @@ class Language
remap(/Y/, "[ostroke]")
remap(/Z/, "[aring]")
when 'hu' then
-
+ # nothing
when 'ca' then
- remap(/\\c\{.*?\}/, "")
+ demap(/\\c\{/, "\\delete{")
when 'de', 'deo' then
- remap(/\\c\{.*?\}/, "")
- remap(/\\n\{\}/, "")
+ demap(/\\c\{/, "\\delete{")
+ demap(/\\n\{/, "\\keep{")
remap(/\\3/, "[ssharp]")
remap(/\\9/, "[ssharp]")
remap(/\"a/, "[adiaeresis]")
remap(/\"o/, "[odiaeresis]")
remap(/\"u/, "[udiaeresis]")
when 'fr' then
- remap(/\\n\{\}/, "")
+ demap(/\\n\{/, "\\keep{")
remap(/\\ae/, "[adiaeresis]")
remap(/\\oe/, "[odiaeresis]")
when 'la' then
# \lccode`'=`' somewhere else, todo
- remap(/\\c\{.*?\}/, "")
+ demap(/\\c\{/, "\\delete{")
remap(/\\a\s*/, "[aeligature]")
remap(/\\o\s*/, "[oeligature]")
when 'agr' then
@@ -2202,6 +2211,47 @@ end
class Commands
+ @@re_utf_bom = /^\357\273\277/o # just utf-8
+
+ def disarmutfbom
+
+ if @commandline.arguments.empty? then
+ report("provide filename")
+ else
+ @commandline.arguments.each do |filename|
+ report("checking '#{filename}'")
+ if FileTest.file?(filename) then
+ begin
+ data = IO.read(filename)
+ if data.sub!(@@re_utf_bom,'') then
+ if @commandline.option('force') then
+ if f = File.open(filename,'wb') then
+ f << data
+ f.close
+ report("bom found and removed")
+ else
+ report("bom found and removed, but saving file fails")
+ end
+ else
+ report("bom found, use '--force' to remove it")
+ end
+ else
+ report("no bom found")
+ end
+ rescue
+ report("bom found, but removing it fails")
+ end
+ else
+ report("provide valid filename")
+ end
+ end
+ end
+ end
+
+end
+
+class Commands
+
include CommandBase
def updatecontext
@@ -2303,6 +2353,7 @@ commandline.registeraction('brandfiles' , 'add context copyright notice [
commandline.registeraction('platformize' , 'replace line-endings [--recurse --force] [pattern]')
commandline.registeraction('dependencies' , 'analyze depedencies witin context [--compact] [rootfile]')
commandline.registeraction('updatecontext' , 'download latest version and remake formats')
+commandline.registeraction('disarmutfbom' , 'remove utf bom [==force]')
commandline.registervalue('type','')
diff --git a/scripts/context/ruby/rlxtools.rb b/scripts/context/ruby/rlxtools.rb
index 7962474eb..addfe9894 100644
--- a/scripts/context/ruby/rlxtools.rb
+++ b/scripts/context/ruby/rlxtools.rb
@@ -97,13 +97,13 @@ class Commands
report("processing record #{nofrecords} (#{variables['file'] || 'noname'}: #{variables.size} entries)")
if conversion = variables['conversion'] then
report("testing for conversion #{conversion}")
- if suffix = variables['suffix'] then
+ if suffix.downcase = variables['suffix'].downcase then
if file = variables['file'] then
report("conversion #{conversion} for suffix #{suffix} for file #{file}")
else
report("conversion #{conversion} for suffix #{suffix}")
end
- pattern = "@name='#{conversion}' and @suffix='#{suffix}'"
+ pattern = "@name='#{conversion}' and @suffix='#{suffix.downcase}'"
if steps = REXML::XPath.first(proc.root,"/rl:manipulators/rl:manipulator[#{pattern}]") then
localsteps = steps.deep_clone
['rl:old','rl:new'].each do |tag|
diff --git a/scripts/context/ruby/rscortool.rb b/scripts/context/ruby/rscortool.rb
new file mode 100644
index 000000000..c656fed85
--- /dev/null
+++ b/scripts/context/ruby/rscortool.rb
@@ -0,0 +1,63 @@
+# program : rscortool
+# copyright : PRAGMA Publishing On Demand
+# version : 1.00 - 2002
+# author : Hans Hagen
+#
+# project : eXaMpLe
+# concept : Hans Hagen
+# info : j.hagen@xs4all.nl
+# www : www.pragma-pod.com / www.pragma-ade.com
+
+require 'rexml/document.rb'
+
+class Array
+
+ def downcase
+ self.collect { |l| l.to_s.downcase }
+ end
+
+end
+
+class SortedXML
+
+ def initialize (filename)
+ return nil if not filename or filename.empty? or not test(?e,filename)
+ @data = REXML::Document.new(File.new(filename),
+ {:ignore_whitespace_nodes => :all,
+ :compress_whitespace => :all})
+ end
+
+ def save (filename)
+ # filename += '.xml' unless filename.match(/\..*?$/)
+ filename += '.xml' unless filename =~ /\..*?$/
+ if not filename.empty? and f = open(filename,'w')
+ @data.write(f,0)
+ f.close
+ end
+ end
+
+ def sort
+ keys = REXML::XPath.match(@data.root,"/contacts/contact/@label")
+ return unless keys
+ keys = keys.downcase
+ records = @data.elements.to_a("/contacts/contact")
+ @data.elements.delete_all("/contacts/contact")
+ keys = keys.collect do |l| # prepare numbers
+ l.gsub(/(\d+)/) do |d| sprintf('%05d', d) end
+ end
+ keys.sort.each do |s|
+ @data.root.add_element(records[keys.index(s)])
+ end
+ end
+
+end
+
+def sortfile (filename)
+ c = SortedXML.new(filename)
+ c.sort
+ c.save('test.xml')
+end
+
+exit if ARGV[0] == nil or ARGV[0].empty?
+
+sortfile(ARGV[0])
diff --git a/scripts/context/ruby/rsfiltool.rb b/scripts/context/ruby/rsfiltool.rb
new file mode 100644
index 000000000..f3abfdfc7
--- /dev/null
+++ b/scripts/context/ruby/rsfiltool.rb
@@ -0,0 +1,340 @@
+# program : rsfiltool
+# copyright : PRAGMA Publishing On Demand
+# version : 1.01 - 2002
+# author : Hans Hagen
+#
+# project : eXaMpLe
+# concept : Hans Hagen
+# info : j.hagen@xs4all.nl
+# www : www.pragma-pod.com / www.pragma-ade.com
+
+unless defined? ownpath
+ ownpath = $0.sub(/[\\\/]\w*?\.rb/i,'')
+ $: << ownpath
+end
+
+# --name=a,b,c.xml wordt names [a.xml, b.xml, c.xml]
+# --path=x/y/z/a,b,c.xml wordt [x/y/z/a.xml, x/y/z/b.xml, x/y/z/c.xml]
+
+# todo : split session stuff from xmpl/base into an xmpl/session module and "include xmpl/session" into base and here and ...
+
+require 'ftools'
+require 'xmpl/base'
+require 'xmpl/switch'
+require 'xmpl/request'
+
+session = Example.new('rsfiltool', '1.01', 'PRAGMA POD')
+
+filterprefix = 'rsfil-'
+
+commandline = CommandLine.new
+
+commandline.registerflag('submit')
+commandline.registerflag('fetch')
+commandline.registerflag('report')
+#commandline.registerflag('split')
+commandline.registerflag('stamp')
+commandline.registerflag('silent')
+commandline.registerflag('request')
+commandline.registerflag('nobackup')
+
+commandline.registervalue('filter')
+
+commandline.registervalue('root')
+commandline.registervalue('path')
+commandline.registervalue('name')
+
+commandline.expand
+
+session.set('log.silent',true) if commandline.option('silent')
+
+session.inherit(commandline)
+
+session.identify
+
+# session.exit unless session.loadenvironment
+
+def prepare (session)
+
+ # Normally the system provides the file, but a user can provide the rest; in
+ # order to prevent problems with keying in names, we force lowercase names.
+
+ session.set('option.file',session.get('argument.first')) if session.get('option.file').empty?
+
+ root = session.get('option.root').downcase
+ path = session.get('option.path').downcase
+ name = session.get('option.name').downcase
+ file = session.get('option.file').downcase
+
+ session.error('provide file') if file.empty?
+ session.error('provide root') if root.empty?
+
+ filter = session.get('option.filter').downcase
+ trash = session.get('option.trash').downcase
+
+ trash = '' unless FileTest.directory?(trash)
+
+ if not filter.empty? then
+ begin
+ require filter
+ rescue Exception
+ begin
+ require filterprefix + filter
+ rescue Exception
+ session.error('invalid filter')
+ end
+ end
+ begin
+ if RSFIL::valid?(file) then
+ split = RSFIL::split(file,name)
+ path = if split[0].downcase then split[0] else '' end
+ file = if split[1].downcase then split[1] else '' end
+ name = if split[2].downcase then split[2] else '' end
+ session.report('split result',split.inspect)
+ session.error('unable to split off path') if path.empty?
+ session.error('unable to split off file') if file.empty?
+ session.error('unable to split off name') if name.empty?
+ session.set('option.path',path) if path
+ session.set('option.file',file) if file
+ session.set('option.name',name) if name
+ else
+ session.error('invalid filename', file)
+ unless trash.empty? then
+ File.copy(file,trash + '/' + file)
+ end
+ end
+ rescue
+ session.error('unable to split',file,'with filter',filter)
+ end
+ end
+
+ session.error('provide path') if path.empty?
+
+ session.error('invalid root') unless test(?d,root)
+
+ exit if session.error?
+
+ session.set('fb.filename',file)
+
+ path.gsub!(/\\/o, '/')
+ path.gsub!(/\s/o, '')
+
+ path = root + '/' + path
+
+ # multiple paths
+
+ if path =~ /^(.*)\/(.*?)$/o then
+ prepath = $1
+ postpath = $2
+ paths = postpath.split(/\,/)
+ paths.collect! do |p|
+ prepath + '/' + p
+ end
+ else
+ paths = Array.new
+ paths.push(path)
+ end
+
+ paths.collect! do |p|
+ p.gsub(/[^a-zA-Z0-9\s\-\_\/\.\:]/o, '-')
+ end
+
+ file.gsub!(/\\/o, '/')
+ file.gsub!(/[^a-zA-Z0-9\s\-\_\/\.\:]/o, '-')
+
+# if session.get('option.split')
+# if file =~ /(.*)\.(.*?)$/o
+# path = path + '/' + $1
+# else
+# session.error('nothing to split in filename')
+# end
+# end
+
+ paths.each do |p|
+ begin
+ session.report('creating path', p)
+ File.makedirs(p)
+ rescue
+ session.error('unable to create path', p)
+ end
+ end
+
+ name.gsub!(/\s+/,'')
+
+ # can be a,b,c.exa.saved => a.exa.saved,b.exa.saved,c.exa.saved
+
+ if name =~ /(.*?)\.(.*)$/
+ name = $1
+ suffix = $2
+ names = name.split(/\,/)
+ names.collect! do |n|
+ n + '.' + suffix
+ end
+ name = names.join(',')
+ else
+ names = name.split(/\,/)
+ end
+
+ session.set('fb.path',path)
+ session.set('fb.paths',paths)
+ session.set('fb.name',name)
+ session.set('fb.names',names)
+
+end
+
+def thefullname(path,file,name='')
+
+ filename = file.gsub(/.*?\//, '')
+
+ if name.empty?
+ path + '/' + filename
+ else
+ unless name =~ /\..+$/o # unless name.match(/\..+$/o)
+ if filename =~ /(\..+)$/o # if file.match(/(\..+)$/o)
+ name = name + $1
+ end
+ end
+ path + '/' + name
+ end
+
+end
+
+def submitfile (session)
+
+ filename = session.get('fb.filename')
+ paths = session.get('fb.paths')
+ names = session.get('fb.names')
+
+ paths.each do |path|
+ session.report('submitting path',path)
+ names.each do |name|
+ session.report('submitting file',filename,'to',name)
+ submit(session,path,filename,name)
+ end
+ end
+
+end
+
+def submitlist (session)
+
+ requestname = session.get('fb.filename')
+ paths = session.get('fb.paths')
+
+ if test(?e,requestname)
+ session.report('loading request file', requestname)
+ if request = ExaRequest.new(requestname)
+ filelist = request.files
+ if filelist && (filelist.size > 0)
+ filelist.each do |filename|
+ paths.each do |path|
+ session.report('submitting file from list', filename)
+ submit(session,path,filename,request.naturalname(filename))
+ end
+ end
+ else
+ session.warning('no filelist in', requestname)
+ end
+ else
+ session.warning('unable to load', requestname)
+ end
+ else
+ session.warning('no file', requestname)
+ end
+
+end
+
+def submit (session, path, filename, newname)
+
+ fullname = thefullname(path,newname)
+
+ unless test(?e,filename)
+ session.warning('no file to submit', filename)
+ return
+ end
+
+ begin
+ File.copy(fullname,fullname+'.old') if ! session.get('nobackup') && test(?e,fullname)
+ if test(?e,filename)
+ File.copy(filename,fullname)
+ session.report('submit', filename, 'in', fullname)
+ if session.get('option.stamp')
+ f = open(fullname+'.tim','w')
+ f.puts(Time.now.gmtime.strftime("%a %b %d %H:%M:%S %Y"))
+ f.close
+ end
+ else
+ session.error('unable to locate', filename)
+ end
+ rescue
+ session.error('unable to move', filename, 'to', fullname)
+ end
+
+end
+
+def fetch (session)
+
+ filename = session.get('fb.filename')
+ paths = session.get('fb.paths')
+ name = session.get('fb.name')
+
+ begin
+ File.copy(filename,filename+'.old') if ! session.get('nobackup') && test(?e,filename)
+ paths.each do |path|
+ # fullname = thefullname(path,request.naturalname(filename))
+ # fullname = thefullname(path,filename)
+ fullname = thefullname(path,name)
+ if test(?e,fullname)
+ File.copy(fullname,filename)
+ session.report('fetch', filename, 'from', fullname)
+ return
+ else
+ session.report('file',fullname, 'is not present')
+ end
+ end
+ rescue
+ session.error('unable to fetch file from path')
+ end
+ session.error('no file',filename, 'fetched') unless test(?e,filename)
+
+end
+
+def report (session)
+
+ filename = session.get('fb.filename')
+ paths = session.get('fb.paths')
+
+ paths.each do |path|
+ fullname = thefullname(path,request.naturalname(filename))
+ if test(?e,fullname)
+ begin
+ session.report('file', fullname)
+ session.report('size', test(?s,fullname))
+ if test(?e,fullname+'.tim')
+ str = IO.readlines(fullname+'.tim')
+ # str = IO.read(fullname+'.tim')
+ session.report('time', str)
+ end
+ rescue
+ session.error('unable to report about', fullname)
+ end
+ end
+ end
+
+end
+
+if session.get('option.submit')
+ prepare(session)
+ if session.get('option.request')
+ submitlist(session)
+ else
+ submitfile(session)
+ end
+elsif session.get('option.fetch')
+ prepare(session)
+ fetch(session)
+elsif session.get('option.report')
+ prepare(session)
+ report(session)
+else
+ session.report('provide action')
+end
diff --git a/scripts/context/ruby/rslibtool.rb b/scripts/context/ruby/rslibtool.rb
new file mode 100644
index 000000000..7ae5efb64
--- /dev/null
+++ b/scripts/context/ruby/rslibtool.rb
@@ -0,0 +1,114 @@
+# program : rslibtool
+# copyright : PRAGMA Publishing On Demand
+# version : 1.00 - 2002
+# author : Hans Hagen
+#
+# project : eXaMpLe
+# concept : Hans Hagen
+# info : j.hagen@xs4all.nl
+# www : www.pragma-pod.com / www.pragma-ade.com
+
+# --add --base=filename --path=directory pattern
+# --remove --base=filename --path=directory label
+# --sort --base=filename --path=directory
+# --purge --base=filename --path=directory
+# --dummy --base=filename
+# --namespace
+
+# rewrite
+
+unless defined? ownpath
+ ownpath = $0.sub(/[\\\/]\w*?\.rb/i,'')
+ $: << ownpath
+end
+
+require 'rslb/base'
+require 'xmpl/base'
+require 'xmpl/switch'
+
+session = Example.new('rslbtool', '1.0', 'PRAGMA POD')
+
+session.identify
+
+commandline = CommandLine.new
+
+commandline.registerflag('add')
+commandline.registerflag('remove')
+commandline.registerflag('delete')
+commandline.registerflag('sort')
+commandline.registerflag('purge')
+commandline.registerflag('dummy')
+commandline.registerflag('process')
+commandline.registerflag('namespace')
+
+commandline.registervalue('prefix')
+commandline.registervalue('base')
+commandline.registervalue('path')
+commandline.registervalue('result')
+commandline.registervalue('texexec')
+commandline.registervalue('zipalso')
+
+commandline.expand
+
+session.inherit(commandline)
+
+base = session.get('option.base')
+path = session.get('option.path')
+
+base = 'rslbtool.xml' if base.empty?
+
+# when path is given, assume that arg list is list of
+# suffixes, else assume it is a list of globbed filespec
+
+if path.empty?
+ base += '.xml' unless base =~ /\..+$/
+ list = commandline.arguments
+else
+ Dir.chdir(File.dirname(path))
+ list = Dir.glob("*.{#{commandline.arguments.join(',')}}")
+end
+
+begin
+ reslib = Resource.new(base,session.get('option.namespace'))
+ reslib.load(base)
+rescue
+ session.error('problems with loading base')
+ exit
+end
+
+unless session.get('option.texexec').empty?
+ reslib.set_texexec(session.get('option.texexec'))
+end
+
+if session.get('option.add')
+
+ session.report('adding records', list)
+ reslib.add_figures(list,session.get('option.prefix'))
+
+elsif session.get('option.remove') or session.get('option.delete')
+
+ session.report('removing records')
+ reslib.delete_figures(list)
+
+elsif session.get('option.sort')
+
+ session.report('sorting records')
+ reslib.sort_figures()
+
+elsif session.get('option.purge')
+
+ session.report('purging records')
+ reslib.purge_figures()
+
+elsif session.get('option.dummy')
+
+ session.report('creating dummy records')
+ reslib.create_dummies(session.get('option.process'),session.get('option.result'),session.get('option.zipalso'))
+
+else
+
+ session.warning('provide action')
+
+end
+
+reslib.save(base)
diff --git a/scripts/context/ruby/runtools.rb b/scripts/context/ruby/runtools.rb
index 7cb80f4ff..9c504845a 100644
--- a/scripts/context/ruby/runtools.rb
+++ b/scripts/context/ruby/runtools.rb
@@ -213,7 +213,7 @@ class Job
end
end
- def copy_dir(from,to,pattern='*',exclude=[])
+ def copy_dir(from,to,pattern='*',exclude=[]) # recursive
pattern = '*' if ! pattern or pattern.empty?
if from and to and File.expand_path(from) != File.expand_path(to) then
ex = [exclude].flatten
@@ -225,6 +225,18 @@ class Job
end
end
+ def copy_path(from,to,pattern='*',exclude=[]) # non-recursive
+ pattern = '*' if ! pattern or pattern.empty?
+ if from and to and File.expand_path(from) != File.expand_path(to) then
+ ex = [exclude].flatten
+ Dir.glob("#{from}/#{pattern}").each do |file|
+ unless ex.include?(File.extname(file)) then
+ _do_copy_(file,File.join(to,file.sub(/^#{from}/, '')))
+ end
+ end
+ end
+ end
+
def _do_copy_(file,tofile)
if FileTest.file?(file) and File.expand_path(file) != File.expand_path(tofile) then
begin
diff --git a/scripts/context/ruby/texexec.rb b/scripts/context/ruby/texexec.rb
index e4de87b10..2751cef63 100644
--- a/scripts/context/ruby/texexec.rb
+++ b/scripts/context/ruby/texexec.rb
@@ -603,6 +603,42 @@ if job = TEX.new(logger) then
end
+class Commands
+
+ alias saved_help help
+
+ def wrap_help(title, vars)
+ report("")
+ report(title)
+ report("")
+ r, n = '', 0
+ vars.sort.each do |s|
+ if n == 5 then
+ report(r)
+ r, n = '', 1
+ else
+ n += 1
+ end
+ r << ' ' + s
+ end
+ report(r) unless r.empty?
+ end
+
+ def help
+ saved_help
+ if @commandline.option('all') then
+ if job = TEX.new(logger) then
+ wrap_help("boolean switches:", job.allbooleanvars)
+ wrap_help("string switches:", job.allstringvars)
+ end
+ else
+ report('')
+ report('--help --all shows all switches')
+ end
+ end
+
+end
+
# todo: register flags -> first one true
commandline.registerflag('pdf')
diff --git a/scripts/context/ruby/texmfstart.rb b/scripts/context/ruby/texmfstart.rb
index bae921098..569da636c 100644
--- a/scripts/context/ruby/texmfstart.rb
+++ b/scripts/context/ruby/texmfstart.rb
@@ -58,7 +58,9 @@ end
if $kpseerror then
$kpsereport << "unable to locate #{$kpsemodules.join('|')} on library paths:\n\n"
$kpsereport << " " + $:.join("\n ") + "\n\n"
- $kpsereport << "an option is to copy\n\n"
+ $kpsereport << "an option is to point the RUBYLIB variable to\n\n"
+ $kpsereport << " <texmf-local or texmf>/scripts/context/ruby\n\n"
+ $kpsereport << "or to copy\n\n"
$kpsereport << " <texmf-local or texmf>/scripts/context/ruby/base/kpse*\n\n"
$kpsereport << "(including the kpse subpath) to e.g.\n\n"
$kpsereport << " #{$ownpath}/../lib/texmfstart/\n\n"
@@ -74,7 +76,7 @@ if $mswindows then
require "Win32API"
end
-exit if defined?(REQUIRE2LIB)
+# exit if defined?(REQUIRE2LIB)
$stdout.sync = true
$stderr.sync = true
@@ -135,7 +137,7 @@ $makelist = [
'exatools',
'runtools',
#
- 'texmfstart'
+ # no, 'texmfstart'
]
# if ENV['TEXMFSTART_MODE'] = 'experimental' then
@@ -785,75 +787,69 @@ def edit(filename)
end
def make(filename,windows=false,linux=false,remove=false)
- basename = filename.dup
- basename.sub!(/\.[^.]+?$/, '')
- basename.sub!(/^.*[\\\/]/, '')
+ basename = File.basename(filename).gsub(/\.[^.]+?$/, '')
if $stubpath == 'auto' then
basename = File.dirname($0) + '/' + basename
else
basename = $stubpath + '/' + basename unless $stubpath.empty?
end
- if basename == filename then
- report("nothing made (#{filename})")
+ if filename == 'texmfstart' then
+ program = 'ruby'
+ command = 'kpsewhich --format=texmfscripts --progname=context texmfstart.rb'
+ filename = `#{command}`.chomp.gsub(/\\/, '/')
+ if filename.empty? then
+ report("failure: #{command}")
+ return
+ elsif not remove then
+ if windows then
+ ['bat','exe'].each do |suffix|
+ if FileTest.file?("#{basename}.#{suffix}") then
+ report("windows stub '#{basename}.#{suffix}' skipped (already present)")
+ return
+ end
+ end
+ elsif linux && FileTest.file?(basename) then
+ report("unix stub '#{basename}' skipped (already present)")
+ return
+ end
+ end
else
program = nil
if filename =~ /[\\\/]/ && filename =~ /\.(#{$scriptlist})$/ then
program = $applications[$1]
end
filename = "\"#{filename}\"" if filename =~ /\s/
- if filename == 'texmfstart' then
- program = 'ruby'
- command = 'kpsewhich --format=texmfscripts --progname=context texmfstart.rb'
- filename = `#{command}`.chomp
- if filename.empty? then
- report("failure: #{command}")
- return
- elsif not remove then
- if windows then
- ['bat','exe'].each do |suffix|
- if FileTest.file?("#{basename}.#{suffix}") then
- report("windows stub '#{basename}.#{suffix}' skipped (already present)")
- return
- end
- end
- elsif linux && FileTest.file?(basename) then
- report("unix stub '#{basename}' skipped (already present)")
- return
- end
+ program = 'texmfstart' if $indirect || ! program || program.empty?
+ end
+ begin
+ callname = $predefined[filename.sub(/\.*?$/,'')] || filename
+ if remove then
+ if windows && (File.delete(basename+'.bat') rescue false) then
+ report("windows stub '#{basename}.bat' removed (calls #{callname})")
+ elsif linux && (File.delete(basename) rescue false) then
+ report("unix stub '#{basename}' removed (calls #{callname})")
end
else
- program = 'texmfstart' if $indirect || ! program || program.empty?
- end
- begin
- callname = $predefined[filename.sub(/\.*?$/,'')] || filename
- if remove then
- if windows && (File.delete(basename+'.bat') rescue false) then
- report("windows stub '#{basename}.bat' removed (calls #{callname})")
- elsif linux && (File.delete(basename) rescue false) then
- report("unix stub '#{basename}' removed (calls #{callname})")
- end
- else
- if windows && f = open(basename+'.bat','w') then
- f.binmode
- f.write("@echo off\015\012")
- f.write("#{program} #{callname} %*\015\012")
- f.close
- report("windows stub '#{basename}.bat' made (calls #{callname})")
- elsif linux && f = open(basename,'w') then
- f.binmode
- f.write("#!/bin/sh\012")
- f.write("#{program} #{callname} $@\012")
- f.close
- report("unix stub '#{basename}' made (calls #{callname})")
- end
+ if windows && f = open(basename+'.bat','w') then
+ f.binmode
+ f.write("@echo off\015\012")
+ f.write("#{program} #{callname} %*\015\012")
+ f.close
+ report("windows stub '#{basename}.bat' made (calls #{callname})")
+ elsif linux && f = open(basename,'w') then
+ f.binmode
+ f.write("#!/bin/sh\012")
+ f.write("#{program} #{callname} $@\012")
+ f.close
+ report("unix stub '#{basename}' made (calls #{callname})")
end
- rescue
- report("failed to make stub '#{basename}' #{$!}")
- else
- return true
end
+ rescue
+ report("failed to make stub '#{basename}' #{$!}")
+ return false
+ else
+ return true
end
- return false
end
def process(&block)
diff --git a/scripts/context/ruby/www/admin.rb b/scripts/context/ruby/www/admin.rb
new file mode 100644
index 000000000..4e85fd830
--- /dev/null
+++ b/scripts/context/ruby/www/admin.rb
@@ -0,0 +1,215 @@
+require 'fileutils'
+
+require 'www/lib'
+require 'www/dir'
+require 'www/common'
+
+class WWW
+
+ include Common
+
+ # klopt nog niet, twee keer task met een verschillend doel
+
+ def handle_exatask
+ # case @session.check('task', request_variable('task'))
+ task, options, option = @session.get('task'), @session.get('option').split(@@re_bar), request_variable('option')
+ option = (options.first || '') if option.empty?
+ case task
+ when 'exaadmin'
+ @session.set('status', 'admin') # admin: status|dir
+ touch_session(@session.get('id'))
+ if options.include?(option) then
+ case option
+ when 'status' then handle_exaadmin_status
+ when 'dir' then handle_exaadmin_dir
+ else handle_exaadmin_status
+ end
+ elsif option.empty? then
+ message('Status', "unknown option")
+ else
+ message('Status', "option '#{option}' not permitted #{options.inspect}")
+ end
+ else
+ message('Status', "unknown task '#{task}")
+ end
+ end
+
+ def handle_exaadmin
+ if id = valid_session() then
+ handle_exatask
+ else
+ message('Status', 'no login')
+ end
+ end
+
+ def handle_exaadmin_dir
+ check_template_file('exalogin','exalogin-template.htm')
+ @interface.set('path:docroot', work_root)
+ @interface.set('dir:uri', 'exaadmin') # forces the dir handler into cgi mode
+ @interface.set('dir:task', 'exaadmin') # forces the dir handler into cgi mode
+ @interface.set('dir:option', 'dir') # forces the dir handler into cgi mode
+ filename = "#{@@session_prefix}#{request_variable('path')}"
+ fullname = File.join(work_root,filename)
+ if request_variable('path').empty? then
+ handle_exaadmin_status
+ elsif FileTest.directory?(fullname) then
+ handle_dir(filename, [], false)
+ elsif File.zero?(fullname) then
+ message('Error', "The file '#{filename}' is empty")
+ elsif File.size?(fullname) > (4 * 1024 * 1024) then
+ if FileTest.file?(File.expand_path(File.join(cache_root,filename))) then
+ str = "<br/><br/>Cached alternative: <a href=\"#{File.join('cache',filename)}\">#{File.basename(filename)}</a>"
+ else
+ str = ''
+ end
+ message('Error', "The file '#{filename}' is too big to serve over cgi." + str)
+ else
+ send_file(fullname)
+ end
+ end
+
+ def handle_exaadmin_status
+ check_template_file('exalogin','exalogin-template.htm')
+ begin
+ n, str, lines, list, start, most, least, cached = 0, '', '', Hash.new, Time.now, 0, 0, false
+ filename = File.join(tmp_path(dirname),'sessions.rbd')
+ begin
+ File.open(filename) do |f|
+ list = Marshal.load(f)
+ end
+ rescue
+ cached, list = false, Hash.new
+ else
+ cached = true
+ end
+ files = Dir.glob("{#{work_roots.join(',')}}/#{@@session_prefix}*.ses")
+ list.keys.each do |l|
+ list.delete(l) unless files.include?(l) # slow
+ end
+ files.each do |f|
+ ctime = File.ctime(f)
+ stime = list[f][0] == ctime rescue 0
+ unless ctime == stime then
+ begin
+ hash = load_session_file(f)
+ rescue
+ else
+ list[f] = [ctime,hash]
+ end
+ end
+ end
+ begin
+ File.open(filename,'w') do |f|
+ f << Marshal.dump(list)
+ end
+ rescue
+ # no save
+ end
+ begin
+ keys = list.keys.sort do |a,b|
+ case list[b][0] <=> list[a][0]
+ when -1 then -1
+ when +1 then +1
+ else
+ a <=> b
+ end
+ end
+ rescue
+ keys = list.keys.sort
+ end
+ totaltime, totaldone = 0.0, 0
+ if keys.length > 0 then
+ keys.each do |entry|
+ s, t, session = entry, list[entry][0], list[entry][1]
+ status = session['status'] || ''
+ runtime = (session['runtime'] || '').to_f rescue 0
+ starttime = (start.to_i-session['starttime'].to_i).to_s rescue ''
+ requesttime = session['endtime'].to_i-session['starttime'].to_i rescue 0
+ requesttime = if requesttime > 0 then requesttime.to_s else '' end
+ if runtime > 0.0 then
+ totaltime += runtime
+ totaldone += 1
+ if least > 0 then
+ if runtime < least then least = runtime end
+ else
+ least = runtime
+ end
+ if most > 0 then
+ if runtime > most then most = runtime end
+ else
+ most = runtime
+ end
+ end
+ if status.empty? then
+ # skip, garbage
+ elsif status =~ /^(|exa)admin/o then
+ # skip, useless
+ else
+ begin
+ lines << "<tr>\n"
+ lines << td("<a href=\"exaadmin?option=dir&path=#{session['id']}.dir\">#{session['id']}</a>")
+ lines << td(status)
+ lines << td(session['timeout'])
+ lines << td(starttime)
+ lines << td(session['runtime'])
+ lines << td(requesttime)
+ lines << td(t.strftime("%H:%M:%S %Y-%m-%d"))
+ lines << td(session['domain'])
+ lines << td(session['project'])
+ lines << td(session['username'])
+ lines << td(File.basename(File.dirname(s)))
+ lines << "</tr>\n"
+ rescue
+ else
+ n += 1
+ end
+ end
+ end
+ if n > 0 then
+ str = "<table cellpadding='0'>\n"
+ str << "<tr>\n"
+ str << th('session identifier')
+ str << th('status')
+ str << th('timeout')
+ str << th('time')
+ str << th('runtime')
+ str << th('total')
+ str << th('modification&nbsp;time')
+ str << th('domain')
+ str << th('project')
+ str << th('username')
+ str << th('process')
+ str << "</tr>\n"
+ str << lines
+ str << "</table>\n"
+ end
+ end
+ rescue
+ message('Status', "#{$!} There is currently no status available.", false, @@admin_refresh, 'exaadmin')
+ else
+ if n > 0 then
+ # r = if n > 100 then 60 else @@admin_refresh.to_i end # scanning takes long
+ r = @@admin_refresh
+ average = "average = #{if totaldone > 0 then sprintf('%.02f',totaltime/totaldone) else '0' end} (#{sprintf('%.02f',least)} .. #{sprintf('%.02f',most)})"
+ sessions = "sessions = #{n}"
+ refresh = "refresh = #{r.to_s} sec"
+ loadtime = "loadtime = #{sprintf('%.04f',Time.now-start)} sec"
+ cached = if cached then "cached" else "not cached" end
+ message("Status | #{sessions} | #{refresh} | #{loadtime} - #{cached} | #{average} |", str, false, r, 'exaadmin')
+ else
+ message('Status', "There are no sessions registered.", false, @@admin_refresh, 'exaadmin')
+ end
+ end
+ end
+
+ private
+
+ def th(str)
+ "<th align='left'>#{str}&nbsp;&nbsp;&nbsp;</th>\n"
+ end
+
+ def td(str)
+ "<td><code>#{str || ''}&nbsp;&nbsp;&nbsp</code></td>\n"
+ end
+
+end
diff --git a/scripts/context/ruby/www/common.rb b/scripts/context/ruby/www/common.rb
new file mode 100644
index 000000000..9c3832294
--- /dev/null
+++ b/scripts/context/ruby/www/common.rb
@@ -0,0 +1,80 @@
+# We cannot chdir in threads because it is something
+# process wide, so we will run into problems with the
+# other threads. The same is true for the global ENV
+# pseudo hash, so we cannot communicate the runpath
+# via an anvironment either. This leaves texmfstart
+# in combination with a path directive and an tmf file.
+
+module Common # can be a mixin
+
+ # we assume that the hash.subset method is defined
+
+ @@re_texmfstart = /^(texmfstart|ruby\s*texmfstart.rb)\s*(.*)$/
+ @@re_texmfpath = /^\-\-path\=/
+
+ def command_string(path,command,log='')
+ runner = "texmfstart --path=#{File.expand_path(path)}"
+ if command =~ @@re_texmfstart then
+ cmd, arg = $1, $2
+ if arg =~ @@re_texmfpath then
+ # there is already an --path (first switch)
+ else
+ command = "#{runner} #{arg}"
+ end
+ else
+ command = "#{runner} bin:#{command}"
+ end
+ if log && ! log.empty? then
+ return "#{command} 2>&1 > #{File.expand_path(File.join(path,log))}"
+ else
+ return command
+ end
+ end
+
+ def set_os_vars
+ begin
+ ENV['TEXOS'] = ENV['TEXOS'] || platform
+ rescue
+ ENV['TEXOS'] = 'texmf-linux'
+ else
+ ENV['TEXOS'] = 'texmf-' + ENV['TEXOS'] unless ENV['TEXOS'] =~ /^texmf\-/
+ ensure
+ ENV['EXA:TEXOS'] = ENV['TEXOS']
+ end
+ end
+
+ def set_environment(hash)
+ set_os_vars
+ paths = ENV['PATH'].split(File::PATH_SEPARATOR)
+ hash.subset('binpath:').keys.each do |key|
+ begin
+ paths << File.expand_path(hash[key])
+ rescue
+ end
+ end
+ ENV['PATH'] = paths.uniq.join(File::PATH_SEPARATOR)
+ hash.subset('path:').keys.each do |path|
+ key, value = "EXA:#{path.upcase}", File.expand_path(hash[path])
+ ENV[key] = value
+ end
+ end
+
+ def save_environment(hash,path,filename='request.tmf')
+ begin
+ File.open(File.join(path,filename),'w') do |f|
+ set_os_vars
+ ['EXA:TEXOS','TEXOS'].each do |key|
+ f.puts("#{key} = #{ENV[key]}")
+ end
+ hash.subset('binpath:').keys.each do |key|
+ f.puts("PATH < #{File.expand_path(@interface.get(key))}")
+ end
+ hash.subset('path:').keys.each do |path|
+ f.puts("EXA:#{path.upcase} = #{File.expand_path(@interface.get(path))}")
+ end
+ end
+ rescue
+ end
+ end
+
+end
diff --git a/scripts/context/ruby/www/dir.rb b/scripts/context/ruby/www/dir.rb
new file mode 100644
index 000000000..09e088d77
--- /dev/null
+++ b/scripts/context/ruby/www/dir.rb
@@ -0,0 +1,155 @@
+require 'www/lib'
+
+# dir handling
+
+class WWW
+
+ # borrowed code from webrick demo, patched
+
+ @@dir_name_width = 25
+
+ def handle_dir(dirpath=@variables.get('path'),hidden=[],showdirs=true)
+ check_template_file('dir','text-template.htm')
+ docroot = @interface.get('path:docroot')
+ dirpath = dirpath || ''
+ hidden = [] unless hidden
+ local_path = dirpath.dup
+ title, str = "Index of #{escaped(dirpath)}", ''
+ begin
+ local_path.gsub!(/[\/\\]+/,'/')
+ local_path.gsub!(/\/$/, '')
+ if local_path !~ /^(\.|\.\.|\/|[a-zA-Z]\:)$/io then # maybe also /...
+ full_path = File.join(docroot,local_path)
+ @interface.set('log:dir', full_path)
+ begin
+ list = Dir::entries(full_path)
+ rescue
+ str << "unable to parse #{local_path}"
+ else
+ if list then
+ list.collect! do |name|
+ if name =~ /^\.+/o then
+ nil # no . and ..
+ else
+ st = (File::stat(File.join(docroot,local_path,name)) rescue nil)
+ if st.nil? then
+ [name, nil, -1, false]
+ elsif st.directory? then
+ if showdirs then [name + "/", st.mtime, -1, true] else nil end
+ elsif hidden.length > 0 then
+ if hidden.include?(name) then nil else [name, st.mtime, st.size, false] end
+ else
+ [name, st.mtime, st.size, false]
+ end
+ end
+ end
+ list.compact!
+ n, m, s = @variables.get('n'), @variables.get('m'), @variables.get('s')
+ if ! n.empty? then
+ idx, d0 = 0, n
+ elsif ! m.empty? then
+ idx, d0 = 1, m
+ elsif ! s.empty? then
+ idx, d0 = 2, s
+ else
+ idx, d0 = 0, 'a'
+ end
+ d1 = if d0 == 'a' then 'd' else 'a' end
+ if d0 == 'a' then
+ list.sort! do |a,b| a[idx] <=> b[idx] end
+ else
+ list.sort! do |a,b| b[idx] <=> a[idx] end
+ end
+ u = dir_uri(@variables.get('path') || '.')
+ str << "<div class='dir-view'>\n<pre>\n"
+ str << "<a href=\"#{u}&n=#{d1}\">name</A>".ljust(49+u.length)
+ str << "<a href=\"#{u}&m=#{d1}\">last modified</A>".ljust(41+u.length)
+ str << "<a href=\"#{u}&s=#{d1}\">size</A>".rjust(31+u.length) << "\n" << "\n"
+ # parent path
+ if showdirs && ! hidden.include?('..') then
+ dname = "parent directory"
+ fname = "#{File.dirname(dirpath)}"
+ time = File::mtime(File.join(docroot,local_path,"/.."))
+ str << dir_entry(fname,dname,time,-1,true)
+ str << "\n"
+ end
+ # directories
+ done = false
+ list.each do |name, time, size, dir|
+ if dir then
+ if name.size > @@dir_name_width then
+ dname = name.sub(/^(.#{@@dir_name_width-2})(.*)/) do $1 + ".." end
+ else
+ dname = name
+ end
+ fname = "#{escaped(dirpath)}/#{escaped(name)}"
+ str << dir_entry(fname,dname,time,size,dir)
+ done = true
+ end
+ end
+ str << "\n" if done
+ # files
+ list.each do |name, time, size, dir|
+ unless dir then
+ if name.size > @@dir_name_width then
+ dname = name.sub(/^(.#{@@dir_name_width-2})(.*)/) do $1 + ".." end
+ else
+ dname = name
+ end
+ fname = "#{escaped(dirpath)}/#{escaped(name)}"
+ str << dir_entry(fname,dname,time,size,dir)
+ end
+ end
+ str << "\n"
+ str << '</pre></div>'
+ else
+ str << 'no info'
+ end
+ end
+ else
+ str << 'no access'
+ end
+ rescue
+ str << "error #{$!}<br/><pre>"
+ str << $@.join("\n")
+ str << "</pre>"
+ end
+ message(title,str)
+ end
+ def dir_uri(f='.')
+ u, t, o = @interface.get('dir:uri'), @interface.get('dir:task'), @interface.get('dir:option') # takes precedence, in case we run under cgi control
+ if u.empty? then
+ u, t, o = @interface.get('process:uri'), '', ''
+ elsif ! t.empty? then
+ t = "task=#{t}&"
+ o = "option=#{o}&"
+ end
+ if u && ! u.empty? then
+ u = u.sub(/\?.*$/,'') # frozen string
+ if f =~ /^\.+$/ then
+ "#{u}?#{t}#{o}path="
+ else
+ "#{u}?#{t}#{o}path=#{f}"
+ end
+ else
+ ''
+ end
+ end
+
+ def dir_entry(fname,dname,time,size,dir=false)
+ if dir then
+ f = fname.sub(/\/+$/,'').sub(/^\/+/,'')
+ s = "<a href=\"#{dir_uri(f)}\">#{dname}</a>"
+ elsif ! @interface.get('dir:uri').empty? then # takes precedence, in case we run under cgi control
+ s = "<a href=\"#{dir_uri(fname.gsub(/\/+/,'/'))}\">#{dname}</a>"
+ else
+ s = "<a href=\"#{fname.gsub(/\/+/,'/')}\">#{dname}</a>"
+ end
+ # s << " " * (30 - dname.size)
+ s << " " * (@@dir_name_width + 5 - dname.size)
+ s << (time ? time.strftime("%Y/%m/%d %H:%M ") : " " * 22)
+ s << (size >= 0 ? size.to_s : "-").rjust(12) << "\n"
+ return s
+ end
+
+end
diff --git a/scripts/context/ruby/www/exa.rb b/scripts/context/ruby/www/exa.rb
new file mode 100644
index 000000000..6cf7d8a9b
--- /dev/null
+++ b/scripts/context/ruby/www/exa.rb
@@ -0,0 +1,386 @@
+require 'fileutils'
+require 'www/lib'
+require 'www/dir'
+require 'www/common'
+require 'www/admin'
+
+class WWW
+
+ include Common
+
+ def handle_exadefault
+ check_template_file('exalogin','exalogin-template.htm')
+ if id = logged_in_session(true) then
+ finish_login
+ else
+ message('Error', 'No default login permitted.')
+ end
+ end
+
+ def handle_exalogin
+ check_template_file('exalogin','exalogin-template.htm')
+ if id = logged_in_session(false) then
+ finish_login
+ else
+ message('Error', 'No default login permitted.')
+ end
+ end
+
+ def finish_login
+ get_gui()
+ filename, path, task = @session.get('gui'), @session.checked('path','.'), @session.get('task')
+ if ! task.empty? then
+ save_session
+ handle_exatask
+ elsif filename and not filename.empty? then
+ save_session
+ fullname = filename.gsub(/\.\./,'')
+ fullname = File.join(path,filename) unless FileTest.file?(fullname)
+ fullname = File.join(@interface.get('path:interfaces'), filename) unless FileTest.file?(fullname)
+ fullname = File.join(@interface.get('path:interfaces'), path, filename) unless FileTest.file?(fullname)
+ if FileTest.file?(fullname) then
+ send_file(fullname,true)
+ else
+ message('Interface', 'Invalid interface request, no valid interface file.' )
+ end
+ else
+ message('Interface', 'Invalid interface request, no default interface file.')
+ end
+ end
+
+ def handle_exainterface()
+ check_template_file('text','text-template.htm')
+ if id = valid_session() then
+ filename = @interface.get('process:uri').to_s # kind of dup
+ if ! filename.empty? && filename.sub!(/^.*\//,'') then
+ path = @session.checked('path', '.')
+ fullname = filename.gsub(/\.\./,'')
+ fullname = File.join(path,filename) unless FileTest.file?(fullname)
+ fullname = File.join(@interface.get('path:interfaces'),filename) unless FileTest.file?(fullname)
+ fullname = File.join(@interface.get('path:interfaces'),path,filename) unless FileTest.file?(fullname)
+ if FileTest.file?(fullname) then
+ save_session
+ send_file(fullname,true)
+ else
+ get_file(filename)
+ filename, path = @session.get('gui'), @session.checked('path','.')
+ if filename and not filename.empty? then
+ save_session
+ fullname = filename.gsub(/\.\./,'')
+ fullname = File.join(path,filename) unless FileTest.file?(fullname)
+ fullname = File.join(@interface.get('path:interfaces'),filename) unless FileTest.file?(fullname)
+ fullname = File.join(@interface.get('path:interfaces'),path,filename) unless FileTest.file?(fullname)
+ send_file(fullname,true) if FileTest.file?(fullname)
+ else
+ message('Interface', 'Invalid interface request, no interface file.')
+ end
+ end
+ else
+ message('Interface', 'Invalid interface request, no resource file.')
+ end
+ else
+ message('Interface', 'Invalid interface request, no login.')
+ end
+ end
+
+ def handle_exarequest() # todo: check if request is 'command'
+ check_template_file('exalogin','exalogin-template.htm')
+ if id = client_session() then
+ client = true
+ @interface.set('log:kind', "remote client request: #{id}")
+ elsif id = valid_session() then
+ client = false
+ @interface.set('log:kind', "remote browser request: #{id}")
+ else
+ client, id = false, nil
+ @interface.set('log:kind', 'unknown kind of request')
+ end
+ if id then
+ dir, tmp = dirname, tmp_path(dirname)
+ requestname, replyname = 'request.exa', 'reply.exa'
+ requestfile, replyfile = File.join(tmp,requestname), File.join(tmp,replyname)
+ lockfile = File.join(dirname,lckname)
+ action, filename, command, url, req = '', '', '', '', ''
+ extract_sent_files(tmp)
+ @variables.each do |key, value|
+ case key
+ when 'exa:request' then
+ req = value.dup
+ when 'exa:action' then
+ action = value.dup
+ # when 'exa:command' then
+ # command = value.dup
+ # when 'exa:url' then
+ # url = value.dup
+ when 'exa:filename' then
+ filename = value.dup
+ when 'exa:threshold' then
+ @interface.set('process:threshold', value.dup)
+ when /^fakename/o then
+ @variables.set(key, File.basename(value))
+ when /^filename\-/o then
+ @variables.set(key, filename = File.basename(value))
+ when /^dataname\-/o then
+ @variables.set(key)
+ else # remove varname- prefix from value
+ @variables.set(key, @variables.get(key).sub(/#{key}\-/,''))
+ end
+ end
+ @variables.check('exa:filename', filename)
+ @variables.check('exa:action', action)
+ if @variables.empty?('exa:filename') then
+ @variables.set('exa:filename', @interface.get('log:attachments').split('|').first || '')
+ end
+ req.gsub!(/<exa:data\s*\/>/i, '')
+ dat = "<exa:data>\n"
+ @variables.each do |key, value|
+ if ['password','exa:request'].include?(key) then
+ # skip
+ elsif ! value || value.empty? then
+ dat << "<exa:variable label='#{key}'/>\n"
+ else # todo: escape 'm
+ dat << "<exa:variable label='#{key}'>#{value}</exa:variable>\n"
+ end
+ end
+ dat << "</exa:data>\n"
+ if req.empty? then
+ req << "<?xml version='1.0' ?>\n"
+ req << "<exa:request #{@@namespace}'>\n"
+ req << "<exa:application>\n"
+ req << "<exa:action>'#{action}</exa:action>\n" unless action.empty?
+ # req << "<exa:command>'#{command}</exa:command>\n" unless command.empty?
+ # req << "<exa:url>'#{url}</exa:url>\n" unless url.empty?
+ req << "<exa:application>\n"
+ req << "<exa:comment>constructed request</exa:comment>\n"
+ req << dat
+ req << "</exa:request>\n"
+ else
+ # better use rexml but slower
+ if req =~ /<exa:request[^>]*>.*?\s*<exa:threshold>\s*(.*?)\s*<\/exa:threshold>\s*.*?<\/exa:request>/mois then
+ threshold = $1
+ unless threshold.empty? then
+ @interface.set('process:threshold', threshold)
+ @session.set('threshold', threshold)
+ end
+ end
+ req.sub!(/(<exa:request[^>]*>.*?)\s*<exa:option>\s*\-\-action\=(.*?)\s*<\/exa:option>\s*(.*?<\/exa:request>)/mois) do
+ pre, act, pos = $1, $2, $3
+ action = act.sub(/\.exa$/,'') if action.empty?
+ str = "#{pre}<exa:action>#{action}</exa:action>#{pos}"
+ str.sub(/\s*<exa:command>.*?<\/exa:command>\s*/mois ,'')
+ end
+ req.sub!(/(<exa:request[^>]*>.*?)<exa:action>\s*(.*?)\s*<\/exa:action>(.*?<\/exa:request>)/mois) do
+ pre, act, pos = $1, $2, $3
+ action = act.sub(/\.exa$/,'') if action.empty?
+ str = "#{pre}<exa:action>#{action}</exa:action>#{pos}"
+ str.sub(/\s*<exa:command>.*?<\/exa:command>\s*/mois ,'')
+ end
+ unless req =~ /<exa:data>(.*?)<\/exa:data>/mois then
+ req.sub!(/(<\/exa:request>)/) do dat + $1 end
+ end
+ end
+ req.sub!(/<exa:filename>.*?<\/exa:filename>/mois, '')
+ unless @variables.empty?('exa:filename') then
+ req.sub!(/(<\/exa:application>)/mois) do
+ "<exa:filename>#{@variables.get('exa:filename')}<\/exa:filename>" + $1
+ end
+ end
+ @variables.set('exa:action', action)
+ @interface.set("log:#{requestname}", req)
+ begin
+ File.open(requestfile,'w') do |f|
+ f << req
+ end
+ rescue
+ message('Error', 'There is a problem in handling this request (working path access).')
+ return
+ end
+ File.delete(replyfile) rescue false
+ @interface.set('log:action',action)
+ get_command(action)
+ logdata = ''
+ begin
+ command = @session.get('command')
+ @interface.set('log:command',if command.empty? then '[no command]' else command end)
+ if ! command.empty? then
+ @session.set('starttime', Time.now.to_i.to_s) # can be variables and in save list
+ if @interface.true?('process:background') then
+ # background
+ @session.set('status', 'running: background')
+ @session.set('maxtime', @interface.get('process:timeout'))
+ @session.set('threshold', @interface.get('process:threshold'))
+ save_session
+ timeout(@@watch_delay) do
+ save_environment(@interface,tmp)
+ begin
+ starttime = File.mtime(@session_file)
+ # crap
+ loop do
+ sleep(1)
+ if starttime != File.mtime(@session_file) then
+ break unless FileTest.file?(lockfile)
+ end
+ end
+ rescue TimeoutError
+ if client then
+ send_reply()
+ else
+ message('Status', 'Processing your request takes a while',true,5,'exastatus')
+ end
+ return
+ rescue
+ end
+ end
+ if client then send_reply() else send_result() end
+ else
+ # foreground
+ status = 'running: foreground'
+ @session.set('status', status)
+ @session.set('maxtime', @interface.get('process:timeout'))
+ @session.set('threshold', @interface.get('process:threshold'))
+ save_session
+ timeout(@interface.get('process:timeout').to_i) do
+ begin
+ status = 'running: foreground'
+ set_environment(@interface)
+ save_environment(@interface,tmp)
+ command = command_string(tmp,command)
+ logdata = `#{command}`
+ rescue TimeoutError
+ status = 'running: timeout'
+ logdata = "timeout: #{@interface.get('process:timeout')} seconds"
+ rescue
+ status = 'running: aborted'
+ logdata = 'fatal runtime error'
+ else
+ @session.set('endtime', Time.now.to_i.to_s)
+ status = 'running: finished'
+ end
+ end
+ @session.set('status', status)
+ save_session
+ case @session.get('status')
+ when 'running: finished' then
+ if client then send_reply(logdata) else send_result(logdata) end
+ when 'running: timeout' then
+ message('Error', 'There is a problem in handling this request (timeout).')
+ when 'running: aborted' then
+ message('Error', 'There is a problem in handling this request (aborted).')
+ else
+ message('Error', 'There is a problem in handling this request (unknown).')
+ end
+ end
+ else
+ message('Error', 'There is a problem in handling this request (no runner).')
+ end
+ rescue
+ message('Error', 'There is a problem in handling this request (no run).' + $!)
+ end
+ else
+ message('Error', 'Invalid session.')
+ end
+ end
+
+ def handle_exacommand() # shares code with exarequest
+ check_template_file('exalogin','exalogin-template.htm')
+ if id = client_session() then
+ client = true
+ @interface.set('log:kind', "remote client request: #{id}")
+ elsif id = valid_session() then
+ client = false
+ @interface.set('log:kind', "remote browser request: #{id}")
+ else
+ client, id = false, nil
+ @interface.set('log:kind', 'unknown kind of request')
+ end
+ if id then
+ dir, tmp = dirname, tmp_path(dirname)
+ requestname, replyname = 'request.exa', 'reply.exa'
+ requestfile, replyfile = File.join(tmp,requestname), File.join(tmp,replyname)
+ req, command, url = '', '', ''
+ @variables.each do |key, value|
+ case key
+ when 'exa:request' then
+ req = value.dup
+ when 'exa:command' then
+ command = value.dup
+ when 'exa:threshold' then
+ @interface.set('process:threshold', value.dup)
+ when 'exa:url' then
+ url = value.dup
+ end
+ end
+ unless req.empty? then
+ # better use rexml but slower / reuse these : command = filter_from_request('exa:command')
+ if req =~ /<exa:request[^>]*>.*?\s*<exa:command>\s*(.*?)\s*<\/exa:command>\s*.*?<\/exa:request>/mois then
+ command = $1
+ end
+ if req =~ /<exa:request[^>]*>.*?\s*<exa:url>\s*(.*?)\s*<\/exa:url>\s*.*?<\/exa:request>/mois then
+ url = $1
+ end
+ if req =~ /<exa:request[^>]*>.*?\s*<exa:threshold>\s*(.*?)\s*<\/exa:threshold>\s*.*?<\/exa:request>/mois then
+ threshold = $1
+ unless threshold.empty? then
+ @interface.set('process:threshold', threshold)
+ @session.set('threshold', threshold)
+ end
+ end
+ end
+ @variables.check('exa:command', command)
+ @variables.check('exa:url', url)
+ File.delete(replyfile) rescue false
+ case @variables.get('exa:command')
+ when 'fetch' then
+ if @variables.empty?('exa:url') then
+ message('Error', "Problems with fetching, no file given")
+ else
+ # the action starts here
+ filename = @variables.get('exa:url').to_s # kind of dup
+ unless filename.empty? then
+ get_path(filename) # also registers filename as url
+ path = @session.checked('path', '')
+ fullname = filename.gsub(/\.\./,'')
+ fullname = File.join(path,fullname) unless path.empty?
+ if FileTest.file?(fullname) then
+ if client then
+ send_url(fullname)
+ else
+ send_file(fullname,true)
+ end
+ @session.set('threshold', @interface.get('process:threshold'))
+ @session.set('url',filename)
+ save_session
+ else
+ message('Error', "Problems with fetching, unknown file #{fullname}.")
+ # message('Error', "Problems with fetching, unknown file #{filename}.")
+ end
+ else
+ message('Error', "Problems with fetching, invalid file #{filename}.")
+ end
+ # and ends here
+ end
+ else
+ message('Error', "Invalid command #{command}.")
+ end
+ else
+ message('Error', 'Invalid session.')
+ end
+ end
+
+ def handle_exastatus
+ if request_variable('id').empty? then
+ if id = valid_session() then
+ send_result()
+ else
+ message('Error', 'Invalid session.')
+ end
+ else
+ if id = valid_session() then
+ send_reply()
+ else
+ send_reply('invalid session')
+ end
+ end
+ end
+
+end
diff --git a/scripts/context/ruby/www/lib.rb b/scripts/context/ruby/www/lib.rb
new file mode 100644
index 000000000..b330c2a97
--- /dev/null
+++ b/scripts/context/ruby/www/lib.rb
@@ -0,0 +1,1391 @@
+#!/usr/bin/env ruby
+
+# This is just a simple environment for remote processing of context
+# files. It's not a framework, nor an example of how that should be done.
+# Nowadays there are environments like Rails or Nitro. Maybe some day I'll
+# give one of them a try.
+
+# <META Http-Equiv="Cache-Control" Content="no-cache">
+# <META Http-Equiv="Pragma" Content="no-cache">
+# <META Http-Equiv="Expires" Content="0">
+
+# we make limited use of cgi methods because we also need to handle webrick
+
+# %var% as well as $(var) are supported
+
+# paths need to be expanded before they enter apache, since .. is not
+# handled by default
+
+require 'base/variables'
+
+require 'ftools'
+require 'fileutils'
+require 'tempfile'
+require 'timeout'
+require 'md5'
+require 'digest/md5'
+require 'cgi' # we also need escaping for webrick (could move it here)
+
+# beware, namespaces have to match !
+
+module XML
+
+ def XML::element(tag,attributes=nil)
+ if attributes.class == Hash then
+ if block_given? then
+ XML::element(tag,XML::attributes(attributes)) do yield end
+ else
+ XML::element(tag,XML::attributes(attributes))
+ end
+ else
+ if block_given? then
+ "<#{tag}#{if attributes && ! attributes.empty? then ' ' + attributes end}>#{yield}</#{tag}>"
+ else
+ "<#{tag}#{if attributes && ! attributes.empty? then ' ' + attributes end}/>"
+ end
+ end
+ end
+
+ def XML::attributes(hash)
+ str = ''
+ hash.each do |k,v|
+ str << ' ' unless str.empty?
+ if v =~ /\'/ then
+ str << "#{k}=\"#{v}\""
+ else
+ str << "#{k}=\'#{v}\'"
+ end
+ end
+ return str
+ end
+
+ def XML::create(version='1.0')
+ "<?version='#{version}'?>#{yield || ''}"
+ end
+
+ def XML::line
+ "\n"
+ end
+
+end
+
+# str =
+ # XML::create do
+ # XML::element('test') do
+ # XML::element('test') do
+ # 'text a'
+ # end +
+ # XML::element('test',XML::attributes({'a'=>'b'})) do
+ # XML::element('nested',XML::attributes({'a'=>'b'})) do
+ # 'text b-1'
+ # end +
+ # XML::element('nested',XML::attributes({'a'=>'b'})) do
+ # 'text b-2'
+ # end
+ # end +
+ # XML::element('nested',{'a'=>'b'}) do
+ # 'text c'
+ # end
+ # end
+ # end
+
+class ExtendedHash
+
+ DEFAULT = 'default'
+
+ @@re_default = /^(default|)$/i
+
+ def default?(key)
+ self[key] =~ @@re_default rescue true # unset, empty or 'default'
+ end
+
+ def default(key)
+ self[key] = DEFAULT
+ end
+
+ def match?(key,value)
+ value == '*' || value == self[key]
+ end
+
+
+end
+
+class WWW
+
+ @@session_prefix = ''
+ @@data_file = 'example.cfg'
+ @@session_max_age = 60*60
+ @@watch_delay = 30
+ @@send_threshold = 2*1024*1024
+ @@admin_refresh = 10
+ @@namespace = "http://www.pragma-ade.com/schemas/example.rng"
+
+ @@re_bar = /\s*\|\s*/
+ @@re_lst = /\s*\,\s*/
+ @@re_var_a = /\%(.*?)\%/
+ @@re_var_b = /\$\((.*?)\)/
+
+ attr_reader :variables
+ attr_writer :variables
+
+ @@paths = [
+ 'configurations',
+ 'data',
+ 'distributions',
+ 'documents',
+ 'interfaces',
+ 'logs',
+ 'resources',
+ 'runners',
+ 'scripts',
+ 'templates',
+ 'work']
+
+ @@re_true = /^\s*(YES|ON|TRUE|1)\s*$/io
+ @@re_false = /^\s*(NO|OFF|FALSE|0)\s*$/io
+
+ def initialize(webrick_daemon=nil,webrick_request=nil,webrick_response=nil)
+ @session_id, @session_file = '', ''
+ @cgi, @cgi_cookie = nil, nil
+ @webrick_daemon, @webrick_request, @webrick_response = webrick_daemon, webrick_request, webrick_response
+
+ @interface = ExtendedHash.new
+ @variables = ExtendedHash.new
+ @session = ExtendedHash.new
+
+ @checked = false
+
+ analyze_request()
+ update_interface()
+
+ @interface.set('template:message' , 'text-template.htm')
+ @interface.set('template:status' , 'text-template.htm')
+ @interface.set('template:login' , 'exalogin.htm')
+ @interface.set('process:timeout' , @@session_max_age)
+ @interface.set('process:threshold' , @@send_threshold)
+ @interface.set('process:background', 'yes') # this demands a watchdog being active
+ @interface.set('process:indirect' , 'no') # indirect download, no direct feed
+ @interface.set('process:autologin' , 'yes') # provide default interface when applicable
+ @interface.set('process:exaurl' , '') # this one will be used as replacement in templates
+ @interface.set('trace:run' , 'no')
+ @interface.set('trace:errors' , 'no')
+ @interface.set('process:os' , platform)
+ @interface.set('process:texos' , 'texmf-' + platform)
+
+ @interface.set('trace:run' , 'yes') if (ENV['EXA:TRACE:RUN'] || '') =~ @@re_true
+ @interface.set('trace:errors' , 'yes') if (ENV['EXA:TRACE:ERRORS'] || '') =~ @@re_true
+
+ yield self if block_given?
+ end
+
+ def set(key,value)
+ @interface.set(key,value)
+ end
+ def get(key)
+ @interface.get(key,value)
+ end
+
+ def platform
+ case RUBY_PLATFORM
+ when /(mswin|bccwin|mingw|cygwin)/i then 'mswin'
+ when /(linux)/i then 'linux'
+ when /(netbsd|unix)/i then 'unix'
+ when /(darwin|rhapsody|nextstep)/i then 'macosx'
+ else 'unix'
+ end
+ end
+
+ def check_cgi
+ # when mod_ruby is used, we need to close
+ # the cgi session explicitly
+ unless @webrick_request then
+ unless @cgi then
+ @cgi = CGI.new('html4')
+ at_exit do
+ begin
+ @cgi.close
+ rescue
+ end
+ end
+ end
+ end
+ end
+
+ def request_variable(key)
+ begin
+ if @webrick_request then
+ [@webrick_request.query[key]].flatten.first.to_s
+ else
+ check_cgi
+ [@cgi.params[key]].flatten.first.to_s
+ end
+ rescue
+ ''
+ end
+ end
+
+ def request_cookie(key)
+ begin
+ if @cgi then
+ if str = @cgi.cookies[key] then
+ return str.first || ''
+ end
+ elsif @webrick_request then
+ @webrick_request.cookies.flatten.each do |cookie|
+ if cookie.name == key then
+ return cookie.value unless cookie.value.empty?
+ end
+ end
+ end
+ rescue
+ end
+ return ''
+ end
+
+ def analyze_request
+ if @webrick_request then
+ @interface.set('path:docroot', @webrick_daemon.config[:DocumentRoot] || './documents')
+ @interface.set('process:uri', @webrick_request.request_uri.to_s)
+ # @interface.set('process.url', [@webrick_request.host,@webrick_request.request_port].join(':'))
+ @cgi = nil
+ @webrick_request.query.each do |key, value|
+ # todo: filename
+ @variables.set(key, [value].flatten.first)
+ end
+ else
+ @interface.set('path:docroot', ENV['DOCUMENT_ROOT'] || './documents')
+ @interface.set('process:uri', ENV['REQUEST_URI'] || '')
+ # @interface.set('process.url', [ENV['SERVER_NAME'],ENV['SERVER:PORT']].join(':'))
+ ARGV[0] = '' # get rid of terminal mode
+ check_cgi
+ # quite fragile, due to changes between 1.6 and 1.8
+ @cgi.params.keys.each do |p|
+ if @cgi[p].respond_to?(:original_filename) then
+ @interface.set('log:method','post')
+ if @cgi[p].original_filename && ! @cgi[p].original_filename.empty? then
+ @variables.set(p, File.basename(@cgi[p].original_filename))
+ else
+ case @cgi.params[p].class
+ when StringIO.class then @variables.set(p, @cgi[p].read)
+ when Array.class then @variables.set(p, @cgi[p].first.to_s)
+ when String.class then @variables.set(p, @cgi[p])
+ when Tempfile.class then @variables.set(p, '[data blob]')
+ end
+ end
+ else
+ @interface.set('log:method','get') unless @interface.get('log:method') == 'post'
+ @variables.set(p, [@cgi.params[p]].flatten.first.to_s)
+ end
+ end
+ end
+ end
+
+ # name in calling script takes precedence
+ # one can set template:whatever as well
+ # todo: in config
+
+ def check_template_file(tag='',filename='exalogin-template.htm')
+ @interface.set('file:template', filename) if @interface.get('file:template').empty?
+ @interface.set('tag:template', tag)
+ @interface.set('file:template', @interface.get('tag:template')) unless @interface.get('tag:template').empty?
+ end
+
+ def update_interface()
+ root = @interface.get('path:docroot')
+ @interface.set('path:docroot', File.expand_path("#{root}"))
+ @@paths.each do |path|
+ @interface.set("path:#{path}", File.expand_path("#{root}/../#{path}"))
+ end
+ @interface.set('file:template', @interface.get('tag:template')) unless @interface.get('tag:template').empty?
+ end
+
+ def indirect?(result)
+ size = FileTest.size?(result) || 0
+ @interface.true?('trace:errors') || @interface.true?('trace:run') || @interface.true?('process:indirect') ||
+ ((! @interface.empty?('process:threshold')) && (size > @interface.get('process:threshold').to_i)) ||
+ ((! @session.empty?('threshold')) && (size > @session.get('threshold').to_i))
+ end
+
+end
+
+# files
+
+class WWW
+
+ def sesname
+ File.basename(@session_file)
+ end
+ def dirname
+ File.basename(@session_file.sub(/ses$/,'dir'))
+ end
+ def lckname
+ File.basename(@session_file.sub(/ses$/,'lck'))
+ end
+
+ def work_root(expand=true)
+ p = if expand then File.expand_path(@interface.get('path:work')) else @interface.get('path:work') end
+ if @interface.true?('process:background') then
+ File.join(@interface.get('path:work'),'watch')
+ else
+ File.join(@interface.get('path:work'),'direct')
+ end
+ end
+
+ def work_roots(expand=true)
+ p = if expand then File.expand_path(@interface.get('path:work')) else @interface.get('path:work') end
+ [File.join(@interface.get('path:work'),'watch'),File.join(@interface.get('path:work'),'direct')]
+ end
+
+ def cache_root(expand=true)
+ p = if expand then File.expand_path(@interface.get('path:work')) else @interface.get('path:work') end
+ File.join(@interface.get('path:work'),'cache')
+ end
+
+ def cleanup_path(dir)
+ FileUtils::rm_r(pth) rescue false
+ end
+
+ def tmp_path(dir)
+ @interface.set('path:templates', File.expand_path(@interface.get('path:templates'))) # to be sure; here ? ? ?
+ pth = File.join(work_root,dir)
+ File.makedirs(pth) rescue false
+ pth
+ end
+
+ def locked?(lck)
+ FileTest.file?(lck)
+ end
+
+end
+
+# sessions
+
+class WWW
+
+ @@session_tags = ['id','domain','project','username','password','gui','path','process','command','filename','action','status', 'starttime','endtime','runtime','task','option','threshold','url'].sort
+ @@session_keep = ['id','domain','project','username','password','process'].sort
+ @@session_reset = @@session_tags - @@session_keep
+
+ def new_session()
+ if @variables.empty?('exa:session') then
+ @session_id = new_session_id
+ else
+ @session_id = @variables.get('exa:session')
+ end
+ if @session_id == 'default' then # ???
+ @session_id = new_session_id
+ end
+ @session_file = File.join(work_root,"#{@@session_prefix}#{@session_id}.ses")
+ register_session
+ return @session_id
+ end
+
+ def reset_session(all=false)
+ (if all then @@session_tags else @@session_reset end).each do |k|
+ @session.set(k)
+ end
+ end
+
+ def valid_session
+ @session_id = request_variable('id')
+ if @session_id.empty? then
+ begin
+ if @cgi then
+ if @session_id = @cgi.cookies['session_id'] then
+ @session_id = @session_id.first || ''
+ else
+ @session_id = ''
+ end
+ elsif @webrick_request then
+ @webrick_request.cookies.flatten.each do |cookie|
+ if cookie.name == 'session_id' then
+ unless cookie.value.empty? then
+ @session_id = cookie.value
+ # break
+ end
+ end
+ end
+ else
+ @session_id = ''
+ end
+ rescue
+ @interface.set('log:session',"[error in request #{$!}]")
+ return false
+ end
+ end
+ if @session_id.empty? then
+ @interface.set('log:session','[no id, check work dir permissions]')
+ return false
+ else
+ @interface.set('log:session',@session_id)
+ load_session
+ if ! @session.empty?('domain') && ! @session.empty?('project') && ! @session.empty?('username') then
+ register_session
+ return @session_id
+ else
+ return false
+ end
+ end
+ end
+
+ def touch_session(id=nil)
+ begin
+ t = Time.now
+ File.utime(t,t,File.join(work_root,"#{@@session_prefix}#{id || @session_id}.ses")) rescue false
+ rescue
+ false
+ end
+ end
+
+ def forced_session
+ @session_id = new_session
+ if @session_id.empty? then
+ @interface.set('log:session','[no id, check work dir permissions]')
+ return false
+ else
+ return check_session
+ end
+ end
+
+ def client_session
+ request, done = @variables.get('exa:request'), false
+ request.sub!(/(^.*<exa:request[^>]*>.*?)\s*<exa:client>\s*(.*)\s*<\/exa:client>\s*(.*?<\/exa:request>.*$)/mio) do
+ pre, client, post = $1, $2, $3
+ client.scan(/<exa:(domain|project|username|password)>(.*?)<\/exa:\1>/mio) do
+ @variables.set($1, $2)
+ end
+ done = true
+ pre + post
+ end
+ if done then
+ return forced_session
+ else
+ return nil
+ end
+ end
+
+ def register_session
+ if @cgi then
+ @cgi_cookie = CGI::Cookie::new(
+ 'name' => 'session_id',
+ 'value' => @session_id,
+ 'expires' => Time.now + @interface.get('process:timeout').to_i
+ )
+ # @cgi_cookie = CGI::Cookie::new('session_id',@session_id)
+ elsif @webrick_response then
+ if cookie = WEBrick::Cookie.new('session_id', @session_id) then
+ cookie.expires = Time.now + @interface.get('process:timeout').to_i
+ cookie.max_age = @interface.get('process:timeout').to_i
+ cookie.comment = 'exa identifier'
+ @webrick_response.cookies.clear
+ @webrick_response.cookies << cookie
+ end
+ end
+ end
+
+ def new_session_id # taken from cgi
+ md5 = Digest::MD5::new
+ now = Time::now
+ md5.update(now.to_s)
+ md5.update(String(now.usec))
+ md5.update(String(rand(0)))
+ md5.update(String($$))
+ md5.update('foobar')
+ @new_session = true
+ md5.hexdigest[0,32] # was 16
+ end
+
+ @@hide_passwords = true
+ HIDDEN = 'hidden'
+
+ def same_passwords(password) # password in cfg file
+ if @@hide_passwords && (@session.get('password') == HIDDEN) && (@session_id == @session.get('id')) then
+ # this condition is only true when a same session id is found and
+ # the password is checked once and set to HIDDEN
+ same = true
+ elsif password =~ /^MD5:/ then
+ # so, one cannot send a known encrypted password since it will be
+ # encrypted twice then
+ same = (password == "MD5:" + MD5.new(@session.get('password')).hexdigest.upcase)
+ else
+ if (@session.default?('domain') && @session.default?('project') && @session.default?('username')) then
+ @session.default('password') # is this safe enough?
+ end
+ same = (password == @session.get('password'))
+ end
+ if @@hide_passwords && same then
+ @session.set('password', HIDDEN)
+ save_session # next time this session is ok anyway
+ end
+ return same
+ end
+
+ @@session_line = /^\s*(?![\#\%])(.*?)\s*\=\s*(.*?)\s*$/o
+ @@session_begin = 'begin exa session'
+ @@session_end = 'end exa session'
+
+ def loaded_session_data(filename)
+ begin
+ if data = IO.readlines(filename) then
+ return data if (data.first =~ /^[\#\%]\s*#{@@session_begin}/o) && (data.last =~ /^[\#\%]\s*#{@@session_end}/o)
+ end
+ rescue
+ end
+ return nil
+ end
+
+ def load_session()
+ begin
+ @session_file = File.join(work_root,"#{@@session_prefix}#{@session_id}.ses")
+ if data = loaded_session_data(@session_file) then
+ data.each do |line|
+ if line =~ @@session_line then
+ @session.set($1, $2 || '')
+ end
+ end
+ else
+ return false
+ end
+ rescue
+ return false
+ else
+ return true
+ end
+ end
+
+ def load_session_file(filename)
+ begin
+ if data = loaded_session_data(filename) then
+ session = Hash.new
+ data.each do |line|
+ if line =~ @@session_line then
+ session[$1] = $2 || ''
+ end
+ end
+ else
+ Hash.new
+ end
+ rescue
+ Hash.new
+ else
+ session
+ end
+ end
+
+ def save_session
+ begin
+ unless @session_id.empty? then
+ @session_file = File.join(work_root,"#{@@session_prefix}#{@session_id}.ses")
+ @session_file = File.join(work_root,"#{@@session_prefix}#{@session_id}.ses")
+ File.open(@session_file,'w') do |f|
+ f << "\# #{@@session_begin}\n"
+ @@session_tags.each do |tag|
+ if @session && @session.key?(tag) then
+ if ! @session.get(tag).empty? then # no one liner, fails
+ f << "#{tag}=#{@session.get(tag)}\n"
+ end
+ elsif @variables.key?(tag) && ! @variables.empty?(key) then
+ f << "#{tag}=#{@variables.get(tag)}\n"
+ end
+ end
+ @session.subset("ENV").keys.each do |tag|
+ f << "#{tag}=#{@session.get(tag)}\n"
+ end
+ f << "\# #{@@session_end}\n"
+ end
+ end
+ rescue
+ return false
+ else
+ return true
+ end
+ end
+
+ def logged_in_session(force_default=false)
+ if force_default || (@variables.default?('domain') && @variables.default?('project') && @variables.default?('username')) then
+ id = default_session
+ else
+ id = check_session
+ end
+ end
+
+ def default_session
+ if @interface.true?('process:autologin') then
+ @variables.default('domain')
+ @variables.default('project')
+ @variables.default('username')
+ @variables.default('password')
+ check_session
+ else
+ @session_id = nil
+ end
+ end
+
+ def check_session
+ @session.set('domain', @variables.get('domain').downcase)
+ @session.set('project', @variables.get('project').downcase)
+ @session.set('username', @variables.get('username').downcase)
+ @session.set('password', @variables.get('password').downcase)
+ new_session
+ @session.set('id', @session_id)
+ save_session
+ return @session_id
+ end
+
+ def delete_session(id=nil)
+ File.delete(work_root,"#{@@session_prefix}#{id || @session_id}.ses") rescue false
+ end
+
+ def cleanup_sessions(max_age=nil)
+ begin
+ now, age = Time.now, (max_age||@interface.get('process:timeout')).to_i
+ Dir.glob("{#{work_root},#{cache_root}/#{@@session_prefix}*").each do |s|
+ begin
+ if (now - File.mtime(s)) > age then
+ if FileTest.directory?(s) then
+ FileUtils::rm_r(s)
+ else
+ File.delete(s)
+ end
+ end
+ rescue
+ # maybe purged in the meantime
+ end
+ end
+ rescue
+ # maybe another process is busy
+ end
+ end
+
+end
+
+# templates
+
+class WWW
+
+ def filled_template(title,text,showtime=false,refresh=0,refreshurl=nil)
+ template = @interface.get("template:#{@interface.get('tag:template')}")
+ template = @interface.get("template:status") if template.empty?
+ fullname = File.join(@interface.get('path:templates'),template)
+ @interface.set('log:templatename',template)
+ @interface.set('log:templatefile',fullname)
+ append_status(text)
+ htmreply = ''
+ if FileTest.file?(fullname) then
+ begin
+ htmreply = IO.read(fullname)
+ rescue
+ htmreply = ''
+ end
+ end
+ if refresh>0 then
+ if refreshurl then
+ metadata = "<meta http-equiv='refresh' content='#{refresh};#{refreshurl}'>"
+ else
+ metadata = "<meta http-equiv='refresh' content='#{refresh}'>"
+ end
+ else
+ metadata = ''
+ end
+ if ! htmreply || htmreply.empty? then
+ # in head: <link rel='stylesheet' href='/exaresource/exastyle.css'>
+ htmreply = <<-EOD
+ <html>
+ #{metadata}
+ <head>
+ <title>#{title}</title>
+ </head>
+ <body>
+ <h2>#{title}</h2>
+ <h4>#{Time.now}</h4>
+ #{text}
+ </body>
+ </html>
+ EOD
+ else
+ if showtime then
+ exa_template = "<h1>#{title}</h1>\n<h2>#{Time.now}</h2>\n#{text}\n"
+ else
+ exa_template = "<h1>#{title}</h1>#{text}\n"
+ end
+ htmreply = replace_template_placeholder(htmreply,exa_template,metadata)
+ end
+ htmreply
+ end
+
+ def message(title,str='',showtime=false,refresh=0,refreshurl=nil)
+ if @cgi then
+ @cgi.out("cookie"=>[@cgi_cookie]) do
+ filled_template(title,str,showtime,refresh,refreshurl)
+ end
+ elsif @webrick_response then
+ @webrick_response['content-type'] = 'text/html'
+ @webrick_response.body = filled_template(title,str,showtime,refresh,refreshurl)
+ else
+ filled_template(title,str,showtime,refresh,refreshurl)
+ end
+ end
+
+ def plaintext(str)
+ if @cgi then
+ @cgi.out('cookie'=>[@cgi_cookie],'content-type'=>'text/plain') do
+ str
+ end
+ elsif @webrick_response then
+ @webrick_response['content-type'] = 'text/plain'
+ @webrick_response.body = str
+ else
+ str
+ end
+ end
+
+ def exareply(status='',url='',size='',comment='')
+ exaurl = @interface.get('process:exaurl')
+ str = "<?xml version='1.0'?>\n\n"
+ str << "<exa:reply xmlns:exa='#{@@namespace}'>\n"
+ str << " <exa:session>#{@session_id}</exa:session>\n" unless @session_id.empty?
+ str << " <exa:status>#{status}</exa:status>\n" unless (status || '').empty?
+ str << " <exa:url>#{exaurl}/#{url}</exa:url>\n" unless (url || '').empty?
+ str << " <exa:size>#{size}</exa:size>\n" unless (size || '').empty?
+ str << " <exa:comment>#{comment}</exa:comment>\n" unless (comment|| '').empty?
+ str << "</exa:reply>\n"
+ return str
+ end
+
+ def append_status(str='')
+ if @interface.true?('trace:errors') then
+ if $! && $@ then
+ str << "<br/><br/><br/><em>Error:</em><br/><pre>#{$!}</pre><pre>"
+ str << $@.join("\n")
+ end
+ str << '<br/><br/><br/>'
+ str << status_data
+ str << '<em>Paths</em><br/>'
+ str << '<pre>'
+ @interface.subset('path:').each do |k,v|
+ if FileTest.directory?(v) then
+ if FileTest.writable?(v) then
+ str << "#{v} exists and is writable\n"
+ else
+ str << "#{v} is not writable\n"
+ end
+ else
+ str << "#{v} does not exist\n"
+ end
+ end
+ str << '</pre>'
+ end
+ str
+ end
+
+ def simpleurl(url)
+ if url then url.sub(/(:80|:443)$/,'') else '' end
+ end
+
+ def replace_exa_placeholders(data)
+ data.gsub(/([\"\'])\@exa\_([a-zA-Z0-9\-\_]+)\1/) do
+ quot, key, value = $1, $2, ''
+ begin
+ value = @variables.get(key)
+ rescue
+ value = ''
+ end
+ quot + value + quot
+ end
+ end
+
+ def replace_url_placeholder(data)
+ data.gsub!(/(http:\/\/|\/+)*\@exa\_main\_url/, @interface.get('process:exaurl'))
+ replace_exa_placeholders(data)
+ end
+
+ def replace_template_placeholder(data,template='',metadata='')
+ data.gsub!(/(http:\/\/|\/+)*\@exa\_main\_url/, @interface.get('process:exaurl'))
+ data.gsub!(/\@exa\_template/, template)
+ data.gsub!(/\@exa\_metadata/, metadata)
+ replace_exa_placeholders(data)
+ end
+
+ def escaped(str)
+ str
+ end
+
+end
+
+# send files
+
+class WWW
+
+ def send_file(filename,parse=false) # this can take a lot of memory, look for alternative (fastcgi ?)
+ begin
+ if filename =~ /\.pdf$/ then
+ mimetype, parse = 'application/pdf', false
+ elsif filename =~ /\.(html|htm)$/ then
+ mimetype, parse = 'text/html', true
+ else
+ mimetype, parse = 'text/plain', false
+ end
+ if FileTest.file?(filename) then
+ if @webrick_response then
+ begin
+ @webrick_response['content-type'] = mimetype
+ @webrick_response['content-length'] = FileTest.size?(filename)
+ if parse then
+ File.open(filename, 'rb') do |f|
+ @webrick_response.body = replace_url_placeholder(f.read)
+ end
+ else
+ @webrick_response.body = File.open(filename, 'rb')
+ end
+ rescue
+ else
+ return
+ end
+ elsif @cgi then
+ begin
+ # the following works ok, but stores the whole file in memory (see @cgi.out)
+ #
+ # File.open(filename, 'rb') do |f|
+ # @cgi.out('cookie'=>[@cgi_cookie],'connection'=>'close', 'length'=>File.size(filename), 'type'=>mimetype) do
+ # if parse then replace_url_placeholder(f.read) else f.read end
+ # end
+ # end
+ if parse then
+ File.open(filename, 'rb') do |f|
+ @cgi.out('cookie'=>[@cgi_cookie],'connection'=>'close', 'length'=>File.size(filename), 'type'=>mimetype) do
+ replace_url_placeholder(f.read)
+ end
+ end
+ else
+ @cgi.print(@cgi.header('cookie'=>[@cgi_cookie],'connection'=>'close', 'length'=>File.size(filename), 'type'=>mimetype))
+ File.open(filename, 'rb') do |f|
+ while str = f.gets do
+ @cgi.print(str)
+ end
+ end
+ end
+ rescue
+ else
+ return
+ end
+ end
+ end
+ rescue
+ end
+ message('Error', "There is a problem with sending file #{File.basename(filename)}.")
+ end
+
+ def send_htmlfile(filename,parse=false)
+ send_file(filename,parse)
+ end
+ def send_pdffile(filename) # this can take a lot of memory, look for alternative (fastcgi ?)
+ send_file(filename,false)
+ end
+
+end
+
+# tracing
+
+class WWW
+
+ def show_vars(a=@variables,title='')
+ if a && a.length > 0 then
+ if title.empty? then
+ str = ''
+ else
+ str = "<em>#{title}</em>"
+ end
+ str << "<br/><pre>\n"
+ a.keys.sort.each do |k|
+ if k && a[k] && ! a[k].empty? then
+ if k == 'password' then
+ val = if a[k] == 'default' then 'default' else '******' end
+ else
+ # str << "#{k} => #{a[k].sub(/^\s+/moi,'').sub(/\s+$/moi,'')}\n"
+ val = a[k].to_s.strip
+ val.gsub!("&","&amp;")
+ val.gsub!("<","&lt;")
+ val.gsub!(">","&gt;")
+ val.gsub!("\n","\n ")
+ end
+ str << "#{k} => #{val}\n"
+ end
+ end
+ str << "</pre><br/>\n"
+ return str
+ else
+ return ''
+ end
+ end
+
+ def status_data
+ show_vars(@session , 'Session' ) +
+ show_vars(@variables, 'Variables' ) +
+ show_vars(@interface, 'Interface' ) +
+ show_vars(ENV , 'Environment')
+ end
+
+ def report_status
+ check_template_file('status')
+ message('Status',status_data)
+ end
+
+end
+
+# attachments
+
+class WWW
+
+ def extract_sent_files(dir)
+ files = Array.new
+ if @cgi then
+ @cgi.params.keys.each do |tag|
+ begin
+ if filename = @cgi[tag].original_filename then
+ files << extract_file_content(dir,filename,@cgi[tag]) unless filename.empty?
+ end
+ rescue
+ end
+ end
+ elsif @webrick_request then
+ @webrick_request.query.keys.each do |tag|
+ begin
+ if filename = @webrick_request.query[tag].filename then
+ files << extract_file_content(dir,filename,@webrick_request.query[tag]) unless filename.empty?
+ end
+ rescue
+ end
+ end
+ end
+ @interface.set('log:attachments', files.compact.uniq.join('|'))
+ end
+
+ def extract_file_content(dir,filename,data)
+ filename = File.join(dir,File.basename(filename))
+ begin
+ @interface.set('log:attachclass', data.class.inspect)
+ if data.class == Tempfile then
+ begin
+ File.copy(data.path,filename)
+ rescue
+ begin
+ File.open(filename,'wb') do |f|
+ File.open(data.path,'rb') do |g|
+ while str = g.gets do
+ f.write(str)
+ end
+ end
+ end
+ rescue
+ @interface.set('log:attachstate', "saving tempfile #{filename} failed (#{$!})")
+ else
+ @interface.set('log:attachstate', "tempfile #{filename} has been saved")
+ end
+ else
+ @interface.set('log:attachstate', "#{data.path} copied to #{filename}")
+ end
+ elsif data.class == String then
+ begin
+ File.open(filename,'wb') do |f|
+ f.write(data)
+ end
+ rescue
+ @interface.set('log:attachstate', "saving string #{filename} failed (#{$!})")
+ else
+ @interface.set('log:attachstate', "string #{filename} has been saved")
+ end
+ elsif data.class == StringIO then
+ begin
+ File.open(filename,'wb') do |f|
+ f.write(data.read)
+ end
+ rescue
+ @interface.set('log:attachstate', "saving stringio #{filename} failed (#{$!})")
+ else
+ @interface.set('log:attachstate', "stringio #{filename} has been saved")
+ end
+ else
+ @interface.set('log:attachstate', "unknown attachment class #{data.class.to_s}")
+ end
+ rescue
+ begin File.delete(filename) ; rescue ; end
+ else
+ begin File.delete(filename) if FileTest.size(filename) == 0 ; rescue ; end
+ end
+ return File.basename(filename)
+ end
+
+end
+
+# configuration
+
+class WWW
+
+ def interface_base_name(str)
+ str.sub(/\.(pdf|htm|html)$/, '')
+ end
+
+ def located_interface_file(filename)
+ ['configurations', 'runners', 'scripts'].each do |tag|
+ datafile = File.join(@interface.get("path:#{tag}"),filename)
+ if FileTest.file?(datafile+'.encrypted') then
+ return datafile + '.encrypted'
+ elsif FileTest.file?(datafile) then
+ return datafile
+ end
+ end
+ return nil
+ end
+
+ def load_interface_file(filename=@@data_file)
+ reset_session() # no save yet
+ if datafile = located_interface_file(filename) then
+ nestedfiles = Array.new
+ begin
+ data = IO.read(datafile) || ''
+ unless data.empty? then
+ loop do # we need to load them recursively
+ done = false
+ data.gsub!(/^include\s*:\s*(.*?)\s*$/) do
+ includedname, done = $1, true
+ if nestedname = located_interface_file(includedname) then
+ begin
+ str = ("\n" + IO.read(nestedname) + "\n") || ''
+ rescue
+ nestedfiles << File.basename('-'+includedname)
+ ''
+ else
+ nestedfiles << File.basename('+'+includedname)
+ str
+ end
+ else
+ nestedfiles << File.basename('-'+includedname)
+ ''
+ end
+ end
+ break unless done
+ end
+ end
+ @interface.set('log:configurationfile', datafile + ' [' + nestedfiles.join(' ') + ']')
+ return data
+ rescue
+ end
+ end
+ @interface.set('log:configurationfile', filename + ' [not loaded]')
+ return nil
+ end
+
+ def fetch_session_interface_variables(data)
+ data.scan(/^variable\s*:\s*(.*?)\s*\=\s*(.*?)\s*$/) do
+ @interface.set($1, $2)
+ end
+ return true
+ end
+
+ def fetch_session_project_list(data)
+ projectlist, permitted = Array.new, false
+ data.scan(/^user\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*\,\s*(.*?)\s*$/) do
+ domain, username, password, projects = $1, $2, $3, $4
+ if @session.match?('domain',domain) && @session.match?('username',username) then
+ if same_passwords(password) then
+ projectlist, permitted = @interface.resolved(projects).split(@@re_bar), true
+ break
+ end
+ end
+ end
+ if permitted then
+ @interface.set('log:projectlist', '['+projectlist.join(' ')+']')
+ if projectlist.length == 0 then
+ return nil
+ else
+ return projectlist
+ end
+ else
+ @interface.set('log:projectlist', '[no projects]')
+ return nil
+ end
+ end
+
+ def fetch_session_command(data)
+ data.scan(/^process\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*$/) do
+ domain, process, command = $1, $2, $3
+ if @session.match?('domain',domain) && @session.match?('process',process) then
+ @session.set('command', @interface.resolved(command))
+ end
+ end
+ return @session.get('command')
+ end
+
+ def fetch_session_settings(data)
+ data.scan(/^setting\s*:\s*(.*?)\s*\,\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*$/) do
+ domain, process, variable, value = $1, $2, $3, $4
+ if @session.match?('domain',domain) && @session.match?('process',process) then
+ @interface.set(variable,value)
+ end
+ end
+ end
+
+ def get_command(action)
+ # @session.set('action', action)
+ # if @session.get('process') == 'none' then
+ # @interface.set('log:child','yes')
+ # @session.set('process', action)
+ # end
+ if data = load_interface_file() then
+ fetch_session_interface_variables(data)
+ if projectlist = fetch_session_project_list(data) then
+ data.scan(/^project\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*$/) do
+ domain, project, gui, path, process = $1, $2, $3, $4, $5
+ if @session.match?('domain',domain) then
+ if @session.match?('project',project) then
+ if projectlist.include?(project) then
+ @session.set('process', @interface.resolved(process))
+ # break # no, else we end up in the parent (e.g. examplap instead of impose)
+ end
+ elsif ! action.empty? && project == action then
+ if projectlist.include?(action) then
+ @session.set('process', @interface.resolved(process))
+ # break # no, else we end up in the parent (e.g. examplap instead of impose)
+ end
+ end
+ end
+ end
+ fetch_session_command(data)
+ fetch_session_settings(data)
+ end
+ end
+ return ! @session.nothing?('command')
+ end
+
+ def get_file(filename)
+ @session.set('filename', filename)
+ if data = load_interface_file() then
+ fetch_session_interface_variables(data)
+ if projectlist = fetch_session_project_list(data) then
+ data.scan(/^project\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*$/) do
+ domain, project, gui, path, process = $1, $2, $3, $4, $5
+ if @session.match?('domain',domain) then
+ guilist = @interface.resolved(gui).split(@@re_bar)
+ guilist.each do |g|
+ if /#{filename}$/ =~ g then
+ @session.set('gui', File.expand_path(@interface.resolved(g)))
+ @session.set('path', File.expand_path(@interface.resolved(path)))
+ @session.set('process', process)
+ break # take first matching interface
+ end
+ end
+ end
+ end
+ end
+ end
+ return ! (@session.nothing?('gui') && @session.nothing?('path') && @session.nothing?('process'))
+ end
+
+ def get_path(url='')
+ if data = load_interface_file() then
+ fetch_session_interface_variables(data)
+ if projectlist = fetch_session_project_list(data) then
+ data.scan(/^project\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*$/) do
+ domain, project, gui, path, process = $1, $2, $3, $4, $5
+ if @session.match?('domain',domain) && @session.match?('project',project) then
+ @session.set('url', url)
+ @session.set('gui', '')
+ @session.set('path', File.expand_path(@interface.resolved(path)))
+ @session.set('process', '')
+ end
+ end
+ end
+ end
+ return ! @session.nothing?('path')
+ end
+
+ def get_gui()
+ if data = load_interface_file() then
+ fetch_session_interface_variables(data)
+ if projectlist = fetch_session_project_list(data) then
+ data.scan(/^project\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*$/) do
+ domain, project, gui, path, process = $1, $2, $3, $4, $5
+ if @session.match?('domain',domain) && @session.match?('project',project) && projectlist.include?(project) then
+ @session.set('gui', File.expand_path(@interface.resolved(gui)))
+ @session.set('path', File.expand_path(@interface.resolved(path)))
+ @session.set('process', process) unless process == 'none'
+ break # take first matching interface
+ end
+ end
+ data.scan(/^admin\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*\,\s*(.*?)\s*$/) do
+ domain, project, task, option = $1, $2, $3, $4
+ if @session.match?('domain',domain) && @session.match?('project',project) && projectlist.include?(project) then
+ @session.set('task', task)
+ @session.set('option', option)
+ break # take first matching task
+ end
+ end
+ end
+ end
+ return ! (@session.nothing?('gui') && @session.nothing?('path') && @session.nothing?('process'))
+ end
+
+end
+
+class WWW
+
+ def send_reply(logdata='')
+ if @interface.true?('trace:run') then
+ send_result(logdata)
+ else
+ dir, tmp = dirname, tmp_path(dirname)
+ case @session.get('status')
+ when 'running: finished' then
+ resultname, replyname = 'result.pdf', 'reply.exa'
+ replyfile = File.join(tmp,replyname)
+ if FileTest.file?(replyfile) then
+ begin
+ data = IO.read(replyfile)
+ resultname = if data =~ /<exa:output>(.*?)<\/exa:output>/ then $1 else resultname end
+ rescue
+ plaintext(exareply('error in reply'))
+ return
+ end
+ end
+ resultfile = File.join(tmp,resultname)
+ if FileTest.file?(resultfile) then
+ if indirect?(resultfile) then
+ begin
+ File.makedirs(File.join(cache_root,dir))
+ FileUtils::mv(resultfile,File.join(cache_root,dir,resultname))
+ rescue
+ plaintext(exareply('unable to access cache'))
+ else
+ plaintext(exareply('big file', "cache/#{dir}/#{resultname}", "#{File.size?(resultfile)}"))
+ end
+ else
+ send_file(resultfile)
+ end
+ else
+ plaintext(exareply('no result'))
+ end
+ else # background, running, aborted
+ plaintext(exareply(@session.get('status')))
+ end
+ end
+ end
+
+ def send_url(fullname)
+ dir, tmp = dirname, tmp_path(dirname)
+ resultname, replyname = 'result.pdf', 'reply.exa'
+ replyfile = File.join(tmp,replyname)
+ resultfile = File.join(tmp,resultname)
+ if FileTest.file?(fullname) then
+ if indirect?(fullname) then
+ begin
+ File.makedirs(File.join(cache_root,dir))
+ targetname = File.join(cache_root,dir,resultname)
+ File.delete(targetname) rescue false # left overs
+ File.symlink(fullname,targetname) rescue message('Status',$!)
+ unless FileTest.file?(targetname) then
+ FileUtils::cp(fullname,targetname) rescue false
+ end
+ rescue
+ plaintext(exareply('unable to access cache'))
+ else
+ plaintext(exareply('big file', "cache/#{dir}/#{resultname}", "#{File.size?(fullname)}"))
+ end
+ else
+ send_file(fullname)
+ end
+ else
+ message('Status', 'The file is not found')
+ end
+ end
+
+ def send_result(logdata='')
+ check_template_file('exalogin','exalogin-template.htm')
+ dir, tmp = dirname, tmp_path(dirname)
+ resultname, replyname, logname = 'result.pdf', 'reply.exa', 'log.htm'
+ case @session.get('status')
+ when 'running: background' then
+ if st = @session.get('starttime') then # fuzzy
+ st = Time.now.to_i if st.empty?
+ if (Time.now.to_i - st.to_i) > @interface.get('process:timeout').to_i then
+ message('Status', 'Your request has been aborted (timeout)',true)
+ else
+ message('Status', 'Your request is queued',true,5,'exastatus')
+ end
+ end
+ when 'running: busy' then
+ if st = @session.get('starttime') then # fuzzy
+ st = Time.now.to_i if st.empty?
+ if (Time.now.to_i - st.to_i) > @interface.get('process:timeout').to_i then
+ message('Status', 'Your request has been aborted (timeout)',true)
+ else
+ message('Status', 'Your request is being processed',true,5,'exastatus')
+ end
+ end
+ when 'running: aborted' then
+ message('Status', 'Your request has been aborted (timeout)',true)
+ when 'running: finished' then
+ if @interface.true?('trace:run') then
+ logfile = File.join(tmp,logname)
+ begin
+ if f = File.open(logname,'w') then
+ if logdata.empty? then
+ begin
+ logdata = IO.read('www-watch.out')
+ rescue
+ logdata = 'no log data'
+ end
+ end
+ f << filled_template('Log',"<pre>#{CGI::escapeHTML(logdata)}</pre>")
+ f.close
+ end
+ rescue
+ message('Error', '')
+ end
+ if FileTest.file?(logfile) then
+ begin
+ File.makedirs(File.join(cache_root,dir))
+ FileUtils::mv(logfile,File.join(cache_root,dir,logname))
+ rescue
+ logdata = "<br/><br/>unable to access cache</a>"
+ else
+ logdata = "<br/><br/><a href='/cache/#{dir}/#{logname}'>#{logname}</a>"
+ end
+ else
+ logdata = ''
+ end
+ else
+ logdata = ''
+ end
+ # todo: generate reply.exa if no reply
+ replyfile = File.join(tmp,replyname)
+ if FileTest.file?(replyfile) then
+ begin
+ data = IO.read(replyfile)
+ resultname = if data =~ /<exa:output>(.*?)<\/exa:output>/ then $1 else resultname end
+ rescue
+ message('Error','There is a problem in handling this request (invalid reply).')
+ return
+ end
+ end
+ resultfile = File.join(tmp,resultname)
+ if FileTest.file?(resultfile) then
+ if indirect?(resultfile) then
+ begin
+ File.makedirs(File.join(cache_root,dir))
+ FileUtils::mv(resultfile,File.join(cache_root,dir,resultname))
+ rescue
+ str = "<br/><br/>unable to access cache</a>"
+ else
+ str = "<br/><br/><a href='/cache/#{dir}/#{resultname}'>#{resultname}</a>&nbsp;&nbsp;(#{File.size?(resultname)} bytes)"
+ end
+ message('Result', 'You can pick up the result here:' + str + logdata)
+ else
+ send_file(resultfile)
+ end
+ else
+ message('Error', 'There is a problem in handling this request (no result file).' + logdata)
+ end
+ end
+ end
+
+end
diff --git a/scripts/context/ruby/www/login.rb b/scripts/context/ruby/www/login.rb
new file mode 100644
index 000000000..1c88a97e6
--- /dev/null
+++ b/scripts/context/ruby/www/login.rb
@@ -0,0 +1,13 @@
+require 'www/lib'
+
+# basic login
+
+class WWW
+
+ def handle_login()
+ check_template_file('login','exalogin.htm')
+ set('password', '')
+ message('Login','')
+ end
+
+end
diff --git a/scripts/context/ruby/wwwclient.rb b/scripts/context/ruby/wwwclient.rb
new file mode 100644
index 000000000..8f5451a8d
--- /dev/null
+++ b/scripts/context/ruby/wwwclient.rb
@@ -0,0 +1,677 @@
+#!/usr/bin/env ruby
+
+# a direct request is just passed on
+#
+# exaclient --direct --request=somerequest.exa --result=somefile.pdf
+#
+# in an extended request the filename in the template file is replaced by the filename
+# given on the command line; templates are located on the current path and at parent
+# directories (two levels); the filename is expanded to a full path
+#
+# exaclient --extend --template=tmicare-l-h.exa --file=somefile.xml --result=somefile.pdf
+#
+# a constructed request is build out of the provided filename and action; the filename is
+# expanded to a full path
+#
+# exaclient --construct --action=tmicare-s-h.exa --file=somefile.xml --result=somefile.pdf
+#
+# in all cases, the result is either determined by a switch or taken from a reply file
+
+banner = ['WWWClient', 'version 1.0.0', '2003-2006', 'PRAGMA ADE/POD']
+
+$: << File.dirname(File.expand_path($0))
+
+require 'base/switch'
+require 'base/logger'
+
+require 'timeout'
+require 'thread'
+require 'rexml/document'
+require 'net/http'
+
+class File
+
+ def File.backtracked(filename,level=3)
+ if level > 0 && filename && ! filename.empty? then
+ if FileTest.file?(filename) then
+ filename
+ else
+ File.backtracked('../'+filename,level-1)
+ end
+ else
+ filename
+ end
+ end
+
+ def File.expanded(filename)
+ File.expand_path(filename)
+ end
+
+end
+
+class Commands
+
+ include CommandBase
+
+end
+
+class Commands
+
+ @@namespace = "xmlns:exa='http://www.pragma-ade.com/schemas/example.rng'"
+ @@randchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "abcdefghijklmnopqrstuvwxyz"
+
+ def traceback
+ "(error: #{$!})" + "\n -- " + $@.join("\n >>")
+ end
+
+ def pdf(action,filename,enabled)
+ if enabled && FileTest.file?(filename) then
+ begin
+ report("pdf action #{action} on #{filename}")
+ case action
+ when 'close' then system("pdfclose --all")
+ when 'open' then system("pdfopen --file #{filename}")
+ end
+ rescue
+ # forget about it
+ end
+ end
+ end
+
+ def status(replyfile,str) # when block, then ok
+ begin
+ # def status(*whatever)
+ # end
+ File.open(replyfile,'w') do |f|
+ report("saving reply info in '#{replyfile}'")
+ f.puts("<?xml version='1.0'?>\n\n")
+ f.puts("<exa:reply #{@@namespace}>\n")
+ if block_given? then
+ f.puts(" <exa:status>ok</exa:status>\n")
+ f.puts(" #{yield}\n")
+ else
+ f.puts(" <exa:status>error</exa:status>\n")
+ end
+ f.puts(" <exa:comment>" + str + "</exa:comment>\n")
+ f.puts("</exa:reply>\n")
+ f.close
+ report("saving status: #{str}")
+ end
+ rescue
+ report("saving reply info in '#{replyfile}' fails")
+ ensure
+ exit
+ end
+ exit # to be real sure
+ end
+
+
+ def boundary_string (length) # copied from webrick/utils
+ rand_max = @@randchars.size
+ ret = ""
+ length.times do
+ ret << @@randchars[rand(rand_max)]
+ end
+ ret.upcase
+ end
+
+end
+
+class Commands
+
+ @@connecttimeout = 10*60 # ten minutes
+ @@processtimeout = 60*60 # an hour
+ @@polldelay = 5 # 5 seconds
+
+ def main
+
+ datatemplate = @commandline.option('template')
+ datafile = @commandline.option('file')
+ dataaction = @commandline.option('action')
+
+ if ! datatemplate.empty? then
+ report("template '#{datatemplate}' specified without --construct")
+ report("aborting")
+ elsif ! dataaction.empty? then
+ report("action data '#{dataaction}' specified without --construct or --extend")
+ report("aborting")
+ elsif ! datafile.empty? then
+ report("action file '#{datafile}' specified without --construct or --extend")
+ report("aborting")
+ else
+ report("assuming --direct")
+ direct()
+ end
+
+ end
+
+ def construct
+
+ requestfile = @commandline.option('request')
+ replyfile = @commandline.option('reply')
+
+ datatemplate = @commandline.option('template')
+ datafile = @commandline.option('file')
+ dataaction = @commandline.option('action')
+
+ domain = @commandline.option('domain')
+ project = @commandline.option('project')
+ username = @commandline.option('username')
+ password = @commandline.option('password')
+
+ threshold = @commandline.option('threshold')
+
+ datablob = ''
+
+ begin
+ datablob = IO.read(datatemplate)
+ rescue
+ datablob = ''
+ else
+ begin
+ request = REXML::Document.new(datablob)
+ if e = REXML::XPath.match(request.root,"/exa:request/exa:data") then
+ datablob = e.to_s.chomp
+ end
+ rescue
+ datablob = ''
+ end
+ end
+
+ begin
+ File.open(requestfile,'w') do |f|
+ f.puts "<?xml version='1.0'?>\n"
+ f.puts "<exa:request #{@@namespace}>\n"
+ f.puts " <exa:application>\n"
+ f.puts " <exa:action>#{dataaction}</exa:action>\n" unless dataaction.empty?
+ f.puts " <exa:filename>#{datafile}</exa:filename>\n" unless datafile.empty?
+ f.puts " <exa:threshold>#{threshold}</exa:threshold>\n" unless threshold.empty?
+ f.puts " </exa:application>\n"
+ f.puts " <exa:client>\n"
+ f.puts " <exa:domain>#{domain}</exa:domain>\n"
+ f.puts " <exa:project>#{project}</exa:project>\n"
+ f.puts " <exa:username>#{username}</exa:username>\n"
+ f.puts " <exa:password>#{password}</exa:password>\n"
+ f.puts " </exa:client>\n"
+ if datablob.empty? then
+ f.puts " <exa:data/>\n"
+ else
+ f.puts " #{datablob.chomp}\n"
+ end
+ f.puts "</exa:request>"
+ end
+ rescue
+ status(replyfile,"unable to create '#{requestfile}'")
+ end
+
+ direct()
+
+ end
+
+ def extend
+
+ requestfile = @commandline.option('request')
+ replyfile = @commandline.option('reply')
+
+ datatemplate = @commandline.option('template')
+ datafile = @commandline.option('file')
+ dataaction = @commandline.option('action')
+
+ threshold = @commandline.option('threshold')
+
+ if datatemplate.empty? then
+ status(replyfile,"invalid data template '#{datatemplate}'")
+ else
+ begin
+ if FileTest.file?(datatemplate) && oldrequest = IO.read(datatemplate) then
+ request, done = REXML::Document.new(oldrequest), false
+ if ! threshold.empty? && e = REXML::XPath.match(request.root,"/exa:request/exa:application/exa:threshold") then
+ e.text, done = threshold, true
+ end
+ if ! dataaction.empty? && e = REXML::XPath.match(request.root,"/exa:request/exa:application/exa:action") then
+ e.text, done = dataaction, true
+ end
+ if ! datafile.empty? && e = REXML::XPath.match(request.root,"/exa:request/exa:application/exa:filename") then
+ e.text, done = datafile, true
+ end
+ #
+ if ! threshold.empty? && e = REXML::XPath.match(request.root,"/exa:request/exa:application") then
+ e = e.add_element('exa:threshold')
+ e.add_text(threshold.to_s)
+ done = true
+ end
+ #
+ report("nothing replaced in template file") unless done
+ begin
+ File.open(requestfile,'w') do |f|
+ f.puts(newrequest.to_s)
+ end
+ rescue
+ status(replyfile,"unable to create '#{requestfile}'")
+ end
+ else
+ status(replyfile,"unable to read data template '#{datatemplate}'")
+ end
+ rescue
+ status(replyfile,"unable to handle data template '#{datatemplate}'")
+ end
+ end
+
+ direct()
+
+ end
+
+ def direct
+
+ requestpath = @commandline.option('path')
+ requestfile = @commandline.option('request')
+ replyfile = @commandline.option('reply')
+ resultfile = @commandline.option('result')
+ datatemplate = @commandline.option('template')
+ datafile = @commandline.option('file')
+ threshold = @commandline.option('threshold')
+ address = @commandline.option('address')
+ port = @commandline.option('port')
+ session_id = @commandline.option('session')
+ exaurl = @commandline.option('exaurl')
+
+ exaurl = "/#{exaurl}" unless exaurl =~ /^\//
+
+ address.sub!(/^http\:\/\//io) do
+ ''
+ end
+ address.sub!(/\:(\d+)$/io) do
+ port = $1
+ ''
+ end
+
+ autopdf = @commandline.option('autopdf')
+
+ dialogue = nil
+
+ resultfile.sub!(/\.[a-z]+?$/, '') # don't overwrite the source
+
+ unless requestpath.empty? then
+ begin
+ if FileTest.directory?(requestpath) then
+ if Dir.chdir(requestpath) then
+ report("gone to path '#{requestpath}'")
+ else
+ status(replyfile,"unable to go to path '#{requestpath}")
+ end
+ else
+ status(replyfile,"unable to locate '#{requestpath}'")
+ end
+ rescue
+ status(replyfile,"unable to handle '#{requestpath}'")
+ end
+ end
+
+ datafile = File.expand_path(datafile) unless datafile.empty?
+ datatemplate = File.backtracked(datatemplate,3) unless datatemplate.empty?
+
+ # request must be valid
+
+ status(replyfile,'no request file') if requestfile.empty?
+ status(replyfile,"invalid request file '#{requestfile}'") unless FileTest.file?(requestfile)
+
+ begin
+ request = IO.readlines(requestfile).join('')
+ request = REXML::Document.new(request)
+ status(replyfile,'invalid request (no request)') unless request.root.fully_expanded_name=='exa:request'
+ status(replyfile,'invalid request (no application block)') unless request.elements['exa:request'].elements['exa.application'] == nil # explicit nil test needed
+ rescue REXML::ParseException
+ status(replyfile,'invalid request (invalid xml file)')
+ rescue
+ status(replyfile,'invalid request (invalid file)')
+ else
+ report("using request file '#{requestfile}'")
+ end
+
+ # request can force session_id
+
+ if session_id && session_id.empty? then
+ begin
+ id = request.elements['exa:request'].elements['exa:application'].elements['exa:session'].text
+ rescue Exception
+ id = ''
+ ensure
+ if id && ! id.empty? then
+ session_id = id
+ end
+ end
+ end
+
+ # request can overload reply name
+
+ begin
+ rreplyfile = request.elements['exa:request'].elements['exa:application'].elements['exa:output'].text
+ rescue Exception
+ rreplyfile = nil
+ ensure
+ if rreplyfile && ! rreplyfile.empty? then
+ replyfile = rreplyfile
+ report("reply file '#{replyfile} set by request'")
+ else
+ report("using reply file '#{replyfile}'")
+ end
+ end
+
+ # request can overload result name
+
+ begin
+ rresultfile = request.elements['exa:request'].elements['exa:application'].elements['exa:result']
+ rescue Exception
+ rresultfile = nil
+ ensure
+ if rresultfile && ! rresultfile.empty? then
+ resultfile = rresultfile
+ report("result file '#{resultfile}' set by request")
+ else
+ report("using result file '#{resultfile}'")
+ end
+ end
+
+ # try to connect to server
+
+ start_time = Time.now
+
+ processtimeout = begin @commandline.option('timeout').to_i rescue @@processtimeout end
+ processtimeout = @@processtimeout if processtimeout == 0 # 'xx'.to_i => 0
+
+ dialogue = start_dialogue(address, port, processtimeout)
+
+ if dialogue then
+ # continue
+ else
+ status(replyfile,'no connection')
+ end
+
+ # post request
+
+ timeout (@@processtimeout-10) do # -10 so that we run into this one first
+ begin
+ report("posting request of type '#{exaurl}'")
+ report("using session id '#{session_id}'") if session_id && ! session_id.empty?
+ firstline, chunks, total = nil, 0, 0
+ body, boundary, crlf = '', boundary_string(32), "\x0d\x0a"
+ body << '--' + boundary + crlf
+ body << "Content-Disposition: form-data; name=\"exa:request\""
+ body << crlf
+ body << "Content-Type: text/plain"
+ body << crlf + crlf
+ body << request.to_s
+ body << crlf + '--' + boundary + crlf
+if session_id && ! session_id.empty? then
+ body << "Content-Disposition: form-data; name=\"exa:session\""
+ body << "Content-Type: text/plain"
+ body << crlf + crlf
+ body << session_id
+ body << crlf + '--' + boundary + crlf
+end
+ begin
+ File.open(datafile,'rb') do |df|
+ body << "Content-Disposition: form-data; name=\"filename\""
+ body << "Content-Type: text/plain"
+ body << crlf + crlf
+ body << datafile
+ body << crlf + '--' + boundary + crlf
+ body << "Content-Disposition: form-data; name=\"fakename\" ; filename=\"#{datafile}\""
+ body << "Content-Type: application/octetstream"
+ body << "Content-Transfer-Encoding: binary"
+ body << crlf + crlf
+ body << df.read
+ body << crlf + '--' + boundary + '--' + crlf
+ end
+ rescue
+ # skip
+ end
+ headers = Hash.new
+ headers['content-type'] = "multipart/form-data; boundary=#{boundary}"
+ headers['content-length'] = body.length.to_s
+ begin
+ File.open(resultfile,'wb') do |rf|
+ begin
+ # firstline is max 1024 but ok for reply
+ dialogue.post(exaurl,body,headers) do |str|
+ if ! firstline || firstline.empty? then
+ report('receiving result') if total == 0
+ firstline = str
+ end
+ total += 1
+ rf.write(str)
+ end
+ rescue
+ report("forced close #{traceback}")
+ end
+ end
+ rescue
+ status(replyfile,'cannot open file')
+ end
+ begin
+ File.delete(resultfile) if File.zero?(resultfile)
+ rescue
+ end
+ unless FileTest.file?(resultfile) then
+ report("deleting empty resultfile")
+ begin
+ File.delete(resultfile)
+ rescue
+ # nice try, an error anyway
+ end
+ status(replyfile,'empty file')
+ else
+ n, id, status = 0, '', ''
+ loop do
+ again = false
+ if ! dialogue then
+ again = true
+ elsif firstline =~ /(\<exa:reply)/moi then
+ begin
+ reply = REXML::Document.new(firstline)
+ id = (REXML::XPath.match(reply.root,"/exa:reply/exa:session/text()") || '').to_s
+ status = (REXML::XPath.match(reply.root,"/exa:reply/exa:status/text()") || '').to_s
+ rescue
+ report("error in parsing reply #{traceback}")
+ break
+ else
+ report("status: #{status}")
+ if (status =~ /^running\s*\:\s*(background|busy)$/i) && (! id.empty?) then
+ report("waiting for status reply (#{n*@@polldelay})")
+ again = true
+ end
+ end
+ end
+ if again then
+ n += 1
+ sleep(@@polldelay) # todo: duplicate when n > 1
+ unless dialogue then
+ report('reestablishing connection')
+ dialogue = start_dialogue(address, port, processtimeout)
+ end
+ if dialogue then
+ begin
+ File.open(resultfile,'wb') do |rf|
+ begin
+ body = "id=#{id}"
+ headers = Hash.new
+ headers['content-type'] = "application/x-www-form-urlencoded"
+ headers['content-length'] = body.length.to_s
+ total, firstline = 0, ''
+ dialogue.post("/exastatus",body,headers) do |str|
+ if ! firstline || firstline.empty? then
+ firstline = str
+ end
+ total += 1
+ rf.write(str)
+ end
+ rescue
+ report("forced close #{traceback}")
+ dialogue = nil
+ again = true
+ end
+ end
+ begin
+ File.delete(resultfile) if File.zero?(resultfile)
+ rescue
+ end
+ rescue
+ report("error in opening file #{traceback}")
+ status(replyfile,'cannot open file')
+ end
+ else
+ report("unable to make a connection")
+ status(replyfile,'unable to make a connection') # exit
+ end
+ else
+ break
+ end
+ end
+ case firstline
+ when /<\?xml\s*version=.*?\?>\s*<exa:reply/moi then
+ begin
+ File.delete(replyfile) if FileTest.file?(replyfile)
+ resultfile = replyfile if File.rename(resultfile,replyfile)
+ rescue
+ end
+ report("reply saved in '#{resultfile}'")
+ when /\%PDF\-/io then
+ report("done, file #{resultfile}, type pdf, #{total} chunks, #{File.size? rescue 0} bytes")
+ if resultfile =~ /\.pdf$/i then
+ report("file identified as 'pdf'")
+ elsif resultfile =~ /\..*$/o
+ report("result file suffix should be 'pdf'")
+ else
+ newresultfile = resultfile + '.pdf'
+ newresultfile.sub!(/\.pdf\.pdf/io, '.pdf')
+ pdf('close',newresultfile,autopdf)
+ begin
+ File.delete(newresultfile) if FileTest.file?(newresultfile)
+ resultfile = newresultfile if File.rename(resultfile,newresultfile)
+ rescue
+ report("adding 'pdf' suffix to result name failed")
+ else
+ report("'pdf' suffix added to result name")
+ end
+ end
+ report("result saved in '#{resultfile}'")
+ pdf('open',resultfile,autopdf)
+ status(replyfile,'ok') do
+ "<exa:filename>#{resultfile}</exa:filename>"
+ end
+ when /html/io then
+ report("done, file #{resultfile}, type html, #{total} chunks, #{File.size? rescue 0} bytes")
+ if resultfile =~ /\.(htm|html)$/i then
+ report("file identified as 'html'")
+ elsif resultfile =~ /\..*$/o
+ report("result file suffix should be 'htm'")
+ else
+ newresultfile = resultfile + '.htm'
+ begin
+ File.delete(newresultfile) if FileTest.file?(newresultfile)
+ resultfile = newresultfile if File.rename(resultfile,newresultfile)
+ rescue
+ report("adding 'htm' suffix to result name failed")
+ else
+ report("'htm' suffix added to result name")
+ end
+ end
+ report("result saved in '#{resultfile}'")
+ status(replyfile,'ok') do
+ "<exa:filename>#{resultfile}</exa:filename>"
+ end
+ else
+ report("no result file, first line #{firstline}")
+ status(replyfile,'no result file')
+ end
+ end
+ rescue TimeoutError
+ report("aborted due to time out")
+ status(replyfile,'time out')
+ rescue
+ report("aborted due to some problem #{traceback}")
+ status(replyfile,"no answer #{traceback}")
+ end
+ end
+
+ begin
+ report("run time: #{Time.now-start_time} seconds")
+ rescue
+ end
+
+ end
+
+ def start_dialogue(address, port, processtimeout)
+ timeout(@@connecttimeout) do
+ report("trying to connect to #{address}:#{port}")
+ begin
+ begin
+ if dialogue = Net::HTTP.new(address, port) then
+ # dialogue.set_debug_output $stderr
+ dialogue.read_timeout = processtimeout # set this before start
+ if dialogue.start then
+ report("connected to #{address}:#{port}, timeout: #{processtimeout}")
+ else
+ retry
+ end
+ else
+ retry
+ end
+ rescue
+ sleep(2)
+ retry
+ else
+ return dialogue
+ end
+ rescue TimeoutError
+ return nil
+ rescue
+ return nil
+ end
+ end
+ end
+
+end
+
+logger = Logger.new(banner.shift)
+commandline = CommandLine.new
+
+commandline.registerflag('autopdf')
+
+commandline.registervalue('path' , '')
+
+commandline.registervalue('request' , 'request.exa')
+commandline.registervalue('reply' , 'reply.exa')
+commandline.registervalue('result' , 'result')
+
+commandline.registervalue('template' , '')
+commandline.registervalue('file' , '')
+commandline.registervalue('action' , '')
+commandline.registervalue('timeout' , '')
+
+commandline.registervalue('domain' , 'default')
+commandline.registervalue('project' , 'default')
+commandline.registervalue('username' , 'guest')
+commandline.registervalue('password' , 'anonymous')
+commandline.registervalue('exaurl' , 'exarequest')
+commandline.registervalue('threshold' , '0')
+commandline.registervalue('session' , '')
+
+commandline.registervalue('address' , 'localhost')
+commandline.registervalue('port' , '80')
+
+commandline.registeraction('direct' , '[--path --request --reply --result --autopdf]')
+commandline.registeraction('construct', '[--path --request --reply --result --autopdf] --file --action')
+commandline.registeraction('extend' , '[--path --request --reply --result --autopdf] --file --action --template')
+
+commandline.registeraction('direct')
+commandline.registeraction('construct')
+commandline.registeraction('extend')
+
+commandline.registerflag('verbose')
+commandline.registeraction('help')
+commandline.registeraction('version')
+
+commandline.expand
+
+Commands.new(commandline,logger,banner).send(commandline.action || 'main')
diff --git a/scripts/context/ruby/wwwserver.rb b/scripts/context/ruby/wwwserver.rb
new file mode 100644
index 000000000..aa6352183
--- /dev/null
+++ b/scripts/context/ruby/wwwserver.rb
@@ -0,0 +1,292 @@
+#!/usr/env ruby
+
+banner = ['WWWServer', 'version 1.0.0', '2003-2006', 'PRAGMA ADE/POD']
+
+$: << File.dirname(File.expand_path($0))
+
+require 'base/switch'
+require 'base/logger'
+
+require 'monitor'
+
+# class WWW < Monitor
+# end
+# class Server < Monitor
+# end
+
+require 'www/lib'
+require 'www/dir'
+require 'www/login'
+require 'www/exa'
+
+require 'tempfile'
+require 'ftools'
+require 'webrick'
+
+class Server
+
+ attr_accessor :document_root, :work_path, :logs_path, :port_number, :exa_url, :verbose, :trace, :direct
+
+ def initialize(logger)
+ @httpd = nil
+ @document_root = ''
+ @work_path = ''
+ @logs_path = ''
+ @port_number = 8061
+ @exa_url = 'http://localhost:8061'
+ @logger = logger
+ @n_of_clients = 500
+ @request_timeout = 5*60
+ @verbose = false
+ @trace = false
+ @direct = false
+ end
+
+ def report(str)
+ @logger.report(str) if @logger
+ end
+
+ def setup
+ if @document_root.empty? then
+ rootpath = File.expand_path($0)
+ @document_root = File.expand_path(File.join(File.dirname(rootpath),'..','documents'))
+ unless FileTest.directory?(@document_root) then # todo: optional
+ loop do
+ prevpath = rootpath.dup
+ rootpath = File.dirname(rootpath)
+ if prevpath == rootpath then
+ break
+ else
+ checkpath = File.join(rootpath,'documents')
+ # report("locating: #{checkpath}")
+ if FileTest.directory?(checkpath) then
+ @document_root = checkpath
+ break
+ else
+ checkpath = File.join(rootpath,'docroot/documents')
+ # report("locating: #{checkpath}")
+ if FileTest.directory?(checkpath) then
+ @document_root = checkpath
+ break
+ end
+ end
+ end
+ end
+ end
+ end
+ @document_root = File.join(Dir.pwd, 'documents') unless FileTest.directory?(@document_root)
+ unless FileTest.directory?(@document_root) then
+ report("invalid document root: #{@document_root}")
+ exit
+ else
+ report("using document root: #{@document_root}")
+ end
+ #
+ @work_path = File.expand_path(File.join(@document_root,'..','work')) if @work_path.empty?
+ # begin File.makedirs(@work_path) ; rescue ; end # no, let's auto-temp
+ if ! FileTest.directory?(@work_path) || ! FileTest.writable?(@work_path) then
+ @work_path = File.expand_path(File.join(Dir.tmpdir,'exaserver','work'))
+ begin File.makedirs(@logs_path) ; rescue ; end
+ end
+ report("using work path: #{@work_path}")
+ #
+ @logs_path = File.expand_path(File.join(@document_root,'..','logs')) if @logs_path.empty?
+ # begin File.makedirs(@logs_path) ; rescue ; end # no, let's auto-temp
+ if ! FileTest.directory?(@logs_path) || ! FileTest.writable?(@logs_path) then
+ @logs_path = File.expand_path(File.join(Dir.tmpdir,'exaserver','logs'))
+ begin File.makedirs(@logs_path) ; rescue ; end
+ end
+ report("using log path: #{@logs_path}")
+ #
+ if @logs_path.empty? then
+ @logfile = $stderr
+ @accfile = $stderr
+ else
+ @logfile = File.join(@logs_path,'exa-info.log')
+ @accfile = File.join(@logs_path,'exa-access.log')
+ begin File.delete(@logfile) ; rescue ; end
+ begin File.delete(@accfile) ; rescue ; end
+ end
+ #
+ begin
+ @httpd = WEBrick::HTTPServer.new(
+ :DocumentRoot => @document_root,
+ :DirectoryIndex => ['index.html','index.htm','showcase.pdf'],
+ :Port => @port_number.to_i,
+ :Logger => WEBrick::Log.new(@logfile, WEBrick::Log::INFO), # DEBUG
+ :RequestTimeout => @request_timeout,
+ :MaxClients => @n_of_clients,
+ :AccessLog => [
+ [ @accfile, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
+ [ @accfile, WEBrick::AccessLog::REFERER_LOG_FORMAT ],
+ [ @accfile, WEBrick::AccessLog::AGENT_LOG_FORMAT ],
+ # :CGIPathEnv => ENV["PATH"] # PATH environment variable for CGI.
+ ]
+ )
+ rescue
+ report("starting server at port: #{@port_number} failed")
+ exit
+ else
+ report("running server at port: #{@port_number}")
+ end
+
+ begin
+ #
+ @httpd.mount_proc("/dir") do |request,reply|
+ report("accepting /dir") if @verbose
+ web_session(request,reply).handle_dir
+ end
+ @httpd.mount_proc("/login") do |request,reply|
+ report("accepting /login") if @verbose
+ web_session(request,reply).handle_login
+ end
+ @httpd.mount("/cache", WEBrick::HTTPServlet::FileHandler, File.join(@work_path,'cache'))
+ # @httpd.mount_proc("/cache") do |request,reply|
+ # WEBrick::HTTPServlet::FileHandler(@httpd,@work_path) # not ok
+ # end
+ @httpd.mount_proc("/exalogin") do |request,reply|
+ report("accepting /exalogin") if @verbose
+ web_session(request,reply).handle_exalogin
+ end
+ @httpd.mount_proc("/exadefault") do |request,reply|
+ report("accepting /exadefault") if @verbose
+ web_session(request,reply).handle_exadefault
+ end
+ @httpd.mount_proc("/exainterface") do |request,reply|
+ report("accepting /exainterface") if @verbose
+ web_session(request,reply).handle_exainterface
+ end
+ @httpd.mount_proc("/exarequest") do |request,reply|
+ report("accepting /exarequest") if @verbose
+ web_session(request,reply).handle_exarequest
+ end
+ @httpd.mount_proc("/exacommand") do |request,reply|
+ report("accepting /exacommand") if @verbose
+ web_session(request,reply).handle_exacommand
+ end
+ @httpd.mount_proc("/exastatus") do |request,reply|
+ report("accepting /exastatus") if @verbose
+ web_session(request,reply).handle_exastatus
+ end
+ @httpd.mount_proc("/exaadmin") do |request,reply|
+ report("accepting /exaadmin") if @verbose
+ web_session(request,reply).handle_exaadmin
+ end
+ #
+ rescue
+ report("problem in starting server: #{$!}")
+ end
+ [:INT, :TERM, :EXIT].each do |signal|
+ trap(signal) do
+ @httpd.shutdown
+ end
+ end
+ end
+
+ def start
+ unless @httpd then
+ setup
+ @httpd.start
+ end
+ end
+
+ def stop
+ @httpd.shutdown if @httpd
+ end
+
+ def restart
+ stop
+ start
+ end
+
+ private
+
+ def web_session(request,reply)
+ www = WWW.new(@httpd,request,reply)
+ www.set('path:work', @work_path)
+ www.set('path:logs', @logs_path)
+ www.set('path:root', File.dirname(@document_root))
+ www.set('process:exaurl', @exa_url)
+ www.set('trace:errors','yes') if @trace
+ www.set('process:background', 'no') if @direct
+ return www
+ end
+
+end
+
+class Commands
+
+ include CommandBase
+
+ def start
+ if server = setup then server.start end
+ end
+
+ def stop
+ if server = setup then server.stop end
+ end
+
+ def restart
+ if server = setup then server.restart end
+ end
+
+ private
+
+ def setup
+ server = Server.new(logger)
+ server.document_root = @commandline.option('root')
+ server.verbose = @commandline.option('verbose')
+ if @commandline.option('forcetemp') then
+ server.work_path = Dir.tmpdir + '/exa/work'
+ server.logs_path = Dir.tmpdir + '/exa/logs'
+ [server.work_path,server.logs_path].each do |d|
+ begin
+ File.makedirs(d) unless FileTest.directory?(d)
+ rescue
+ report("unable to create #{d}")
+ exit
+ end
+ unless FileTest.writable?(d) then
+ report("unable to access #{d}")
+ exit
+ end
+ end
+ else
+ server.work_path = @commandline.option('work')
+ server.logs_path = @commandline.option('logs')
+ end
+ server.port_number = @commandline.option('port')
+ server.exa_url = @commandline.option('url')
+ server.trace = @commandline.option('trace')
+ server.direct = @commandline.option('direct')
+ return server
+ end
+
+end
+
+logger = Logger.new(banner.shift)
+commandline = CommandLine.new
+
+commandline.registervalue('root' , '')
+commandline.registervalue('work' , '')
+commandline.registervalue('logs' , '')
+commandline.registervalue('address', 'localhost')
+commandline.registervalue('port' , '8061')
+commandline.registervalue('url' , 'http://localhost:8061')
+
+commandline.registeraction('start' , 'start the server [--root --forcetemp --work --logs --address --port --url]')
+commandline.registeraction('stop' , 'stop the server')
+commandline.registeraction('restart', 'restart the server')
+
+commandline.registerflag('forcetemp')
+commandline.registerflag('direct')
+commandline.registerflag('verbose')
+commandline.registerflag('trace')
+
+commandline.registeraction('help')
+commandline.registeraction('version')
+
+commandline.expand
+
+Commands.new(commandline,logger,banner).send(commandline.action || 'start')
+
diff --git a/scripts/context/ruby/wwwwatch.rb b/scripts/context/ruby/wwwwatch.rb
new file mode 100644
index 000000000..1f61ef479
--- /dev/null
+++ b/scripts/context/ruby/wwwwatch.rb
@@ -0,0 +1,464 @@
+#!/usr/bin/env ruby
+
+banner = ['WWWWatch', 'version 1.0.0', '2003-2006', 'PRAGMA ADE/POD']
+
+$: << File.dirname(File.expand_path($0))
+
+require 'base/switch'
+require 'base/logger'
+
+require 'www/common'
+
+require 'monitor'
+require 'fileutils'
+require 'ftools'
+require 'tempfile'
+require 'timeout'
+require 'thread'
+
+class Watch < Monitor
+
+ include Common
+
+ @@session_prefix = ''
+ @@check_factor = 4
+ @@process_timeout = 1*60*60
+ @@fast_wait_loop = false
+
+ @@session_line = /^\s*(?![\#\%])(.*?)\s*\=\s*(.*?)\s*$/o
+ @@session_begin = 'begin exa session'
+ @@session_end = 'end exa session'
+
+ attr_accessor :root_path, :work_path, :delay, :max_threads, :max_age, :verbose
+
+ def initialize(logger) # we need to register all @vars here becase of the monitor
+ @threads = Hash.new
+ @files = Array.new
+ @stats = Hash.new
+ @skips = Hash.new
+ @root_path = ''
+ @work_path = Dir.tmpdir
+ @cache_path = @work_path
+ @last_action = Time.now
+ @delay = 1
+ @max_threads = 5
+ @max_age = @@process_timeout
+ @logger = logger
+ @verbose = false
+ [:INT, :TERM, :EXIT].each do |signal|
+ trap(signal) do
+ kill
+ exit
+ end
+ end
+ at_exit do
+ kill
+ end
+ end
+
+ def trace
+ if @verbose && @logger then
+ @logger.report("exception: #{$!})")
+ $@.each do |t|
+ @logger.report(">> #{t}")
+ end
+ end
+ end
+
+ def report(str)
+ @logger.report(str) if @logger
+ end
+
+ def setup
+ @threads = Hash.new
+ @files = Array.new
+ @stats = Hash.new
+ @skips = Hash.new
+ @root_path = File.expand_path(File.join(File.dirname($0),'..')) if @root_path.empty?
+ @work_path = File.expand_path(File.join(@root_path,'work','watch')) if @work_path.empty?
+ @cache_path = File.expand_path(File.join(@root_path,'work','cache')) if @work_path.empty?
+ begin File.makedirs(@work_path) ; rescue ; end
+ begin File.makedirs(@cache_path) ; rescue ; end
+ unless File.writable?(@work_path) then
+ @work_path = File.expand_path(File.join(Dir.tmpdir,'work','watch'))
+ begin File.makedirs(@work_path) ; rescue ; end
+ end
+ unless File.writable?(@cache_path) then
+ @cache_path = File.expand_path(File.join(Dir.tmpdir,'work','cache'))
+ begin File.makedirs(@cache_path) ; rescue ; end
+ end
+ unless File.writable?(@work_path) then
+ puts "no valid work path: #{@work_path}" ; exit
+ end
+ unless File.writable?(@cache_path) then
+ puts "no valid work path: #{@work_path}" ; # no reason to exit
+ end
+ @last_action = Time.now
+ report("watching path #{@work_path}") if @verbose
+ end
+
+ def lock(lck)
+ begin
+ report("watchdog: locking #{lck}") if @verbose
+ File.open(lck,'w') do |f|
+ f << Time.now
+ end
+ rescue
+ trace
+ end
+ end
+
+ def unlock(lck)
+ begin
+ report("watchdog: unlocking #{lck}") if @verbose
+ File.delete(lck)
+ rescue
+ trace
+ end
+ end
+
+ def kill
+ @threads.each do |t|
+ t.kill rescue false
+ end
+ end
+
+ def restart
+ @files = Array.new
+ @skips = Hash.new
+ @stats = Hash.new
+ kill # threads
+ end
+
+ def collect
+ begin
+ @files = Array.new
+ Dir.glob("#{@work_path}/#{@@session_prefix}*.ses").each do |sessionfile|
+ sessionfile = File.expand_path(sessionfile)
+ begin
+ if @threads.key?(sessionfile) then
+ # leave alone
+ elsif (Time.now - File.mtime(sessionfile)) > @max_age.to_i then
+ # delete
+ FileUtils::rm_r(sessionfile) rescue false
+ FileUtils::rm_r(sessionfile.sub(/ses$/,'dir')) rescue false
+ FileUtils::rm_r(sessionfile.sub(/ses$/,'lck')) rescue false
+ begin
+ FileUtils::rm_r(File.join(@cache_path, File.basename(sessionfile.sub(/ses$/,'dir'))))
+ rescue
+ report("watchdog: problems in cache cleanup #{$!}") # if @verbose
+ end
+ @stats.delete(sessionfile) rescue false
+ @skips.delete(sessionfile) rescue false
+ report("watchdog: removing session #{sessionfile}") if @verbose
+ elsif ! @skips.key?(sessionfile) then
+ @files << sessionfile
+ report("watchdog: checking session #{sessionfile}") if @verbose
+ end
+ rescue
+ # maybe purged in the meantime
+ end
+ end
+ rescue
+ if File.directory?(@work_path) then
+ @files = Array.new
+ else
+ # maybe dir is deleted (manual cleanup)
+ restart
+ end
+ end
+ begin
+ Dir.glob("#{@cache_path}/*.dir").each do |dirname|
+ begin
+ if (Time.now - File.mtime(dirname)) > @max_age.to_i then
+ begin
+ FileUtils::rm_r(dirname)
+ rescue
+ report("watchdog: problems in cache cleanup #{$!}") # if @verbose
+ end
+ end
+ rescue
+ # maybe purged in the meantime
+ end
+ end
+ rescue
+ end
+ end
+
+ def purge
+ begin
+ Dir.glob("#{@work_path}/#{@@session_prefix}*").each do |sessionfile|
+ sessionfile = File.expand_path(sessionfile)
+ begin
+ if (Time.now - File.mtime(sessionfile)) > @max_age.to_i then
+ begin
+ if FileTest.directory?(sessionfile) then
+ FileUtils::rm_r(sessionfile)
+ else
+ File.delete(sessionfile)
+ end
+ rescue
+ end
+ begin
+ @stats.delete(sessionfile)
+ @skips.delete(sessionfile)
+ rescue
+ end
+ report("watchdog: purging session #{sessionfile}") if @verbose
+ end
+ rescue
+ # maybe purged in the meantime
+ end
+ end
+ rescue
+ end
+ end
+
+ def loaded_session_data(filename)
+ begin
+ if data = IO.readlines(filename) then
+ return data if (data.first =~ /^[\#\%]\s*#{@@session_begin}/o) && (data.last =~ /^[\#\%]\s*#{@@session_end}/o)
+ end
+ rescue
+ trace
+ end
+ return nil
+ end
+
+ def load(sessionfile)
+ # we assume that we get an exception when the file is locked
+ begin
+ if data = loaded_session_data(sessionfile) then
+ report("watchdog: loading session #{sessionfile}") if @verbose
+ vars = Hash.new
+ data.each do |line|
+ begin
+ if line.chomp =~ /^(.*?)\s*\=\s*(.*?)\s*$/o then
+ key, value = $1, $2
+ vars[key] = value
+ end
+ rescue
+ end
+ end
+ return vars
+ else
+ return nil
+ end
+ rescue
+ trace
+ return nil
+ end
+ end
+
+ def save(sessionfile, vars)
+ begin
+ report("watchdog: saving session #{sessionfile}") if @verbose
+ if @stats.key?(sessionfile) then
+ @stats[sessionfile] = File.mtime(sessionfile)
+ elsif @stats[sessionfile] == File.mtime(sessionfile) then
+ else
+ # construct data first
+ str = "\# #{@@session_begin}\n"
+ for k,v in vars do
+ str << "#{k}=#{v}\n"
+ end
+ str << "\# #{@@session_end}\n"
+ # save as fast as possible
+ File.open(sessionfile,'w') do |f|
+ f.puts(str)
+ end
+ end
+ rescue
+ report("watchdog: unable to save session #{sessionfile}") if @verbose
+ trace
+ return false
+ else
+ return true
+ end
+ end
+
+ def launch
+ begin
+ @files.each do |sessionfile|
+ if @threads.length < @max_threads then
+ begin
+ if ! @skips.key?(sessionfile) && (vars = load(sessionfile)) then
+ if (id = vars['id']) && vars['status'] then
+ if vars['status'] == 'running: background' then
+ @last_action = Time.now
+ @threads[sessionfile] = Thread.new(vars, sessionfile) do |vars, sessionfile|
+ begin
+ report("watchdog: starting thread #{sessionfile}") if @verbose
+ dir = File.expand_path(sessionfile.sub(/ses$/,'dir'))
+ lck = File.expand_path(sessionfile.sub(/ses$/,'lck'))
+ start_of_run = Time.now
+ start_of_job = start_of_run.dup
+ max_runtime = @max_age
+ begin
+ start_of_job = vars['starttime'].to_i || start_of_run
+ start_of_job = start_of_run if start_of_job == 0
+ rescue
+ start_of_job = Time.now
+ end
+ begin
+ max_runtime = vars['maxtime'].to_i || @max_age
+ max_runtime = @max_age if max_runtime == 0
+ max_runtime = max_runtime - (Time.now.to_i - start_of_job.to_i)
+ rescue
+ max_runtime = @max_age
+ end
+ lock(lck)
+ if max_runtime > 0 then
+ command = vars['command'] || ''
+ if ! command.empty? then
+ vars['status'] = 'running: busy'
+ vars['timeout'] = max_runtime.to_s
+ save(sessionfile,vars)
+ timeout(max_runtime) do
+ begin
+ command = command_string(dir,command,'process.log')
+ report("watchdog: #{command}") if @verbose
+ system(command)
+ rescue TimeoutError
+ vars['status'] = 'running: timeout'
+ rescue
+ trace
+ vars['status'] = 'running: aborted'
+ else
+ vars['status'] = 'running: finished'
+ vars['runtime'] = sprintf("%.02f",(Time.now - start_of_run))
+ vars['endtime'] = Time.now.to_i.to_s
+ end
+ end
+ else
+ vars['status'] = 'running: aborted' # no command
+ end
+ else
+ vars['status'] = 'running: aborted' # not enough time
+ end
+ save(sessionfile,vars)
+ unlock(lck)
+ report("watchdog: ending thread #{sessionfile}") if @verbose
+ @threads.delete(sessionfile)
+ rescue
+ trace
+ end
+ end
+ else
+ report("watchdog: skipping - id (#{vars['id']}) / status (#{vars['status']})") if @verbose
+ end
+ @skips[sessionfile] = true
+ else
+ # not yet ok
+ end
+ else
+ # maybe a lock
+ end
+ rescue
+ trace
+ end
+ else
+ break
+ end
+ end
+ rescue
+ trace
+ end
+ end
+
+ def wait
+ begin
+ # report(Time.now.to_s) if @verbose
+ loop do
+ if @threads.length == @max_threads then
+ if @delay > @max_threads then
+ sleep(@delay)
+ else
+ sleep(@max_threads)
+ end
+ break if @@fast_wait_loop
+ else
+ sleep(@delay)
+ break
+ end
+ end
+ rescue
+ trace
+ end
+ end
+
+ def check
+ begin
+ time = Time.now
+ if (time - @last_action) > @@check_factor*@max_age then
+ report("watchdog: cleanup") if @verbose
+ @stats = Hash.new
+ @last_action = time
+ kill
+ end
+ rescue
+ trace
+ end
+ end
+
+ def cycle
+ loop do
+ begin
+ collect
+ launch
+ wait
+ check
+ rescue
+ trace
+ report("watchdog: some problem, restarting loop")
+ end
+ end
+ end
+
+end
+
+class Commands
+
+ include CommandBase
+
+ def watch
+ if watch = setup then watch.cycle end
+ end
+ def main
+ watch
+ end
+
+ private
+
+ def setup
+ watch = Watch.new(logger)
+ watch.root_path = @commandline.option('root')
+ watch.work_path = @commandline.option('work')
+ watch.verbose = @commandline.option('verbose')
+ begin
+ watch.max_threads = @commandline.option('threads').to_i
+ rescue
+ watch.max_threads = 5
+ end
+ watch.setup
+ return watch
+ end
+
+end
+
+logger = Logger.new(banner.shift)
+commandline = CommandLine.new
+
+commandline.registervalue('root' , '')
+commandline.registervalue('work' , '')
+commandline.registervalue('threads' , '5')
+
+commandline.registeraction('watch', '[--work=path] [--root=path]')
+
+commandline.registerflag('verbose')
+commandline.registeraction('help')
+commandline.registeraction('version')
+
+commandline.expand
+
+Commands.new(commandline,logger,banner).send(commandline.action || 'main')
diff --git a/scripts/context/stubs/mswin/texmfstart.bat b/scripts/context/stubs/mswin/texmfstart.bat
deleted file mode 100755
index 287f9c4fa..000000000
--- a/scripts/context/stubs/mswin/texmfstart.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-ruby c:\data\develop\context/ruby/texmfstart.rb %*
diff --git a/scripts/context/stubs/unix/ctxtools b/scripts/context/stubs/unix/ctxtools
new file mode 100755
index 000000000..5a6a1feb5
--- /dev/null
+++ b/scripts/context/stubs/unix/ctxtools
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart ctxtools.rb $@
diff --git a/scripts/context/stubs/unix/ctxtools.bat b/scripts/context/stubs/unix/ctxtools.bat
deleted file mode 100755
index f1f5e019e..000000000
--- a/scripts/context/stubs/unix/ctxtools.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart ctxtools.rb %*
diff --git a/scripts/context/stubs/unix/exatools b/scripts/context/stubs/unix/exatools
new file mode 100755
index 000000000..cededbb57
--- /dev/null
+++ b/scripts/context/stubs/unix/exatools
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart exatools.rb $@
diff --git a/scripts/context/stubs/unix/exatools.bat b/scripts/context/stubs/unix/exatools.bat
deleted file mode 100755
index 57f798e82..000000000
--- a/scripts/context/stubs/unix/exatools.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart exatools.rb %*
diff --git a/scripts/context/stubs/unix/makempy b/scripts/context/stubs/unix/makempy
new file mode 100755
index 000000000..c30a261f0
--- /dev/null
+++ b/scripts/context/stubs/unix/makempy
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart makempy.pl $@
diff --git a/scripts/context/stubs/unix/makempy.bat b/scripts/context/stubs/unix/makempy.bat
deleted file mode 100755
index e339058c6..000000000
--- a/scripts/context/stubs/unix/makempy.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart makempy.pl %*
diff --git a/scripts/context/stubs/unix/mpstools b/scripts/context/stubs/unix/mpstools
new file mode 100755
index 000000000..68fd485bc
--- /dev/null
+++ b/scripts/context/stubs/unix/mpstools
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart mpstools.rb $@
diff --git a/scripts/context/stubs/unix/mpstools.bat b/scripts/context/stubs/unix/mpstools.bat
deleted file mode 100755
index df1732e17..000000000
--- a/scripts/context/stubs/unix/mpstools.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart mpstools.rb %*
diff --git a/scripts/context/stubs/unix/mptopdf b/scripts/context/stubs/unix/mptopdf
new file mode 100755
index 000000000..a29448782
--- /dev/null
+++ b/scripts/context/stubs/unix/mptopdf
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart mptopdf.pl $@
diff --git a/scripts/context/stubs/unix/mptopdf.bat b/scripts/context/stubs/unix/mptopdf.bat
deleted file mode 100755
index 242854337..000000000
--- a/scripts/context/stubs/unix/mptopdf.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart mptopdf.pl %*
diff --git a/scripts/context/stubs/unix/pdftools b/scripts/context/stubs/unix/pdftools
new file mode 100755
index 000000000..fc6b9e864
--- /dev/null
+++ b/scripts/context/stubs/unix/pdftools
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart pdftools.rb $@
diff --git a/scripts/context/stubs/unix/pdftools.bat b/scripts/context/stubs/unix/pdftools.bat
deleted file mode 100755
index adc48eacf..000000000
--- a/scripts/context/stubs/unix/pdftools.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart pdftools.rb %*
diff --git a/scripts/context/stubs/unix/pstopdf b/scripts/context/stubs/unix/pstopdf
new file mode 100755
index 000000000..e1f0375e5
--- /dev/null
+++ b/scripts/context/stubs/unix/pstopdf
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart pstopdf.rb $@
diff --git a/scripts/context/stubs/unix/pstopdf.bat b/scripts/context/stubs/unix/pstopdf.bat
deleted file mode 100755
index 248e34caf..000000000
--- a/scripts/context/stubs/unix/pstopdf.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart pstopdf.rb %*
diff --git a/scripts/context/stubs/unix/runtools b/scripts/context/stubs/unix/runtools
new file mode 100755
index 000000000..3e4e2c505
--- /dev/null
+++ b/scripts/context/stubs/unix/runtools
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart runtools.rb $@
diff --git a/scripts/context/stubs/unix/runtools.bat b/scripts/context/stubs/unix/runtools.bat
deleted file mode 100755
index 68a7b4f97..000000000
--- a/scripts/context/stubs/unix/runtools.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart runtools.rb %*
diff --git a/scripts/context/stubs/unix/texexec b/scripts/context/stubs/unix/texexec
new file mode 100755
index 000000000..a8e297307
--- /dev/null
+++ b/scripts/context/stubs/unix/texexec
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart texexec.rb $@
diff --git a/scripts/context/stubs/unix/texexec.bat b/scripts/context/stubs/unix/texexec.bat
deleted file mode 100755
index 02b297b9c..000000000
--- a/scripts/context/stubs/unix/texexec.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart texexec.rb %*
diff --git a/scripts/context/stubs/unix/texfont b/scripts/context/stubs/unix/texfont
new file mode 100755
index 000000000..ec1bd57d5
--- /dev/null
+++ b/scripts/context/stubs/unix/texfont
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart texfont.pl $@
diff --git a/scripts/context/stubs/unix/texfont.bat b/scripts/context/stubs/unix/texfont.bat
deleted file mode 100755
index 3134bf14c..000000000
--- a/scripts/context/stubs/unix/texfont.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart texfont.pl %*
diff --git a/scripts/context/stubs/unix/texmfstart.bat b/scripts/context/stubs/unix/texmfstart.bat
deleted file mode 100755
index 287f9c4fa..000000000
--- a/scripts/context/stubs/unix/texmfstart.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-ruby c:\data\develop\context/ruby/texmfstart.rb %*
diff --git a/scripts/context/stubs/unix/textools b/scripts/context/stubs/unix/textools
new file mode 100755
index 000000000..5078ebce0
--- /dev/null
+++ b/scripts/context/stubs/unix/textools
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart textools.rb $@
diff --git a/scripts/context/stubs/unix/textools.bat b/scripts/context/stubs/unix/textools.bat
deleted file mode 100755
index 727b4a36d..000000000
--- a/scripts/context/stubs/unix/textools.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart textools.rb %*
diff --git a/scripts/context/stubs/unix/texutil b/scripts/context/stubs/unix/texutil
new file mode 100755
index 000000000..773176da5
--- /dev/null
+++ b/scripts/context/stubs/unix/texutil
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart texutil.rb $@
diff --git a/scripts/context/stubs/unix/texutil.bat b/scripts/context/stubs/unix/texutil.bat
deleted file mode 100755
index 1e63639bb..000000000
--- a/scripts/context/stubs/unix/texutil.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart texutil.rb %*
diff --git a/scripts/context/stubs/unix/tmftools b/scripts/context/stubs/unix/tmftools
new file mode 100755
index 000000000..9b52a5e53
--- /dev/null
+++ b/scripts/context/stubs/unix/tmftools
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart tmftools.rb $@
diff --git a/scripts/context/stubs/unix/tmftools.bat b/scripts/context/stubs/unix/tmftools.bat
deleted file mode 100755
index c9c0c08bd..000000000
--- a/scripts/context/stubs/unix/tmftools.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart tmftools.rb %*
diff --git a/scripts/context/stubs/unix/xmltools b/scripts/context/stubs/unix/xmltools
new file mode 100755
index 000000000..7e8c174ca
--- /dev/null
+++ b/scripts/context/stubs/unix/xmltools
@@ -0,0 +1,2 @@
+#!/bin/sh
+texmfstart xmltools.rb $@
diff --git a/scripts/context/stubs/unix/xmltools.bat b/scripts/context/stubs/unix/xmltools.bat
deleted file mode 100755
index 2de0e4457..000000000
--- a/scripts/context/stubs/unix/xmltools.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart xmltools.rb %*
diff --git a/tex/context/base/cont-new.tex b/tex/context/base/cont-new.tex
index e8ca518a3..64d27e992 100644
--- a/tex/context/base/cont-new.tex
+++ b/tex/context/base/cont-new.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2006.05.08 12:59}
+\newcontextversion{2006.05.10 23:26}
%D This file is loaded at runtime, thereby providing an
%D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/context.tex b/tex/context/base/context.tex
index e2e646813..953c7e5f5 100644
--- a/tex/context/base/context.tex
+++ b/tex/context/base/context.tex
@@ -31,7 +31,7 @@
%D 2004.8.30 the low level interface is english. Watch out and adapt
%D your styles an modules.
-\def\contextversion{2006.05.08 12:59}
+\def\contextversion{2006.05.10 23:26}
%D For those who want to use this:
diff --git a/tex/context/base/core-job.tex b/tex/context/base/core-job.tex
index 5e129caae..794af85c3 100644
--- a/tex/context/base/core-job.tex
+++ b/tex/context/base/core-job.tex
@@ -348,13 +348,21 @@
% \expandafter\endinput
% \fi}
-\let\currentcomponent\v!text
+\let\currentcomponent \v!text
+\let\currentcomponentpath\f!currentpath
\def\donextlevel#1#2#3#4#5#6#7\\%
{\pushmacro\currentcomponent
+ \pushmacro\currentcomponentpath
\let\currentcomponent#1%
\setsystemmode\currentcomponent
- \beforesplitstring#7\at.\to#2\relax
+ \splitfilename{#1}%
+ \ifx\splitoffpath\empty
+ \let\currentcomponentpath\f!currentpath
+ \else
+ \let\currentcomponentpath\splitoffpath
+ \fi
+ \beforesplitstring#7\at.\to#2\relax % can become path + base
\ifcase\filelevel\relax
\starttext
\def\project ##1 {#3{##1}}%
@@ -366,7 +374,8 @@
\fullexpandoneargafter\addtocommalist{#1}\loadedfiles}
\def\doprevlevel
- {\popmacro\currentcomponent
+ {\popmacro\currentcomponentpath
+ \popmacro\currentcomponent
\setsystemmode\currentcomponent
\ifnum\filelevel=\plusone
\expandafter\stoptext
diff --git a/tex/context/base/core-mat.tex b/tex/context/base/core-mat.tex
index c3edf584e..298803bd0 100644
--- a/tex/context/base/core-mat.tex
+++ b/tex/context/base/core-mat.tex
@@ -158,6 +158,7 @@
\edef\hetsubnummer{#4}%
\fi
\doifsomething{#3}{\rawreference\s!for{#3}{\composedsectionnumber\hetsubnummer}}%
+ \doflushformulalistentry{\composedsectionnumber\hetsubnummer}%
\rm % nodig ?
\doif{\formulaparameter\c!location}\v!right{\hskip\formuladistance}%
\@@fmnumbercommand
@@ -567,6 +568,40 @@
{\setfalse\incrementformulanumber
\dodoubleempty\doplaceformula}
+%D Experimental goodie:
+%D
+%D \startbuffer
+%D \placelist[formula][criterium=text] \blank[2*big]
+%D \placenamedformula[one]{first} \startformula a = 1 \stopformula \endgraf
+%D \placeformula \startformula a = 2 \stopformula \endgraf
+%D \placenamedformula {second} \startformula a = 3 \stopformula \endgraf
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\definelist[\v!formula]
+
+\global\let\doflushformulalistentry\gobbleoneargument
+
+\def\setformulalistentry#1%
+ {\gdef\doflushformulalistentry##1%
+ {\expanded{\writetolist[\v!formula]{##1}}{#1}%
+ \global\let\doflushformulalistentry\gobbleoneargument}}
+
+\def\placenamedformula
+ {\dosingleempty\doplacenamedformula}
+
+\def\doplacenamedformula[#1]#2%
+ {\iffirstargument
+ \def\next{\placeformula[#1]}%
+ \else
+ \let\next\placeformula
+ \fi
+ \setformulalistentry{#2}%
+ \next}
+
+%D The implementation of placement is a bit ugly:
+
% \def\doplaceformula[#1][#2]% #2 = dummy, gobbles spaces
% {\def\redoplaceformula
% {\bgroup\def\dostartformula####1{\relax}%
diff --git a/tex/context/base/core-uti.tex b/tex/context/base/core-uti.tex
index a6e2af819..680de0f7a 100644
--- a/tex/context/base/core-uti.tex
+++ b/tex/context/base/core-uti.tex
@@ -106,7 +106,11 @@
\let\checkedutility\docheckedutility
\to \everybeforeshipout
-\edef\testbytesequence{\rawcharacter{7}\rawcharacter{27}\rawcharacter{227}}
+\edef\testbytesequence
+ {\rawcharacter{7}%
+ \rawcharacter{27}%
+ %rawcharacter{227}% invalid in xetex, which expects utf
+ \rawcharacter{195}\rawcharacter{128}} % valid utf code
\def\thisisbytesequence#1%
{\ifx\testbytesequence\empty\else
@@ -118,6 +122,10 @@
\fi
\global\let\thisisbytesequence\gobbleoneargument}
+\beginXETEX
+ \let\testbytesequence\empty
+\endXETEX
+
% Better use marks.
\def\checkutilities
diff --git a/tex/context/base/core-ver.tex b/tex/context/base/core-ver.tex
index 595ba075e..55646f053 100644
--- a/tex/context/base/core-ver.tex
+++ b/tex/context/base/core-ver.tex
@@ -1306,7 +1306,8 @@
\doiflocfileelse{#3}
\donetrue % sets \readfilename
{\doifinputfileelse{#3}
- {\donetrue\let\readfilename\filepath}
+ {\donetrue
+ \def\readfilename{\pathplusfile\filepath{#3}}}
\donefalse}%
\ifdone
\startpacked % includes \bgroup
@@ -1318,7 +1319,6 @@
\settypingparameter\c!option{\prettyidentifier}}%
\initializetyping
\startverbatimcolor
- \makelocreadfilename{#3}%
\doifundefinedelse{\currenttypingclass#3\v!global\c!start}
{\scratchcounter\zerocount}
{\scratchcounter\getvalue{\currenttypingclass#3\v!global\c!start}}%
diff --git a/tex/context/base/enco-ini.tex b/tex/context/base/enco-ini.tex
index be1cd966c..9139aae75 100644
--- a/tex/context/base/enco-ini.tex
+++ b/tex/context/base/enco-ini.tex
@@ -1143,8 +1143,7 @@
\else
\enablepatterntokens
\fi
-\let\dochar\thechr
-% \enableregime[utf]%
+ \let\dochar\thechr
\lccode16=16 % brrr, extra quote in ec (turkish)
\lccode17=17 % brrr, extra quote in ec (turkish)
\lccode`\-=`\-
diff --git a/tex/context/base/lang-ini.tex b/tex/context/base/lang-ini.tex
index 9a6d62124..6bfdabcef 100644
--- a/tex/context/base/lang-ini.tex
+++ b/tex/context/base/lang-ini.tex
@@ -339,31 +339,23 @@
\dodoloadpatterns{#1}{#2}{}{}%
\fi}
+\def\setuphyppatencoding
+ {\pathypsettings
+ \enableregime[utf]}
+
+\beginXETEX
+ \def\setuphyppatencoding
+ {\pathypsettings}
+\endXETEX
+
\def\dodoloadpatterns#1#2#3#4% beware, loaded language also incr
{\normallanguage\loadedlanguage % when not really needed
\bgroup
- % \startencoding[#3]%
- % \enablemapping[#4]% hm, does a sync patterns
- % \doifnothing\currentencoding{\let\currentencoding\s!default}%
- % \doifnothing\currentmapping {\let\currentmapping \s!default}%
- % better:
\let\synchronizepatterns\relax % needed?
\let\enabledmapping \empty % needed?
- % old (original) patterns
-% \let\dochar\thechr
-\pathypsettings
-\enableregime[utf]% just in case (xetex)
\doifelsenothing{#3}{\enableencoding[\s!default]}{\enableencoding[#3]}%
\doifelsenothing{#4}{\enablemapping [\s!default]}{\enablemapping [#4]}%
-% \iftrue
-% \dostepwiserecurse{0}{255}{1}
-% {\ifnum\lccode\recurselevel>0
-% \writestatus{lccodes}{#4: \recurselevel: \the\lccode\recurselevel}%
-% \fi}
-% \fi
- % new patterns
- % \enableregime[utf]%
- %
+ \setuphyppatencoding
\ifundefined{\??la\??la:\currentencoding:\currentmapping:#2}%
\let\doshowpatterns\relax
\edef\alreadyloadedlanguage
diff --git a/tex/context/base/meta-fig.tex b/tex/context/base/meta-fig.tex
index 638166860..6d4d304f9 100644
--- a/tex/context/base/meta-fig.tex
+++ b/tex/context/base/meta-fig.tex
@@ -49,26 +49,11 @@
\def\startMPpage
{\dodoubleempty\dostartMPpage}
-% \long\def\dostartMPpage[#1][#2]#3\stopMPpage % second arg gobbles space
-% {\dostartfittingpage[\??mg][#1]%
-% \startMPcode#3\stopMPcode
-% \dostopfittingpage}
-
\long\def\dostartMPpage[#1][#2]% second arg gobbles space
{\dostartfittingpage[\??mg][#1]%
- \obeylines\def\obeyedline{\rawcharacter{13}}%
+ \obeyMPlines
\dodostartMPpage}
-% \long\def\dodostartMPpage#1\stopMPpage
-% {\startMPcode#1\stopMPcode
-% \dostopfittingpage}
-%
-% more efficient:
-
-\long\def\obeyMPlines
- {\obeylines
- \def\obeyedline{\rawcharacter{13}}}
-
\long\def\dodostartMPpage#1\stopMPpage
{\startuseMPgraphic{@@}#1\stopuseMPgraphic
\useMPgraphic{@@}%
diff --git a/tex/context/base/regi-utf.tex b/tex/context/base/regi-utf.tex
index fe7b0b958..da89eedec 100644
--- a/tex/context/base/regi-utf.tex
+++ b/tex/context/base/regi-utf.tex
@@ -33,6 +33,10 @@
\expandafter \endinput
\endTEX
+\beginXETEX
+ \expandafter \endinput
+\endXETEX
+
\unprotect
% beware, this may change: \utftwouniglyph rawchar
diff --git a/tex/context/base/rlxtools.rlx b/tex/context/base/rlxtools.rlx
index 308d533d5..2c5c3c6ce 100644
--- a/tex/context/base/rlxtools.rlx
+++ b/tex/context/base/rlxtools.rlx
@@ -78,4 +78,15 @@
</rl:step>
</rl:manipulator>
+ <rl:manipulator name='pdf' suffix='gif'>
+ <rl:old><rl:value name='path'/>/<rl:value name='file' method='nosuffix'/>.gif</rl:old>
+ <rl:new><rl:value name='cache' default='.'/>/<rl:value name='file' method='nosuffix'/>.pdf</rl:new>
+ <rl:step>
+ texmfstart pstopdf --convert
+ --inputpath=<rl:value name='path'/>
+ --outputpath=<rl:value name='cache' default='.'/>
+ <rl:value name='file' method='nosuffix'/>.gif
+ </rl:step>
+ </rl:manipulator>
+
</rl:manipulators>
diff --git a/tex/context/base/spec-tpd.tex b/tex/context/base/spec-tpd.tex
index dcf803f7b..acd836370 100644
--- a/tex/context/base/spec-tpd.tex
+++ b/tex/context/base/spec-tpd.tex
@@ -306,7 +306,12 @@
\definefileinsertion{tpd}{pdf}{\handlepdfimage}
\definefileinsertion{tpd}{png}{\handlepdfimage}
\definefileinsertion{tpd}{jpg}{\handlepdfimage}
-%definefileinsertion{tpd}{tif}{\handlepdfimage} % unstable
+\definefileinsertion{tpd}{jb2}{\handlepdfimage}
+
+% \definefileinsertion{tpd}{jpeg} {\handlepdfimage}
+% \definefileinsertion{tpd}{jbig2}{\handlepdfimage}
+
+%definefileinsertion{tpd}{tif}{\handlepdfimage} % unstable and gone
%D Experimental:
diff --git a/tex/context/base/supp-fil.tex b/tex/context/base/supp-fil.tex
index 63e2f3730..da4b595b8 100644
--- a/tex/context/base/supp-fil.tex
+++ b/tex/context/base/supp-fil.tex
@@ -509,7 +509,7 @@
{\sanitizefilename#1\to\readfilename
\checkfilename\readfilename
\ifcase\kindoffile
- \edef\locreadfilename{\pathplusfile\f!currentpath{#1}}%
+ \edef\readfilename{\pathplusfile\f!currentpath{#1}}%
\fi}
%D \macros
diff --git a/tex/context/base/supp-mps.tex b/tex/context/base/supp-mps.tex
index 82a5dcb7b..0b11ef592 100644
--- a/tex/context/base/supp-mps.tex
+++ b/tex/context/base/supp-mps.tex
@@ -1085,7 +1085,8 @@
\def\MPOSTbatchswitch {-int=batchmode}
\def\MPOSTnonstopswitch {-int=nonstopmode}
- \def\MPOSTformatswitch {-progname=mpost -mem=}
+% \def\MPOSTformatswitch {-progname=mpost -mem=}
+ \def\MPOSTformatswitch {-mem=}
\def\MPOSTdriver {dvips}
\def\executeMPOST#1% direct call
@@ -1935,4 +1936,11 @@
\let\stopMPcode \relax % so that we can use it in \expanded
+%D Special for \XETEX\ (problem with newlines):
+
+\beginXETEX
+ \let\obeyMPlines\relax
+ \longMPlinesfalse % alas
+\endXETEX
+
\protect \endinput
diff --git a/tex/context/base/syst-ext.tex b/tex/context/base/syst-ext.tex
index b9183a9e8..40dfc27ec 100644
--- a/tex/context/base/syst-ext.tex
+++ b/tex/context/base/syst-ext.tex
@@ -2588,7 +2588,7 @@
%D A first application of the two routines defined above is:
%D
%D \starttyping
-%D \removesubstringtest-\from first-last\to\nothyphenated
+%D \removesubstring-\from first-last\to\nothyphenated
%D \stoptyping
%D
%D Which in terms of \TEX\ looks like:
diff --git a/tex/context/base/syst-xtx.tex b/tex/context/base/syst-xtx.tex
index 7466725c7..af6d6e8df 100644
--- a/tex/context/base/syst-xtx.tex
+++ b/tex/context/base/syst-xtx.tex
@@ -24,10 +24,19 @@
\immediate\openin\scratchread=xplain.tex \ifeof\scratchread
% no initialization file
\else
- \input xplain.tex
+ \input xplain.tex\relax
\fi
\else
- \input unicode-letters.tex
+ \input unicode-letters.tex\relax
+ % begin of patch (turkish patterns need this)
+ \begingroup
+ \catcode`\{=1 \catcode`\}=2 \catcode`\#=6
+ \def\C #1 #2 #3 {\global\uccode"#1="#2 \global\lccode"#1="#3 } % case mappings (non-letter)
+ \def\L #1 #2 #3 {\global\catcode"#1=11 \C #1 #2 #3 } % letter with case mappings
+ \L 201C 201C 201C
+ \L 201D 201D 201D
+ \endgroup
+ % end of patch
\fi
\protect \endinput
diff --git a/tex/context/base/xtag-xsl.tex b/tex/context/base/xtag-xsl.tex
index 4d844c8e1..7981524d1 100644
--- a/tex/context/base/xtag-xsl.tex
+++ b/tex/context/base/xtag-xsl.tex
@@ -106,7 +106,7 @@
\doifundefined{\??xl#1}%
{\writestatus{XSLT}{unknown script #1}}
{\writestatus{XSLT}{convert #2 into #3 using #1}%
- \edef\par{\rawcharacter{13}}%
+ \edef\par{\rawcharacter{10}}%
\edef\!!stringc{\getvalue{\??xl#1}}%
\immediate\openout\scratchwrite=\XSLTscriptfile.xsl
\immediate\write\scratchwrite{\!!stringc}%
diff --git a/tex/context/interface/keys-cz.xml b/tex/context/interface/keys-cz.xml
index e77af536e..e191d8162 100644
--- a/tex/context/interface/keys-cz.xml
+++ b/tex/context/interface/keys-cz.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
-<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="cz" version="2006.04.27 15:59">
+<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="cz" version="2006.05.10 23:26">
<cd:variables>
<cd:variable name="one" value="jedna"/>
diff --git a/tex/context/interface/keys-de.xml b/tex/context/interface/keys-de.xml
index 0e7154545..01f4f2e9b 100644
--- a/tex/context/interface/keys-de.xml
+++ b/tex/context/interface/keys-de.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
-<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="de" version="2006.04.27 15:59">
+<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="de" version="2006.05.10 23:26">
<cd:variables>
<cd:variable name="one" value="eins"/>
diff --git a/tex/context/interface/keys-en.xml b/tex/context/interface/keys-en.xml
index 478b43a6f..9dc7275e5 100644
--- a/tex/context/interface/keys-en.xml
+++ b/tex/context/interface/keys-en.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
-<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="en" version="2006.04.27 15:59">
+<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="en" version="2006.05.10 23:26">
<cd:variables>
<cd:variable name="one" value="one"/>
diff --git a/tex/context/interface/keys-fr.xml b/tex/context/interface/keys-fr.xml
index 7d60c593f..7bb9d5a1d 100644
--- a/tex/context/interface/keys-fr.xml
+++ b/tex/context/interface/keys-fr.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
-<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="fr" version="2006.04.27 15:59">
+<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="fr" version="2006.05.10 23:26">
<cd:variables>
<cd:variable name="one" value="un"/>
diff --git a/tex/context/interface/keys-it.xml b/tex/context/interface/keys-it.xml
index 20b2b2525..53302e793 100644
--- a/tex/context/interface/keys-it.xml
+++ b/tex/context/interface/keys-it.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
-<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="it" version="2006.04.27 15:59">
+<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="it" version="2006.05.10 23:26">
<cd:variables>
<cd:variable name="one" value="uno"/>
diff --git a/tex/context/interface/keys-nl.xml b/tex/context/interface/keys-nl.xml
index 2f808b4ea..81c09e56c 100644
--- a/tex/context/interface/keys-nl.xml
+++ b/tex/context/interface/keys-nl.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
-<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="nl" version="2006.04.27 15:59">
+<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="nl" version="2006.05.10 23:26">
<cd:variables>
<cd:variable name="one" value="een"/>
diff --git a/tex/context/interface/keys-ro.xml b/tex/context/interface/keys-ro.xml
index 012f83036..cd9f2eb03 100644
--- a/tex/context/interface/keys-ro.xml
+++ b/tex/context/interface/keys-ro.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
-<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="ro" version="2006.04.27 15:59">
+<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="ro" version="2006.05.10 23:26">
<cd:variables>
<cd:variable name="one" value="unu"/>
diff --git a/tex/context/patterns/lang-de.pat b/tex/context/patterns/lang-de.pat
index 2b98f67ea..0a31dac79 100644
--- a/tex/context/patterns/lang-de.pat
+++ b/tex/context/patterns/lang-de.pat
@@ -1672,6 +1672,4170 @@ fä1c
8färm
6fäug
fä8ß
+föde3
+8föf
+3för
+1fü
+fün4f3u
+1ga
+ga6bl
+6gabw
+8gabz
+g3a4der
+ga8ho
+ga5isc
+4gak
+ga1la
+6g5amt
+ga1na
+gan5erb
+gan6g5a
+ga5nj
+6ganl
+8gansc
+6garb
+2g1arc
+2g1arm
+ga5ro
+6g3arti
+ga8sa
+ga8sc
+ga6stre
+2g1atm
+6g5auf
+gau5fr
+g5aus
+2g1b
+g5c
+6gd
+g1da
+1ge
+ge1a2
+ge6an
+ge8at.
+ge1e2
+ge6es
+gef2
+8geff
+ge1g2l
+ge1im
+4g3eise
+geist5r
+gel8bra
+gelt8s
+ge5lö
+ge8nin
+gen3k
+6g5entf
+ge3nä
+ge1or
+ge1ra
+ge6rab
+ger8au
+8gerhö
+ger8ins
+ge1ro
+6g5erz.
+ge1rä
+ge1rü
+ge1s
+ges2p
+ge2s7te.
+ge2s7ten
+ge2s7ter
+ge2s7tik
+ge5unt
+4g3ex3
+2g1f8
+2g1g
+g1ha
+6g1hei
+5ghel.
+g5henn
+6g1hi
+g1ho
+1ghr
+g1hö
+1gi
+gi5la
+gi8me.
+gi1na
+4g3ins
+gis1tr
+g1j
+2g1k
+8gl.
+1glad
+g5lag
+glan4z3
+1glas
+6glass
+5glaub
+g3lauf
+1gle.
+g5leb
+3gleic
+g3lein
+5gleis
+1glem
+2gler
+8g3leu
+gli8a
+g2lie
+3glied
+1g2lik
+1g2lim
+g6lio
+1gloa
+5glom
+1glon
+1glop
+g1los
+g4loss
+g5luf
+1g2ly
+1glü
+2g1m
+gn8
+6gn.
+1gna
+8gnach
+2gnah
+g1nas
+g8neu
+g2nie
+g3nis
+1gno
+8gnot
+1go
+goe1
+8gof
+2gog
+5gogr
+6g5oh
+goni5e
+6gonist
+go1ra
+8gord
+2g1p2
+g1q
+1gr4
+g5rahm
+gra8m
+gra4s3t
+6g1rec
+gre6ge
+4g3reic
+g5reit
+8grenn
+gri4e
+g5riem
+5grif
+2grig
+g5ring
+6groh
+2grot
+gro6ß
+4grut
+2gs
+gs1ab
+g5sah
+gs1ak
+gs1an
+gs8and
+gs1ar
+gs1au
+g1sc
+gs1ef
+g5seil
+gs5ein
+g2s1er
+gs1in
+g2s1o
+gso2r
+gs1pr
+g2s1u
+2g1t
+g3te
+g2t1h
+1gu
+gu5as
+gu2e
+2gue.
+6gued
+4g3uh
+8gums
+6g5unt
+gut3h
+gu2tu
+4g1v
+2g1w
+gy1n
+g1z
+1gä
+8gä8m
+6gärm
+1gö
+1gü
+6güb
+1haa
+hab8r
+ha8del
+hade4n
+8hae
+ha5el.
+haf6tr
+2hal.
+ha1la
+hal4b5a
+6hale
+8han.
+ha1na
+han6dr
+han6ge.
+2hani
+h5anth
+6hanz
+6harb
+h3arbe
+h3arme
+ha5ro
+ha2t1h
+h1atm
+hau6san
+ha8ß
+h1b2
+h1c
+h1d
+he2bl
+he3cho
+h3echt
+he5d6s
+5heft
+h5e6he.
+hei8ds
+h1eif
+2hein
+he3ism
+he5ist.
+heit8s3
+hek6ta
+hel8lau
+8helt
+he6mer
+1hemm
+6h1emp
+hen5end
+hen5klo
+hen6tri
+he2nu
+8heo
+he8q
+her3ab
+he5rak
+her3an
+4herap
+her3au
+h3erbi
+he1ro
+he8ro8b
+he4r3um
+her6z5er
+he4spe
+he1st
+heta6
+het5am
+he5th
+heu3sc
+he1xa
+hey5e
+h1f2
+h1g
+hgol8
+h1h
+h1iat
+hie6r5i
+hi5kt
+hil1a2
+hil4fr
+hi5nak
+hin4ta
+hi2nu
+hi5ob
+hirn5e
+hir6ner
+hi1sp
+hi1th
+hi5tr
+5hitz
+h1j
+h6jo
+h1k2
+hlabb4
+hla4ga
+hla6gr
+h5lai
+hl8am
+h1las
+h1laß
+hl1c
+h1led
+h3lein
+h5ler.
+h2lif
+h2lim
+h8linf
+hl5int
+h2lip
+h2lit
+h4lor
+h3lose
+h1läs
+hme5e
+h2nee
+h2nei
+hn3eig
+h2nel
+hne8n
+hne4p3f
+hn8erz
+h6netz
+h2nip
+h2nit
+h1nol
+hn5sp
+h2nuc
+h2nud
+h2nul
+hoch1
+1hoh
+hoh8lei
+2hoi
+ho4l3ar
+1holz
+h2on
+ho1ra
+6horg
+5horn.
+ho3sl
+hos1p
+ho4spi
+h1p
+hpi6
+h1q
+6hr
+h1rai
+h8rank
+h5raum
+hr1c
+hrcre8
+h1red
+h3reg
+h8rei.
+h4r3erb
+h8rert
+hrg2
+h1ric
+hr5ins
+h2rom
+hr6t5erl
+hr2t1h
+hr6t5ra
+hr8tri
+h6rum
+hr1z
+hs3ach
+h6s5amt
+h1sc
+h6s5ec
+h6s5erl
+hs8erle
+h4sob
+h1sp
+h8spaß
+h8spel
+hs6po
+h4spun
+h1str
+h4s3tum
+hs3und
+h1sü
+h5ta.
+h5tab
+ht3ac
+ht1ak
+ht3ang
+h5tanz
+ht1ar
+ht1at
+h5taub
+h1te
+h2t1ec
+ht3eff
+ht3ehe
+h4t3eif
+h8teim
+h4t3ein
+ht3eis
+h6temp
+h8tentf
+hte8ren
+h6terfü
+h8tergr
+h4t3erh
+h6t5ersc
+h8terst
+h8tese
+h8tess
+h2t1eu
+h4t3ex
+ht1he
+ht5hu
+h1ti
+ht5rak
+hts3ah
+ht1sc
+ht6sex
+ht8sk
+ht8so
+h1tu
+htz8
+h5tüm
+hub5l
+hu6b5r
+huh1l
+h5uhr.
+huld5a6
+hu8lent
+hu8lä
+h5up.
+h1v
+h5weib
+h3weis
+h1z
+hä8kl
+häl8s
+häma8tu8
+hä8sche.
+hät1s
+häu4s3c
+2hö.
+2höe
+8höi
+hö6s
+hös5c
+hühne6
+hül4s3t
+hütte8re
+i5adn
+i1af
+i5ak.
+i1al.
+i1al1a
+i1alb
+i1ald
+i5alei
+i1alf
+i1alg
+i3alh
+i1alk
+i1all
+i1alp
+i1alr
+i1als
+i1alt
+i1alv
+i5alw
+i3alz
+i1an.
+ia5na
+i3and
+ian8e
+ia8ne8b
+i1ang
+i3ank
+i5ann
+i1ant
+i1anz
+i6apo
+i1ar.
+ia6rab
+i5arr
+i1as.
+i1asm
+i1ass
+i5ast.
+i1at.
+i5ats
+i1au
+i5azz
+i6b5eig
+i6b5eis
+ib2le
+i4blis
+i6brig
+i6b5unt
+i6büb
+i1che
+ich5ei
+i6cherb
+i1chi
+ich5ins
+ich1l
+ich3m
+ich1n
+i1cho
+icht5an
+icht3r
+i1chu
+ich1w
+ick6s5te
+ic5l
+i1d
+id3arm
+3ideal
+ide8na
+3ideol
+ide5rö
+i6diot
+id5rec
+id1t
+ie1a
+ie6b5ar
+iebe4s3
+ie2bl
+ieb1r
+ie8bra
+ie4bre
+ie8bä
+ie2dr
+ie1e8
+ie6f5ad
+ief5f
+ie2f1l
+ie4fro
+ief1t
+i1ei
+ie4l3ec
+ie8lei
+ie4lek
+i3ell
+i1en.
+i1end
+ien6e
+i3enf
+i5enn
+ien6ne.
+i1enp
+i1enr
+i5ensa
+ien8stal
+i5env
+i1enz
+ie5o
+ier3a4b
+ie4rap
+i2ere
+ie4rec
+ie6r5ein
+ie6r5eis
+ier8er
+i3ern.
+ie8rum
+ie8rund
+ie6s5che
+ie6tau
+ie8tert
+ie5the
+ie6t5ri
+i1ett
+ie5un
+iex5
+2if
+i1fa
+if5ang
+i6fau
+if1fr
+if5lac
+i5f6lie
+i1fre
+ift5a
+if6t5r
+ig3art
+2ige
+i8gess
+ig5he
+i5gla
+ig2ni
+i5go
+ig3rot
+ig3s2p
+i1ha
+i8ham
+i8hans
+i1he
+i1hi
+ih1n
+ih1r
+i1hu
+i8hum
+ih1w
+8i1i
+ii2s
+ii2t
+i1j
+i1k
+i6kak
+i8kerz
+i6kes
+ik4ler
+i6k5unt
+2il
+i5lac
+i1lag
+il3ans
+i5las
+i1lau
+il6auf
+i1le
+ile8h
+i8lel
+il2fl
+il3ipp
+il6l5enn
+i1lo
+ilt8e
+i1lu
+i1lä
+i8mart
+imb2
+i8mele
+i8mid
+imme6l5a
+i1mu
+i1mä
+i5mö
+ina5he
+i1nat
+in1au
+inau8s
+8ind.
+in4d3an
+5index
+ind2r
+3indus
+i5nec
+i2n1ei
+i8nerw
+3infek
+1info
+5ingeni
+ing5s6o
+5inhab
+ini5er.
+5inj
+in8kät
+in8nan
+i1no
+inoi8d
+in3o4ku
+in5sau
+in1sp
+5inspe
+5instit
+5instru
+ins4ze
+5intere
+5interv
+in3the
+in5t2r
+i5ny
+inä2
+i1när
+in1äs
+inö8
+in5öd
+i1nös
+2io
+io1a8
+io1c
+iode4
+io2di
+ioi8
+i1ol.
+i1om.
+i1on.
+i5onb
+ion2s1
+i1ont
+i5ops
+i5o8pt
+i1or.
+i3oral
+io3rat
+i5orc
+i1os.
+i1ot.
+i1o8x
+2ip
+i1pa
+i1pi
+i1p2l
+i1pr
+i1q
+i1ra
+ir6bl
+i1re
+i1ri
+ir8me8d
+ir2m1o2
+ir8nak
+i1ro
+ir5rho
+ir6schl
+ir6sch5r
+i5rus
+i5ry
+i5rä
+i1sa
+i8samt
+i6sar
+i2s1au
+i8scheh
+i8schei
+isch5m
+isch3r
+ischä8
+is8ele
+ise3ra
+i4s3erh
+is3err
+isi6de
+i8sind
+is4kop
+ison5e
+is6por
+i8s5tum
+i5sty
+i5sö
+i1ta
+it5ab.
+i2t1a2m
+i8tax
+i1te
+i8tersc
+i1thi
+i1tho
+i5thr
+it8hä
+i1ti
+i8ti8d
+iti6kl
+itmen4
+i1to
+i8tof
+it3ran
+it3rau
+i1tri
+itri5o
+it1sc
+it2se
+it5spa
+it8tru
+i1tu
+it6z5erg
+it6z1w
+i1tä
+itä6r5e
+ität2
+itäts5
+i1tü
+i1u
+iu6r
+2i1v
+i6vad
+iva8tin
+i8vei
+i6v5ene
+i8verh
+i2vob
+i8vur
+i1w
+iwi2
+i5xa
+i1xe
+i1z
+ize8n
+i8zir
+i6z5w
+iä8m
+i1ä6r
+i5ät.
+i5äv
+i1ö8
+iü8
+i6ß5ers
+ja5la
+je2t3r
+6jm
+5jo
+jo5as
+jo1ra
+jou6l
+ju5cha
+jugen4
+jugend5
+jung5s6
+3jä
+1ka
+8kachs
+8kakz
+ka1la
+kal5d
+kam5t
+ka1na
+2kanl
+8kapf
+ka6pl
+ka5r6a
+6k3arbe
+ka1ro
+kar6p5f
+4k3arti
+8karz
+ka1rä
+kasi5e
+ka6teb
+kat8ta
+kauf6s
+kau3t2
+2k1b
+2k1c
+4k1d
+kehr6s
+kehrs5a
+8keic
+2k1eig
+6k5ein
+6k5eis
+ke6lar
+ke8leis
+ke8lo
+8kemp
+k5ente.
+k3entf
+8k5ents
+6kentz
+ke1ra
+k5erlau
+2k1f8
+2k1g
+2k1h
+ki5fl
+8kik
+king6s5
+6kinh
+ki5os
+ki5sp
+ki5th
+8ki8ö
+2k1k2
+kl8
+1kla
+8klac
+k5lager
+kle4br
+k3leib
+3kleid
+kle5isc
+4k3leit
+k3lek
+6k5ler.
+5klet
+2klic
+8klig
+k2lim
+k2lin
+5klip
+5klop
+k3lor
+1klä
+2k1m
+kmani5e
+kn8
+6kner
+k2ni
+knä8
+1k2o
+ko1a2
+ko6de.
+ko1i
+koi8t
+ko6min
+ko1op
+ko1or
+ko6pht
+ko3ra
+kor6d5er
+ko5ru
+ko5t6sc
+k3ou
+3kow
+6k5ox
+2k1p2
+k1q
+1kr8
+4k3rad
+2k1rec
+4k3reic
+kre5ie
+2krib
+6krig
+2krip
+6kroba
+2ks
+k1sa
+k6sab
+ksal8s
+k8samt
+k6san
+k1sc
+k2s1ex
+k5spat
+k5spe
+k8spil
+ks6por
+k1spr
+kst8
+k2s1uf
+2k1t
+kta8l
+kt5a6re
+k8tein
+kte8re
+k2t1h
+k8tinf
+kt3rec
+kt1s
+1ku
+ku1ch
+kuck8
+k3uhr
+ku5ie
+kum2s1
+kunfts5
+kun2s
+kunst3
+ku8rau
+ku4ro
+kurz1
+4kusti
+ku1ta
+ku8ß
+6k1v
+2k1w
+ky5n
+2k1z
+1kä
+kä4m
+4k3ämi
+käse5
+1kö
+kö1c
+kö1s
+1kü
+kü1c
+kür6sc
+1la.
+8labf
+8labh
+lab2r
+2l1abs
+lach3r
+la8dr
+5ladu
+8ladv
+6laff
+laf5t
+la2gn
+5laken
+8lamb
+la6mer
+5lampe.
+2l1amt
+la1na
+1land
+lan4d3a
+lan4d3r
+lan4gr
+8lanme
+6lann
+8lanw
+6lanä
+8lappa
+lap8pl
+lap6pr
+l8ar.
+la5ra
+lar4af
+la8rag
+la8ran
+la6r5a6s
+l3arbe
+la8rei
+6larm.
+la8sa
+la1sc
+la8sta
+lat8i
+6l5atm
+4lauss
+4lauto
+1law
+2lb
+l8bab
+l8bauf
+l8bede
+l4b3ins
+l5blo
+lbst5an
+lbst3e
+8lc
+l1che
+l8chert
+l1chi
+lch3m
+l5cho
+lch5w
+6ld
+l4d3ei
+ld1re
+l6düb
+le2bl
+le8bre
+lecht6s5
+led2r
+6leff
+le4gas
+1lehr
+lei6br
+le8inf
+8leinn
+5leistu
+4lektr
+le6l5ers
+lemo2
+8lemp
+l8en.
+8lends
+6lendun
+le8nend
+len8erw
+6l5ents
+4l3entw
+4lentz
+8lenzy
+8leoz
+6lepi
+le6pip
+8lepo
+1ler
+l6er.
+8lerbs
+6l5erde
+le8reis
+le8rend
+le4r3er
+4l3erg
+l8ergr
+6lerkl
+6l5erzie
+8lerö
+8lesel
+lesi5e
+le3sko
+le3tha
+let1s
+5leuc
+4leuro
+leu4s3t
+le5xe
+6lexp
+l1f
+2l1g
+lgend8
+l8gh
+lglie3
+lglied6
+6l1h
+1li
+li1ar
+li1as
+2lick
+li8dr
+li1en
+lien6n
+li8ers
+li8ert
+2ließ
+3lig
+li8ga8b
+li1g6n
+li1l8a
+8limb
+li1na
+4l3indu
+lings5
+4l3inh
+6linj
+link4s3
+4linkt
+2lint
+8linv
+4lipp
+5lipt
+4lisam
+livi5e
+6l1j
+6l1k
+l8keim
+l8kj
+lk2l
+lko8f
+lkor8
+lk2sa
+lk2se
+6ll
+l1la
+ll3a4be
+l8labt
+ll8anl
+ll1b
+ll1c
+ll1d6
+l1le
+l4l3eim
+l6l5eise
+ller3a
+l4leti
+l5lip
+l1lo
+ll3ort
+ll5ov
+ll6spr
+llte8
+l1lu
+ll3urg
+l1lä
+l5lü
+l6lüb
+2l1m
+l6m5o6d
+6ln
+l1na
+l1no
+8lobl
+lo6br
+3loch.
+l5o4fen
+5loge.
+5lohn
+4l3ohr
+1lok
+l2on
+4l3o4per
+lo1ra
+2l1ord
+6lorg
+4lort
+lo1ru
+1los.
+lo8sei
+3losig
+lo6ve
+lowi5
+6l1p
+lp2f
+l8pho
+l8pn
+lp4s3te
+l2pt
+l1q
+8l1r
+2ls
+l1sa
+l6sarm
+l1sc
+l8sec
+l6s5erg
+l4s3ers
+l8sh
+l5s6la
+l1sp
+ls4por
+ls2pu
+l1str
+l8suni
+l1sü
+2l1t
+lt5amp
+l4t3ein
+l5ten
+l6t5eng
+l6t5erp
+l4t3hei
+lt3her
+l2t1ho
+l6t5i6b
+lti1l
+l8trö
+lt1sc
+lt6ser
+lt4s3o
+lt5ums
+lu8br
+lu2dr
+lu1en8
+8lu8fe
+luft3a
+luf8tr
+lu6g5r
+2luh
+l1uhr
+lu5it
+5luk
+2l1umf
+2l1umw
+1lun
+6l5u6nio
+4l3unte
+lu5ol
+4lurg
+6lurs
+l3urt
+lu4sto
+lus1tr
+lu6st5re
+lu8su
+lu6tal
+lu6t5e6g
+lu8terg
+lu3the
+lu6t5or
+lu2t1r
+lu6ß5
+l1v
+lve5r6u
+2l1w
+1ly
+lya6
+6lymp
+ly1no
+l8zess
+l8zo8f
+l3zwei
+lz5wu
+3länd
+lä5on
+lä6sc
+lät1s
+5läuf
+2läug
+läu6s5c
+lä5v
+l1öl
+1lös
+lö1ß6t
+6l1übe
+1ma
+8mabg
+ma5chan
+mad2
+ma5el
+4magg
+mag8n
+ma1la
+ma8lau
+mal5d
+8malde
+mali5e
+malu8
+ma8lut
+2m1amp
+3man
+mand2
+man3ds
+8mangr
+mani5o
+8m5anst
+6mappa
+4m3arbe
+mar8kr
+ma1r4o
+mar8schm
+3mas
+ma1sc
+ma1tö
+4m5auf
+ma5yo
+2m1b
+mb6r
+2m1c
+2m1d
+md6sä
+1me
+me1ch
+me5isc
+5meld
+mel8sa
+8memp
+me5nal
+men4dr
+men8schl
+men8schw
+8mentsp
+me1ra
+mer4gl
+me1ro
+3mes
+me6s5ei
+meta3s2
+me1th
+me8ß
+2m1f6
+2m1g
+2m1h
+1mi
+mi1a
+mi6ale
+mi1la
+2m1imm
+mi1na
+mi5nü
+mi4s3an
+mit1h
+mi5t6ra
+3mitt
+mitta8
+mi6ß5
+6mj
+2m1k8
+2m1l
+2m1m
+m6mad
+m6m5ak
+m8menth
+m8mentw
+mme6ra
+m2mn
+mm5sp
+mm5ums
+mmut5s
+m8män
+m1n8
+m5ni
+1mo
+mo5ar
+mo4dr
+8mof
+mo8gal
+mo4kla
+mol5d
+m2on
+mon8do
+mo4n3od
+mon2s1tr
+mont8a
+6m5ony
+mopa6
+mo1ra
+mor8d5a
+mo1sc
+mo1sp
+5mot
+moy5
+2mp
+m1pa
+mpfa6
+mpf3l
+mphe6
+m1pi
+mpin6
+m1pl
+mp2li
+m2plu
+mpo8ste
+m1pr
+mprä5
+mp8th
+mput6
+mpu5ts
+m1pö
+8m1q
+2m1r
+2ms
+ms5au
+m1sc
+msch4l
+ms6po
+m3spri
+m1str
+2m1t
+mt1ar
+m8tein
+m2t1h
+mt6se
+mt8sä
+mu5e
+6m5uh
+mumi1
+1mun
+mun6dr
+muse5e
+mu1ta
+2m1v
+mvol2
+mvoll3
+2m1w
+1my
+2m1z
+mä6kl
+1män
+mä1s
+mä5tr
+mäu4s3c
+3mäß
+möb2
+6möl
+1mü
+5mün
+3müt
+1na.
+n5ab.
+8nabn
+n1abs
+n1abz
+na6bä
+na2c
+nach3e
+3nacht
+1nae
+na5el
+n1afr
+1nag
+1n2ah
+na8ha
+na8ho
+1nai
+6nair
+na4kol
+n1akt
+nal1a
+8naly
+1nama
+na4mer
+na1mn
+n1amp
+8n1amt
+5nanc
+nan6ce
+n1and
+n6and.
+2n1ang
+1nani
+1nann
+n1ans
+8nanw
+5napf.
+1n2ar.
+na2ra
+2n1arc
+n8ard
+1nari
+n8ark
+6n1arm
+5n6ars
+2n1art
+n8arv
+6natm
+nat6s5e
+1naue
+4nauf
+n3aug
+5naui
+n5auk
+na5um
+6nausb
+6nauto
+1nav
+2nax
+3naz
+1naß
+n1b2
+nbau5s
+n1c
+nche5e
+nch5m
+2n1d
+nda8d
+n2d1ak
+nd5ans
+n2d1ei
+nde8lac
+ndel6sa
+n8derhi
+nde4se
+nde8stal
+n2dj
+ndnis5
+n6d5or6t
+nd3rec
+nd3rot
+nd8samt
+nd6sau
+ndt1h
+n8dumd
+1ne
+ne5as
+ne2bl
+6n5ebn
+2nec
+5neei
+ne5en
+ne1g4l
+2negy
+4n1ein
+8neis
+4n3e4lem
+8nemb
+2n1emp
+nen1a
+6n5energ
+nen3k
+8nentb
+4n3en3th
+8nentl
+8n5entn
+8n5ents
+ne1ra
+ne5r8al
+ne8ras
+8nerbi
+6n5erde.
+nere5i6d
+nerfor6
+6n5erhö
+8nerlö
+2n1err
+n8ers.
+6n5ertra
+2n1erz
+nesi3e
+net1h
+neu4ra
+neu5sc
+8neuß
+n1f
+nf5f
+nf2l
+nflei8
+nf5lin
+nft8st
+n8g5ac
+ng5d
+ng8en
+nge8ram
+ngg2
+ng1h
+n6glic
+ng3rip
+ng8ru
+ng2se4
+ng2si
+n2g1um
+n1gy
+n8gäl
+n1h
+nhe6r5e
+1ni
+ni1bl
+ni5chä
+ni8dee
+n6ie
+ni1en
+nie6s5te
+niet5h
+ni8etn
+4n3i6gel
+n6ik
+ni1la
+2n1imp
+ni5na
+2n1ind
+8ninf
+6n5inh
+ni8nit
+6n5inn
+2n1ins
+4n1int
+n6is
+nis1tr
+ni1th
+ni1tr
+n1j
+n6ji
+n8kad
+nk5ans
+n1ke
+n8kerla
+n1ki
+nk5inh
+n5klö
+n1k2n
+n8k5not
+nk3rot
+n8krü
+nk5spo
+nk6t5r
+n8kuh
+n6küb
+n5l6
+nli4mi
+n1m
+nmen4s
+n1na
+n8nerg
+nni5o
+n1no
+nn4t3ak
+nnt1h
+nnu1e
+n1ny
+n1nä
+n1nö
+n1nü
+no5a
+no4b3la
+4n3obs
+2nobt
+noche8
+no6die
+no4dis
+no8ia
+no5isc
+6n5o6leu
+no4mal
+noni6er
+2n1onk
+n1ony
+4n3o4per
+6nopf
+6nopti
+no3ra
+no4ram
+nor6da
+4n1org
+2n1ort
+n6os
+no1st
+8nost.
+no8tan
+no8ter
+noty6pe
+6n5ox
+n1p2
+n1q
+n1r
+nrös3
+6ns
+n1sac
+ns3ang
+n1sc
+n8self
+n8s5erf
+n8serg
+n6serk
+ns5erw
+n8sint
+n1s2pe
+n1spr
+n6s5tat.
+n6stob
+n1str
+n1ta
+n4t3a4go
+nt5anh
+nt3ark
+nt3art
+n1te
+nt3eis
+nte5n6ar
+nte8nei
+nter3a
+nte6rei
+nt1ha
+nt6har
+n3ther
+nt5hie
+n3thus
+n1ti
+nti1c
+n8tinh
+nti1t
+ntlo6b
+ntmen8
+n1to
+nt3o4ti
+n1tr
+ntra5f
+ntra5ut
+nt8rea
+nt3rec
+nt8rep
+n4t3rin
+nt8rop
+n4t3rot
+n4trü
+nt1s
+nts6an
+nt2sk
+n1tu
+nt1z
+n1tä
+n1tö
+n8töl
+n1tü
+1nu
+nu1a
+nu5el
+nu5en
+4n1uhr
+nu5ie
+8numl
+6n5ums
+6n5umw
+2n1und
+6nuni
+6n5unr
+2n1unt
+2nup
+2nu6r
+n5uri
+nu3skr
+nu5ta
+n1v
+8n1w
+1nys
+n1za
+n6zab
+n2z1ar
+n6zaus
+nzi4ga
+n8zof
+n6z5unt
+n1zw
+n6zwir
+1näc
+5näe
+5näi
+n8äl
+nä6m
+nä6re
+n5ärz
+5näus
+n1öl
+1nöt
+n5öz
+5nü.
+6n1ü2b
+5nüß
+o5ab.
+oa2l
+o8ala
+o1a2m
+o1an
+ob1ac
+obe4ra
+o6berh
+5o4bers
+o4beru
+obe6ser
+1obj
+o1bl
+o2bli
+ob5sk
+3obst.
+ob8sta
+obst5re
+ob5sz
+o1che
+oche8b
+o8chec
+o3chi
+och1l
+och3m
+ocho8f
+o3chro
+och3to
+o3chu
+och1w
+o1d
+o2d1ag
+od2dr
+ode5i
+ode6n5e
+od1tr
+o5e6b
+o5e6der.
+oe8du
+o1ef
+o1e2l
+o1e2p
+o1er.
+o5e8x
+o1fa
+of8fan
+1offi
+of8fin
+of6f5la
+o5fla
+o1fr
+8o1g
+og2n
+o1ha
+o1he
+o6h5eis
+o1hi
+ohl1a
+oh1le
+oh4l3er
+5ohm.
+oh2ni
+o1ho
+oh1re
+oh1ru
+o1hu
+oh1w
+o1hy
+o1hä
+o5ia
+o1id.
+o8idi
+oi8dr
+o5ids
+o5isch.
+oiset6
+o1ism
+o3ist.
+o5i6tu
+o1j
+o1k
+ok2l
+ok3lau
+o8klä
+1okta
+o1la
+old5am
+old5r
+o1le
+ole5in
+ole1r
+ole3u
+ol6gl
+ol2kl
+olk4s1
+ol8lak
+ol8lauf.
+ol6lel
+ol8less
+o1lo
+ol1s
+ol2ster
+ol6sk
+o1lu
+oly1e2
+5olym
+o2mab
+om6an
+o8mau
+ombe4
+o8merz
+om5sp
+o1mu
+o8munt
+o1mä
+o1mö
+o1na
+ona8m
+on1ax
+on8ent
+o6n5erb
+8oni
+oni5er.
+on1k
+on6n5a6b
+o1no
+ono1c
+o4nokt
+1ons
+onts8
+o1nä
+oo8f
+1oog
+oo2pe
+oo2sa
+o1pa
+3o4pera
+o3pfli
+opf3lo
+opf3r
+o1pi
+o1pl
+o2pli
+o5p6n
+op8pa
+op6pl
+o1pr
+o3p4ter
+1opti
+o1pä
+o5pö
+o1q
+o1ra.
+o3rad
+o8radd
+1oram
+o6rang
+o5ras
+o8rauf
+or5cha
+or4d3a4m
+or8dei
+or8deu
+1ordn
+or4dos
+o1re
+o5re.
+ore2h
+o8r5ein
+ore5isc
+or6enn
+or8fla
+or8fli
+1orga
+5orgel.
+or2gl
+o1ri
+5o6rient
+or8nan
+or8nä
+o1ro
+or1r2h
+or6t5an
+or8tau
+or8tere
+o1rus
+o1ry
+o1rä
+or1ü2
+o1sa
+osa3i
+6ose
+o8serk
+o1sk
+o6ske
+o6ski
+os2kl
+os2ko
+os2kr
+osni5e
+o2s1o2d
+o3s4per
+o4stam
+o6stau
+o3stra
+ost3re
+osu6
+o6s5ur
+o5s6ze
+o1ta
+ot3auf
+o6taus
+o1te
+o6terw
+o1th
+othe5u
+o2th1r
+o1ti
+o1to
+oto1a
+ot1re
+o1tri
+o1tro
+ot1sc
+o3tsu
+ot6t5erg
+ot2t3h
+ot2t5r
+ot8tö
+o1tu
+ou3e
+ouf1
+ou5f6l
+o5u6gr
+ou5ie
+ou6rar
+ou1t6a
+o1v
+o1wa
+o1we
+o6wer.
+o1wi
+owid6
+o1wo
+o5wu
+o1xe
+oy5al.
+oy1e
+oy1i
+o5yo
+o1z
+oza2r
+1o2zea
+ozo3is
+oö8
+oß5elt
+oß1t
+3paa
+pa6ce
+5pad
+pag2
+1pak
+pa1la
+pa8na8t
+pani5el
+pa4nor
+pan1s2
+1pap
+pap8s
+pa8rei
+par8kr
+paro8n
+par5o6ti
+part8e
+5partei
+3partn
+pas6sep
+pa4tha
+1pau
+6paug
+pau3sc
+p1b
+8p5c
+4p1d
+1pe
+4peic
+pe5isc
+2pek
+pen3k
+pen8to8
+p8er
+pe1ra
+pere6
+per5ea
+per5eb
+pe4rem
+2perr
+per8ran
+3pers
+4persi
+pe3rü
+pe4sta
+pet2s
+p2f1ec
+p4fei
+pf1f
+pf2l
+5pflanz
+pf8leg
+pf3lei
+2pft
+pf3ta
+p1g
+1ph
+2ph.
+2p1haf
+6phb
+8phd
+6p5heit
+ph5eme
+6phg
+phi6e
+8phk
+6phn
+p5holl
+pht2
+ph3tha
+4ph3the
+phu6
+6phz
+pi1en
+pi5err
+pi1la
+pi1na
+5pinse
+pioni8e
+1pis
+pi1s2k
+pi1th
+p1k
+pl8
+5pla
+p2lau
+4plei
+p3lein
+2pler
+6p5les
+2plig
+p6lik
+6p5ling
+p2liz
+plo8min
+6p1m
+p1n
+1p2o
+8poh
+5pol
+po8lan
+poly1
+po3ny
+po1ra
+2porn
+por4t3h
+po5rö
+5poti
+p1pa
+p6p5ei
+ppe6la
+pp5f
+p2p1h
+p1pi
+pp1l
+ppp6
+pp5ren
+pp1s
+pp2ste
+p5pö
+pr6
+3preis
+1pres
+2p3rig
+5prinz
+1prob
+1prod
+5prog
+pro8pt
+pro6t5a
+prote5i
+8proß
+prä3l
+1präs
+präte4
+1prüf
+p5schl
+2pst
+1p2sy
+p1t
+p8to8d
+pt1s
+5p6ty
+1pu
+pu1b2
+2puc
+pu2dr
+puf8fr
+6p5uh
+pun8s
+pu8rei
+pu5s6h
+pu1ta
+p1v
+p3w
+5py
+py5l
+p1z
+pä6der
+p5ä6m
+pä8nu
+8pär
+pät5h
+pät1s
+qu6
+1qui
+8rabk
+ra6bla
+3rable
+ra2br
+r1abt
+6rabz
+ra4dan
+ra2dr
+5rafal
+ra4f3er
+ra5gla
+ra2g3n
+6raha
+ral5am
+5rald
+4ralg
+ra8lins
+2rall
+ral5t
+8ramei
+r3anal
+r6and
+ran8der
+ran4dr
+8ranf
+6ranga
+5rangi
+ran8gli
+r3angr
+rans5pa
+8ranw
+r8anz.
+ra5or
+6rapf
+ra5pl
+rap6s5er
+2r1arb
+1rarh
+r1arm
+ra5ro
+2r1art
+6r1arz
+ra8tei
+ra6t5he
+6ratl
+ra4t3ro
+r5atta
+raue4n
+6raus.
+r5austa
+rau8tel
+raut5s
+ray1
+r1b
+rb5lass
+r6bler
+rb4lie
+rbon6n
+r8brecht
+rb6s5tä
+r8ces
+r1che
+rch1l
+rch3m
+rch3re
+rch3tr
+rch1w
+8rd
+r1da
+r8dachs
+r8dap
+rda5ro
+rde5ins
+rdio5
+r8dir
+rd3ost
+r1dr
+r8drau
+1re.
+re1ak
+3reakt
+re3als
+re6am.
+re1as
+4reben
+re6bl
+rech5a
+r8edi
+re3er
+8reff
+3refl
+2reh
+5reha
+r4ei.
+reich6s5
+8reier
+6reign
+re5imp
+4r3eina
+6r3einb
+6reing
+6r5einn
+6reinr
+4r3eins
+r3eint
+reli3e
+8r5elt
+6rempf
+2remt
+ren5a6b
+ren8gl
+r3enni
+1reno
+5rente
+4r3enth
+8rentl
+4r3entw
+8rentz
+ren4zw
+re1on
+requi5
+1rer
+rer4bl
+6rerbs
+4r3erd
+8rerhö
+8rerkl
+4r3erla
+8rerlö
+4r3erns
+6r5ernä
+rer5o
+6r5erreg
+r5ertr
+r5erwec
+r5erö
+re2sa
+re8schm
+2ress
+re5u8ni
+6rewo
+2r1ex
+r1f
+r8ferd
+rf4lie
+8r1g
+r8gah
+rge4bl
+rge5na
+rgest4
+rg6ne
+r2gni2
+r8gob
+r4g3ret
+rg8sel
+r1h8
+r2hy
+5rhyt
+ri1ar
+ri5cha
+rid2g
+r2ie
+rieg4s5
+ri8ei
+ri1el
+ri6ele
+ri1en
+ri3er.
+ri5ers.
+ri6fan
+ri8fer
+ri8fr
+1r2ig
+ri8kn
+ri5la
+rimä8
+ri1na
+r8inde
+rin4ga
+rin6gr
+1rinn
+6rinner
+rino1
+r8insp
+4rinst
+ri1nä
+ri5o6ch
+ri1o2d
+ri3o6st
+2r1ir
+r2is
+ri3sko
+ri8spr
+ri5sv
+r2it
+6r5i6tal
+ri5tr
+ri6ve.
+8r1j
+6rk
+r1ke
+rkehrs5
+r1ki
+r3klin
+r1k2n
+rk3str
+rk4t3an
+rk6to
+r6kuh
+rkä4s3t
+r1l
+r5li
+rline5a
+6r1m
+r6manl
+rma4p
+r4m3aph
+r8minf
+r8mob
+rm5sa
+2rn
+r1na
+rna8be
+r5ne
+rn2ei
+r6neif
+r6nex
+r6nh
+rn1k
+r1no
+r6n5oc
+rn1sp
+r1nä
+r1nü
+ro6bern
+6robs
+ro1ch
+3rock.
+ro5de
+ro1e
+4rofe
+ro8hert
+1rohr
+ro5id
+ro1in
+ro5isc
+6rolym
+r2on
+6roog
+ro6phan
+r3ort
+ro1s2p
+ro5s6w
+ro4tau
+ro1tr
+ro6ts
+5rout
+r1p
+rpe8re
+rp2f
+r2ps
+r2pt
+r1q
+2rr
+r1ra
+r1re
+rrer6
+rr6hos
+r5rhö
+r1ri
+r1ro
+rro8f
+rr8or
+rror5a
+r1ru
+r3ry
+r1rä
+r1rö
+r1rü
+2r1s
+r2ste
+r2sti
+r6sab
+r4sanf
+rse6e
+rse5na
+r2sh
+r6ska
+r6ski
+rs2kl
+r8sko
+r2sl
+rs2p
+r6stauf
+r8sterw
+r8stran
+rswi3d4
+r2sz
+2r1t
+rt3art
+r8taut
+r5tei
+rt5eige
+r8tepe
+r4t3erh
+r8terla
+r4t3hei
+r5t6hu
+r4t3int
+rt5reif
+rt1sc
+rt6ser
+rt6s5o
+rt6s5u
+rt5und
+r8turt
+rube6
+ru1en
+1r4uf
+ruf4st
+ru1ie
+2r1umg
+2r1uml
+2rums
+run8der
+run4d5r
+6rundz
+6runf
+8runs
+2r1unt
+2r1ur
+r6us
+ru6sta
+rus1tr
+ru6tr
+1ruts
+r1v
+rven1
+rvi2c
+r1w
+r1x
+r1za
+rz5ac
+r6z5al
+r8z1ar
+r8zerd
+r6z5erf
+rz8erh
+rz4t3h
+r8zum
+rä4ste
+räu8sc
+r1öf
+5röhr
+rö5le
+3röll
+5römis
+r1ör
+rö2sc
+3rümp
+1sa.
+1saa
+s3a4ben
+sa2bl
+2s1abs
+6s1abt
+6sabw
+3sack.
+6s3a4der
+1saf
+sa1fa
+4s1aff
+sa5fr
+1sag
+1sai
+sa1i2k1
+4s1akt
+1sal
+sa1la
+4s3alpi
+6salter
+salz3a
+1sam
+s5anb
+san2c
+1sand
+s5angeh
+6sanl
+2s1ans
+6s3antr
+8s1anw
+s1ap
+s6aph
+8sapo
+sap5p6
+s8ar.
+2s1arb
+3sarg
+s1arm
+sa5ro
+2s1art
+6s1arz
+1sas
+1sat
+sat8a
+2s1atl
+sa8tom
+3s8aue
+s5auff
+sau5i
+s6aur
+2s1aus
+5s6ause
+2s1b2
+2sca
+s4ce
+8sch.
+3scha.
+5schade
+3schaf
+3schal
+sch5ame
+8schanc
+8schb
+1sche
+6schef
+8schex
+2schf
+2schg
+2schh
+1schi
+2schk
+5schlag
+5schlu
+6schmäß
+6schnaß
+1scho
+6schord
+6schp
+3schri
+8schric
+8schrig
+8schrou
+6schs
+2scht
+sch3ta
+sch3tr
+1schu
+8schunt
+6schv
+2schz
+5schö
+5schü
+2sco
+scre6
+6scu
+2s1d
+1se
+se5an
+se1ap
+se6ben
+se5ec
+see5i6g
+se3erl
+8seff
+se6han
+se8hi
+se8hö
+6s5eid.
+2s1eig
+s8eil
+5sein.
+sei5n6e
+6s5einh
+3s8eit
+3sel.
+se4lar
+selb4
+6s3e4lem
+se8lerl
+2s1emp
+sen3ac
+se5nec
+6s5ents
+4sentz
+s8er.
+se8reim
+ser5inn
+8sermä
+8s5erzi
+6seröf
+se1um
+8sexa
+6sexp
+2s1f2
+sfal8ler
+2s3g2
+sge5b2
+s1h
+s8hew
+5s6hip
+5s4hop
+1si
+2siat
+si1b
+sicht6s
+6s5i6dee
+siege6s5
+si1en
+si5err
+si1f2
+si1g2n
+si6g5r
+si8kau
+sik1i
+si4kin
+si2kl
+si8kü
+si1la
+sil6br
+si1na
+2s1inf
+sin5gh
+2s1inh
+sinne6s5
+2s1ins
+si5ru
+si5str
+4s1j
+s1k2
+6sk.
+2skau
+skel6c
+skelch5
+s6kele
+1s2ki.
+3s4kin.
+s6kiz
+s8kj
+6skn
+2skow
+3skrib
+3skrip
+2sku
+8skü
+s1l
+s8lal
+slei3t
+s4low
+2s1m
+s1n
+6sna
+6snot
+1so
+so1ch
+2s1odo
+so4dor
+6s5o4fen
+solo3
+s2on
+so5of
+4sope
+so1ra
+2s1ord
+4sorga
+sou5c
+so3un
+4s3ox
+sp2
+8spaa
+5spal
+1span
+2spap
+s2pec
+s4peis
+1spek
+s6perg
+4spers
+s6pes
+2s1pf
+8sphi
+1s2phä
+1spi
+spi4e
+6s5pig
+6spinse
+2spis
+2spla
+2spol
+5s6pom
+6s5pos
+6spoti
+1spra
+3s8prec
+6spreis
+5spring
+6sprob
+1spru
+s2pul
+1s2pur
+6spy
+5spän
+1spü
+s1q
+2s1r
+2ssa
+2sse
+2ssi
+2sso
+2ssä
+2ssö
+2ssü
+2s1sch
+sse8nu
+ssini6s
+ssoi6r
+2st.
+1sta
+4stafe
+2stag
+sta3la
+6stale
+4s2talg
+8stalk
+8stamt
+6st5anf
+4stans
+6stanw
+6starb
+sta4te
+6staus
+2stb
+6stc
+6std
+s1te
+4steil
+6steppi
+8stesse
+6stf
+2stg
+2sth
+st1ha
+st3hei
+s8t1hi
+st1ho
+st5hu
+s1ti
+s2ti4el
+4s2tigm
+6s2tind
+4s2tinf
+s2ti8r
+2stk
+2stl
+2stm
+1sto
+6stoll.
+4st3ope
+6stopf.
+6stord
+6stp
+4strai
+s3tral
+6s5traum
+3straß
+3strec
+6s3tref
+8streib
+5streif
+6streno
+6stres
+6strev
+2st5rig
+8s2t1ris
+s8troma
+st5rose
+2s1trua
+4struf
+3strum
+6sträg
+2st1s6
+2stt
+1stu
+stu5a
+4stuc
+2stue
+8stun.
+2stv
+2stw
+s2tyl
+6stz
+1stä
+8stäg
+1stö
+1stü
+8stüch
+4stür.
+1su
+su2b1
+3suc
+su1e
+su2fe
+su8mar
+6sumfa
+8sumk
+2s1unt
+sup1p2
+6s5u6ran
+6surte
+2s1v
+2s1w
+1sy
+8syl.
+sy5la
+syn1
+sy2na
+syne4
+s1z
+s4zend
+5s6zene.
+8szu
+1sä
+6s5änd
+6säugi
+6säuß
+5söm
+2s1ü2b
+1süc
+sü8di
+1sün
+5süß
+taats3
+4tab.
+taba6k
+ta8ban
+tab2l
+ta6bre
+4tabs
+t3absc
+8tabz
+6t3acht
+ta6der
+6tadr
+tad6s
+tad2t
+1tafe4
+1tag
+ta6ga6
+ta8gei
+tage4s
+tag6s5t
+tah8
+tahl3
+tai6ne.
+ta5ir.
+tak8ta
+tal3au
+1tale
+ta8leng
+tal5ert
+6t5a6mer
+6tamp
+tampe6
+2t1amt
+tan5d6a
+tan8dr
+tands5a
+tani5e
+6tanl
+2tanr
+t3ans
+8t5antr
+tanu6
+t5anw
+8tanwa
+tan8zw
+ta8rau
+6tarbe
+1tari
+2tark
+2t1arm
+ta1ro
+2tart
+t3arti
+6tarz
+ta1sc
+ta6sien
+ta8stem
+ta8sto
+t5aufb
+4taufn
+8taus.
+5tause
+8tausf
+6tausg
+t5ausl
+2t1b2
+2t1c
+t6chu
+2t1d
+te2am
+tea4s
+te8ben
+5techn
+4teff
+te4g3re
+te6hau
+2tehe
+te4hel
+2t1ehr
+te5id.
+teig5l
+6teign
+tei8gr
+1teil
+4teinh
+t5einhe
+4teis
+t5eisen
+8teiw
+te8lam
+te4lar
+4telek
+8telem
+te6man
+te6n5ag
+ten8erw
+ten5k
+tens4p
+ten8tro
+4t3entw
+8tentz
+te6pli
+5teppi
+ter5a6b
+te3ral
+ter5au
+8terbar
+t5erbe.
+6terben
+8terbs
+4t3erbt
+t5erde.
+ter5ebe
+ter5ein
+te8rers
+terf4
+8terhö
+6terklä
+ter8nor
+ter6re.
+t8erscha
+t5e6sel
+te8stau
+t3euro
+te1xa
+tex3e
+8texp
+tex6ta
+2t1f2
+2t1g2
+2th.
+th6a
+5tha.
+2thaa
+6t1hab
+6t5haf
+t5hah
+8thak
+3thal.
+6thals
+6t3hand
+2t1hau
+1the.
+3t4hea
+t1heb
+t5heil
+t3heit
+t3helf
+1theo
+5therap
+5therf
+6t5herz
+1thes
+1thet
+5thi.
+2t1hil
+t3him
+8thir
+3this
+t5hj
+2th1l
+2th1m
+th1n
+t5hob
+t5hof
+4tholz
+6thopti
+1thr6
+4ths
+t1hum
+1thy
+4t1hä
+2t1hö
+t1hü
+ti1a2m
+ti1b
+tie6fer
+ti1en
+ti8gerz
+tig3l
+ti8kin
+ti5lat
+1tilg
+t1ind
+tin4k3l
+ti3spa
+ti5str
+5tite
+ti5tr
+ti8vel
+ti8vr
+2t1j
+2t1k2
+2t1l
+tl8a
+2t1m8
+2t1n
+3tobe
+8tobj
+to3cha
+5tocht
+8tock
+tode4
+to8del
+to8du
+to1e
+6t5o6fen
+to1in
+toi6r
+5toll.
+to8mene
+t2ons
+2t1ony
+to4per
+5topf.
+6topt
+to1ra
+to1s
+to2ste
+to6ska
+tos2l
+2toti
+to1tr
+t8ou
+2t1p2
+6t1q
+tr6
+tra5cha
+tra8far
+traf5t
+1trag
+tra6gl
+tra6gr
+t3rahm
+1trai
+t6rans
+tra3sc
+tra6st
+3traue
+t4re.
+2trec
+t3rech
+t8reck
+6t1red
+t8ree
+4t1reg
+3treib
+4treif
+8t3reis
+8trepo
+tre6t5r
+t3rev
+4t3rez
+1trib
+t6rick
+tri6er
+2trig
+t8rink
+tri6o5d
+trizi5
+tro1a
+3troc
+trocke6
+troi8d
+tro8man.
+tro3ny
+5tropf
+6t5rosa
+t5roß
+5trub
+5trup
+trut5
+1träg
+6t1röh
+5trüb
+trü3bu
+t1rüc
+t1rüs
+2ts
+ts1ab
+t1sac
+tsa8d
+ts1ak
+t6s5alt
+ts1an
+ts1ar
+ts3auf
+t3schr
+t5schä
+tse6e
+tsee5i
+tsein6s
+ts3ent
+ts1er
+t8serf
+t4serk
+t8sh
+5t6sik
+t4s3int
+ts5ort.
+t5s6por
+t6sprei
+t1st
+t2ste
+t6s5tanz
+ts1th
+t6stit
+t4s3tor
+1t2sua
+t2s1uf
+t8sum.
+t2s1u8n
+t2s1ur
+2t1t
+tt5eif
+tte6sa
+tt1ha
+tt8ret
+tt1sc
+tt8ser
+tt5s6z
+1tuc
+tuch5a
+1tu1e
+6tuh
+t5uhr
+tu1i
+tu6it
+1tumh
+6t5umr
+1tums
+8tumt
+6tund
+6tunf
+2t1unt
+tu5ra
+tu6rau
+tu6re.
+tu4r3er
+2t1v
+2t1w
+1ty1
+ty6a
+ty8la
+8tym
+6ty6o
+2tz
+tz5al
+tz1an
+tz1ar
+t8zec
+tzeh6
+tzehn5
+t6z5ei.
+t6zor
+t4z3um
+t6zäu
+5täg
+6täh
+t5ält
+t8än
+täre8
+8tä8st
+6täuß
+t5öffen
+8tö8k
+1tön
+4tüb
+t6ü5ber.
+5tüch
+1tür.
+u3al.
+u5alb
+u5alf
+u3alh
+u5alk
+u3alp
+u3an.
+ua5na
+u3and
+u5ans
+u5ar.
+ua6th
+u1au
+ua1y
+u2bab
+ubi5er.
+u6b5rit
+ubs2k
+u5bö
+u8büb
+2uc
+u1che
+u6ch5ec
+u1chi
+uch1l
+uch3m
+uch5n
+uch1r
+uch5to
+ucht5re
+u1chu
+uch1w
+uck1a
+uck5in
+u1d
+ud4a
+u1ei
+u6ela
+uene8
+u6ep
+u1er
+uer1a
+ue8rerl
+uer5o
+u8esc
+u2est
+u8ev
+u1fa
+u2f1ei
+u4f3ent
+u8ferh
+uf1fr
+uf1l
+uf1ra
+uf1re
+uf1rä
+uf1rü
+uf1s2p
+uf1st
+uft1s
+u8gabt
+u8gad
+u6gap
+ugeb8
+u8gn
+ugo3s4
+u1ha
+u1he
+u1hi
+uh1le
+u1ho
+uh1re
+u1hu
+uh1w
+u1hä
+u1hö
+6ui
+ui5en
+u1ig
+u3ins
+uin8tes
+u5isch.
+u1j
+6uk
+u1ke
+u1ki
+u1kl
+u8klu
+u1k6n
+u5ky
+u1la
+uld8se
+u1le
+ul8lac
+ul6lau
+ul6le6l
+ul6lo
+ulni8
+u1lo
+ulo6i
+ult6a
+ult8e
+u1lu
+ul2vr
+u1lä
+u1lö
+3umfan
+5umlau
+umo8f
+um8pho
+u1mu
+umu8s
+u5mö
+u1n1a
+un2al
+un6at
+unau2
+6und.
+5undein
+un4d3um
+3undzw
+undü8
+un8düb
+une2b
+un1ec
+une2h
+un3eis
+3unfal
+1unfä
+5ungea
+3unglü
+ung2s1
+un8gä
+1u2nif
+un4it
+un8kro
+unk5s
+u1no
+unpa2
+uns2p
+unvol4
+unvoll5
+u5os.
+u1pa
+u1pi
+u1p2l
+u1pr
+up4s3t
+up2t1a
+u1q
+u1ra
+ur5abs
+ura8d
+ur5ah
+u6rak
+ur3alt
+u6rana
+u6r5ans
+u8rap
+ur5a6ri
+u8ratt
+u1re
+ur3eig
+ur8gri
+u1ri
+ur5ins
+3urlau
+urmen6
+ur8nan
+u1ro
+3ursac
+ur8sau
+ur8sei
+ur4sk
+3urtei
+u1ru
+uru5i6
+uru6r
+u1ry
+ur2za
+ur6zä
+ur5ä6m
+u5rö
+u1rü
+urück3
+u1sa
+usa4gi
+u2s1ar
+u2s1au
+u8schec
+usch5wi
+u2s1ei
+use8kel
+u8sl
+u4st3a4b
+us3tau
+u2s1uf
+u8surn
+ut1ac
+u1tal
+uta8m
+u1tan
+ut1ar
+u1tas
+ut1au
+u1te
+u8teic
+u4tent
+u8terf
+u6terin
+u4t3hei
+ut5ho
+ut1hu
+u1ti
+utine5
+uti6q
+u1to
+uto5c
+u1tr
+ut1sa
+ut1s6p
+ut6stro
+u1tu
+utz5w
+u1u
+u1v
+uve5n
+uve3r4ä
+u1w
+u1xe
+u5ya
+uy5e6
+u1yi
+u2z1eh
+u8zerh
+u5ö
+uße6n
+ußen5e
+8vanb
+6vang
+6varb
+var8d
+va6t5a
+va8tei
+va2t1r
+2v1b
+6v5c
+6vd
+1ve
+6ve5g6
+ver1
+ver5b
+verb8l
+ve2re2
+verg8
+ve2ru8
+ve1s
+ve2s3p
+ve3xe
+2v1f
+2v1g
+6v5h
+vi6el
+vie6w5
+vi1g4
+vi8leh
+vil6le.
+8vint
+vi1ru
+vi1tr
+2v1k
+2v1l
+2v1m
+4v5n
+8vo8f
+voi6le
+vol8lend
+vol8li
+v2or1
+vo2re
+vo8rin
+vo2ro
+2v1p
+8vra
+v6re
+2v2s
+2v1t
+2v1v
+4v3w
+2v1z
+waffe8
+wa6g5n
+1wah
+wah8n
+wa5la
+wal8din
+wal6ta
+wan4dr
+5ware
+wa8ru
+war4za
+1was
+w5c
+w1d
+5wech
+we6fl
+1weg
+we8geng
+weg5h
+weg3l
+we2g1r
+weh6r5er
+5weise
+weit3r
+wel2t
+welt3r
+we6rat
+8werc
+5werdu
+wer4fl
+5werk.
+wer4ka
+wer8ku
+wer4ta
+wer8term
+we2sp
+we8s4tend
+we8str
+we8stö
+wet8ta
+wich6s5t
+1wid
+wi2dr
+wiede4
+wieder5
+wik6
+wim6ma
+win4d3r
+5wirt
+wisch5l
+1wj
+6wk
+2w1l
+8w1n
+wo1c
+woche6
+wol6f
+wor6t5r
+6ws2
+w1sk
+6w5t
+5wunde.
+wun6gr
+wu1sc
+wu2t1
+6w5w
+wy5a
+wärme5
+wä1sc
+1xag
+x1ak
+x3a4men
+8xamt
+x1an
+8x1b
+x1c
+1xe.
+x3e4g
+1xen
+xe1ro
+x1erz
+1xes
+8xf
+x1g
+8x1h
+1xi
+8xid
+xi8so
+4xiste
+x1k
+6x1l
+x1m
+8xn
+1xo
+8x5o6d
+8x3p2
+x1r
+x1s6
+8x1t
+x6tak
+x8terf
+x2t1h
+1xu
+xu1e
+x5ul
+6x3w
+x1z
+5ya.
+y5an.
+y5ank
+y1b
+y1c
+y6cha
+y4chia
+y1d
+yen6n
+y5ern
+y1g
+y5h
+y5in
+y1j
+y1k2
+y1lak
+yl1al
+yla8m
+y5lax
+y1le
+y1lo
+y5lu
+y8mn
+ym1p2
+y3mu
+y1na
+yno2d
+yn1t
+y1on.
+y1o4p
+y5ou
+ypo1
+y1pr
+y8ps
+y1r
+yri3e
+yr1r2
+ys5iat
+ys8ty
+y1t
+y3w
+y1z
+yä8m
+z5a6b
+zab5l
+8za6d
+1zah
+za5is
+4z3ak
+6z1am
+5zange.
+8zanl
+2z1ara
+6z5as
+z5auf
+3zaun
+2z1b
+6z1c
+6z1d
+1ze
+ze4dik
+4z3eff
+8zein
+zei4ta
+zei8ters
+ze6la
+ze8lec
+zel8th
+4zemp
+6z5engel
+zen8zin
+8zergä
+zer8i
+ze1ro
+zers8
+zerta8
+zer8tab
+zer8tag
+8zerz
+ze8ste
+zeu6gr
+2z1ex
+2z1f8
+z1g
+4z1h
+1zi
+zi1en
+zi5es.
+4z3imp
+zi1na
+6z5inf
+6z5inni
+zin6s5er
+8zinsuf
+zist5r
+zi5th
+zi1tr
+6z1j
+2z1k
+2z1l
+2z1m
+6z1n
+1zo
+zo6gl
+4z3oh
+zo1on
+zor6na8
+4z1p
+z5q
+6z1r
+2z1s8
+2z1t
+z4t3end
+z4t3hei
+z8thi
+1zu
+zu3al
+zu1b4
+zu1f2
+6z5uhr
+zun2a
+8zunem
+zunf8
+8zungl
+zu1o
+zup8fi
+zu1s8
+zu1z
+2z1v
+zw8
+z1wal
+5zweck
+zwei3s
+z1wel
+z1wer
+z6werg
+8z5wes
+1zwi
+zwi1s
+6z1wo
+1zy
+2z1z
+zz8a
+zzi1s
+1zä
+1zö
+6zöl.
+zö1le
+1zü
+2z1ü2b
+ä1a6
+äb1l
+ä1che
+ä3chi
+äch8sc
+äch8sp
+ä5chu
+äck5a
+äd1a
+äd5era
+ä6d5ia
+ä1e
+ä5fa
+äf1l
+äft6s
+äg1h
+äg3le
+ä6g5nan
+äg5str
+ä1he
+ä1hi
+äh1le
+äh5ne
+1ähnl
+äh1re
+äh5ri
+äh1ru
+ä1hu
+äh1w
+6äi
+ä1isc
+ä6ische
+ä5ism
+ä5j
+ä1k
+äl1c
+ä1le
+ä8lei
+äl6schl
+ämi1e
+äm8n
+äm8s
+ä5na
+5änderu
+äne5i8
+äng3l
+änk5l
+ä1no
+än6s5c
+ä1pa
+äp6s5c
+3äq
+är1c
+ä1re
+äre8m
+5ärgern
+är6gl
+ä1ri
+3ärmel
+ä1ro
+ärt6s5
+ä1ru
+3ärztl
+ä5rö
+ä6s5chen
+äsen8s
+äs1th
+äta8b
+ä1te
+äteri4
+äter5it
+ä6thy
+ä1ti
+3ätk
+ä1to
+ät8schl
+äts1p
+ä5tu
+äub1l
+äu1e
+1äug
+äu8ga
+äu5i
+ä1um.
+ä1us.
+1äuß
+ä1z
+ö1b
+ö1che
+ö5chi
+öch8s2tei
+öch8str
+öcht6
+5ö6dem
+5öffn
+ö1he
+öh1l8
+öh1re
+ö1hu
+ö1is
+ö1ke
+1ö2ko
+1öl.
+öl6k5l
+öl8pl
+ö1mu
+ö5na
+önig6s3
+ö1no
+ö5o6t
+öpf3l
+öp6s5c
+ö1re
+ör8gli
+ö1ri
+ör8tr
+ö1ru
+5österr
+ö1te
+ö5th
+ö1ti
+ö1tu
+ö1v
+ö1w
+öwe8
+ö2z
+üb6e2
+3ü4ber1
+üb1l
+üb1r
+5ü2bu
+ü1che
+ü1chi
+ü8ch3l
+üch6s5c
+ü8ck
+ück1a
+ück5ers
+üd1a2
+ü6deu
+üdi8t
+ü2d1o4
+üd5s6
+üge4l5a
+üg1l
+üh5a
+ü1he
+ü8heh
+ü6h5erk
+üh1le
+üh1re
+üh1ru
+ü1hu
+üh1w
+ü3k
+ü1le
+ül4l5a
+ül8lo
+ül4ps
+ül6s5c
+ü1lu
+ün8da
+ün8fei
+ünk5l
+ün8za
+ün6zw
+ü5pi
+ü1re
+ü8rei
+ür8fl
+ür8fr
+ür8geng
+ü1ri
+ü1ro
+ür8sta
+ü1ru
+üse8n
+ü8sta
+ü8stes
+ü3ta
+ü1te
+ü1ti
+üt8tr
+ü1tu
+üt8zei
+ü1v
+ß1a8
+5ßa.
+ß8as
+ß1b8
+ß1c
+ß1d
+1ße
+ß5ec
+8ße8g
+8ße8h
+2ß1ei
+8ßem
+ß1f8
+ß1g
+ß1h
+1ßi
+ß1k
+ß1l
+ß1m
+ß1n
+ß1o
+ß1p8
+ß5q
+ß1r
+ß1s2
+ßst8
+ß1ta
+ß1te
+ßt3hei
+ß1ti
+ß5to
+ß1tr
+1ßu8
+6ß5um
+ß1v
+ß1w
+ß1z
+2s1ta.
+i2s1tal
+2s1tani
+2s1tan.
+fe2s1ta
+ta2s1ta
+te2s1ta
+nd2ste
+ve2ste
+3s2tec
+4s3techn
+3s2teg
+3s2teh
+3s2tein
+3s2teig
+3s2teif
+3s2tell
+3s2telz
+a4s3tel
+3s2temm
+3s2temp
+3s2tep
+s3s2ter
+t3s2tern
+3s2teue
+6s4teuro
+bs2ti
+te2s3ti
+ve2sti
+3s2tic
+3s2tieb
+3s2tieg
+3s2tif
+3s2til
+3s2tim
+3s2tink
+3s2titu
+a2s1to
+gu2s1to
+ku2s1to
+i2s1tol
+i2s1tor
+ve2s1to
+2s1tung
+2s7tus
+o2s1tul
+aus3s4
+ens3s4
+gs3s4
+.mis2s1
+s2s1b8
+s2s3chen
+s2s3d
+s2s5ec
+2s2s1ei
+s2s3f
+s2s1g
+s2s3h
+s2s3k
+s2s3l
+s2s3m
+s2s3n
+s2s3p8
+s2s5q
+s2s3r
+s2s3s2
+sss2t8
+as2s3te
+is2s3te
+us2s3te
+üs2s3te
+s2st3hei
+s2s3ti
+s2s1to
+s2s1tr
+6ss5um
+s2s3v
+s2s3w
+s2s3z
+1cker.
+1ckert
+1ckad
+1cke.
+1ckel
+1cken
+4ck1ent
+1ckere
+1ckern
+1ckeru
+1ckie
+1ckig
+1ckun
}
% end pattern data
diff --git a/tex/context/patterns/lang-deo.pat b/tex/context/patterns/lang-deo.pat
index c69be8958..dfc871d68 100644
--- a/tex/context/patterns/lang-deo.pat
+++ b/tex/context/patterns/lang-deo.pat
@@ -1675,6 +1675,4080 @@ fä1c
8färm
6fäug
fä8ß
+föde3
+8föf
+3för
+1fü
+fün4f3u
+1ga
+ga6bl
+6gabw
+8gabz
+g3a4der
+ga8ho
+ga5isc
+4gak
+ga1la
+6g5amt
+ga1na
+gan5erb
+gan6g5a
+ga5nj
+6ganl
+8gansc
+6garb
+2g1arc
+2g1arm
+ga5ro
+6g3arti
+ga8sa
+ga8sc
+ga6stre
+2g1atm
+6g5auf
+gau5fr
+g5aus
+2g1b
+g5c
+6gd
+g1da
+1ge
+ge1a2
+ge6an
+ge8at.
+ge1e2
+ge6es
+gef2
+8geff
+ge1g2l
+ge1im
+4g3eise
+geist5r
+gel8bra
+gelt8s
+ge5lö
+ge8nin
+gen3k
+6g5entf
+ge3nä
+ge1or
+ge1ra
+ge6rab
+ger8au
+8gerhö
+ger8ins
+ge1ro
+6g5erz.
+ge1rä
+ge1rü
+ge1s
+ges2p
+ge5unt
+4g3ex3
+2g1f8
+2g1g
+g1ha
+6g1hei
+5ghel.
+g5henn
+6g1hi
+g1ho
+1ghr
+g1hö
+1gi
+gi5la
+gi8me.
+gi1na
+4g3ins
+gi3str
+g1j
+2g1k
+8gl.
+1glad
+g5lag
+glan4z3
+1glas
+6glass
+5glaub
+g3lauf
+1gle.
+g5leb
+3gleic
+g3lein
+5gleis
+1glem
+2gler
+8g3leu
+gli8a
+g2lie
+3glied
+1g2lik
+1g2lim
+g6lio
+1gloa
+5glom
+1glon
+1glop
+g1los
+g4loss
+g5luf
+1g2ly
+1glü
+2g1m
+gn8
+6gn.
+1gna
+8gnach
+2gnah
+g1nas
+g8neu
+g2nie
+g3nis
+1gno
+8gnot
+1go
+goe1
+8gof
+2gog
+5gogr
+6g5oh
+goni5e
+6gonist
+go1ra
+8gord
+2g1p2
+g1q
+1gr4
+g5rahm
+gra8m
+gra4s3t
+6g1rec
+gre6ge
+4g3reic
+g5reit
+8grenn
+gri4e
+g5riem
+5grif
+2grig
+g5ring
+6groh
+2grot
+gro6ß
+4grut
+2gs
+gs1ab
+g5sah
+gs1ak
+gs1an
+gs8and
+gs1ar
+gs1au
+g1sc
+gs1ef
+g5seil
+gs5ein
+g2s1er
+gs1in
+g2s1o
+gso2r
+gs1pr
+g2s1u
+2g1t
+g3te
+g2t1h
+1gu
+gu5as
+gu2e
+2gue.
+6gued
+4g3uh
+8gums
+6g5unt
+gu1s
+gut3h
+gu2tu
+4g1v
+2g1w
+gy1n
+g1z
+1gä
+8gä8m
+6gärm
+1gö
+1gü
+6güb
+1haa
+hab8r
+ha8del
+hade4n
+8hae
+ha5el.
+haf6tr
+2hal.
+ha1la
+hal4b5a
+6hale
+8han.
+ha1na
+han6dr
+han6ge.
+2hani
+h5anth
+6hanz
+6harb
+h3arbe
+h3arme
+ha5ro
+ha2t1h
+h1atm
+hau6san
+ha8ß
+h1b2
+h1c
+h1d
+he2bl
+he3cho
+h3echt
+he5d6s
+5heft
+h5e6he.
+hei8ds
+h1eif
+2hein
+he3ism
+he5ist.
+heit8s3
+hek6ta
+hel8lau
+8helt
+he6mer
+1hemm
+6h1emp
+hen5end
+hen5klo
+hen6tri
+he2nu
+8heo
+he8q
+her3ab
+he5rak
+her3an
+4herap
+her3au
+h3erbi
+he1ro
+he8ro8b
+he4r3um
+her6z5er
+he4spe
+he1st
+heta6
+het5am
+he5th
+heu3sc
+he1xa
+hey5e
+h1f2
+h1g
+hgol8
+h1h
+h1iat
+hie6r5i
+hi5kt
+hil1a2
+hil4fr
+hi5nak
+hin4ta
+hi2nu
+hi5ob
+hirn5e
+hir6ner
+hi1sp
+hi1th
+hi5tr
+5hitz
+h1j
+h6jo
+h1k2
+hlabb4
+hla4ga
+hla6gr
+h5lai
+hl8am
+h1las
+h1laß
+hl1c
+h1led
+h3lein
+h5ler.
+h2lif
+h2lim
+h8linf
+hl5int
+h2lip
+h2lit
+h4lor
+h3lose
+h1läs
+hme5e
+h2nee
+h2nei
+hn3eig
+h2nel
+hne8n
+hne4p3f
+hn8erz
+h6netz
+h2nip
+h2nit
+h1nol
+hn5sp
+h2nuc
+h2nud
+h2nul
+hoch1
+1hoh
+hoh8lei
+2hoi
+ho4l3ar
+1holz
+h2on
+ho1ra
+6horg
+5horn.
+ho3sl
+hos1p
+ho4spi
+h1p
+hpi6
+h1q
+6hr
+h1rai
+h8rank
+h5raum
+hr1c
+hrcre8
+h1red
+h3reg
+h8rei.
+h4r3erb
+h8rert
+hrg2
+h1ric
+hr5ins
+h2rom
+hr6t5erl
+hr2t1h
+hr6t5ra
+hr8tri
+h6rum
+hr1z
+hs3ach
+h6s5amt
+h1sc
+h6s5ec
+h6s5erl
+hs8erle
+h4sob
+h1sp
+h8spaß
+h8spel
+hs6po
+h4spun
+h1str
+h4s3tum
+hs3und
+h1sü
+h5ta.
+h5tab
+ht3ac
+ht1ak
+ht3ang
+h5tanz
+ht1ar
+ht1at
+h5taub
+h1te
+h2t1ec
+ht3eff
+ht3ehe
+h4t3eif
+h8teim
+h4t3ein
+ht3eis
+h6temp
+h8tentf
+hte8ren
+h6terfü
+h8tergr
+h4t3erh
+h6t5ersc
+h8terst
+h8tese
+h8tess
+h2t1eu
+h4t3ex
+ht1he
+ht5hu
+h1ti
+ht5rak
+hts3ah
+ht1sc
+ht6sex
+ht8sk
+ht8so
+h1tu
+htz8
+h5tüm
+hub5l
+hu6b5r
+huh1l
+h5uhr.
+huld5a6
+hu8lent
+hu8lä
+h5up.
+h1v
+h5weib
+h3weis
+h1z
+hä8kl
+häl8s
+häma8tu8
+hä8sche.
+hät1s
+häu4s3c
+2hö.
+2höe
+8höi
+hö6s
+hös5c
+hühne6
+hül4s3t
+hütte8re
+i5adn
+i1af
+i5ak.
+i1al.
+i1al1a
+i1alb
+i1ald
+i5alei
+i1alf
+i1alg
+i3alh
+i1alk
+i1all
+i1alp
+i1alr
+i1als
+i1alt
+i1alv
+i5alw
+i3alz
+i1an.
+ia5na
+i3and
+ian8e
+ia8ne8b
+i1ang
+i3ank
+i5ann
+i1ant
+i1anz
+i6apo
+i1ar.
+ia6rab
+i5arr
+i1as.
+i1asm
+i1ass
+i5ast.
+i1at.
+i5ats
+i1au
+i5azz
+i6b5eig
+i6b5eis
+ib2le
+i4blis
+i6brig
+i6b5unt
+i6büb
+i1che
+ich5ei
+i6cherb
+i1chi
+ich5ins
+ich1l
+ich3m
+ich1n
+i1cho
+icht5an
+icht3r
+i1chu
+ich1w
+ick6s5te
+ic5l
+i1d
+id3arm
+3ideal
+ide8na
+3ideol
+ide5rö
+i6diot
+id5rec
+id1t
+ie1a
+ie6b5ar
+iebe4s3
+ie2bl
+ieb1r
+ie8bra
+ie4bre
+ie8bä
+ie2dr
+ie1e8
+ie6f5ad
+ief5f
+ie2f1l
+ie4fro
+ief1t
+i1ei
+ie4l3ec
+ie8lei
+ie4lek
+i3ell
+i1en.
+i1end
+ien6e
+i3enf
+i5enn
+ien6ne.
+i1enp
+i1enr
+i5ensa
+ien8stal
+i5env
+i1enz
+ie5o
+ier3a4b
+ie4rap
+i2ere
+ie4rec
+ie6r5ein
+ie6r5eis
+ier8er
+i3ern.
+ie8rum
+ie8rund
+ie6s5che
+ie6tau
+ie8tert
+ie5the
+ie6t5ri
+i1ett
+ie5un
+iex5
+2if
+i1fa
+if5ang
+i6fau
+if1fr
+if5lac
+i5f6lie
+i1fre
+ift5a
+if6t5r
+ig3art
+2ige
+i8gess
+ig5he
+i5gla
+ig2ni
+i5go
+ig3rot
+ig3s2p
+i1ha
+i8ham
+i8hans
+i1he
+i1hi
+ih1n
+ih1r
+i1hu
+i8hum
+ih1w
+8i1i
+ii2s
+ii2t
+i1j
+i1k
+i6kak
+i8kerz
+i6kes
+ik4ler
+i6k5unt
+2il
+i5lac
+i1lag
+il3ans
+i5las
+i1lau
+il6auf
+i1le
+ile8h
+i8lel
+il2fl
+il3ipp
+il6l5enn
+i1lo
+ilt8e
+i1lu
+i1lä
+i8mart
+imb2
+i8mele
+i8mid
+imme6l5a
+i1mu
+i1mä
+i5mö
+ina5he
+i1nat
+in1au
+inau8s
+8ind.
+in4d3an
+5index
+ind2r
+3indus
+i5nec
+i2n1ei
+i8nerw
+3infek
+1info
+5ingeni
+ing5s6o
+5inhab
+ini5er.
+5inj
+in8kät
+in8nan
+i1no
+inoi8d
+in3o4ku
+in5sau
+in1sp
+5inspe
+5instit
+5instru
+ins4ze
+5intere
+5interv
+in3the
+in5t2r
+i5ny
+inä2
+i1när
+in1äs
+inö8
+in5öd
+i1nös
+2io
+io1a8
+io1c
+iode4
+io2di
+ioi8
+i1ol.
+i1om.
+i1on.
+i5onb
+ion2s1
+i1ont
+i5ops
+i5o8pt
+i1or.
+i3oral
+io3rat
+i5orc
+i1os.
+i1ot.
+i1o8x
+2ip
+i1pa
+i1pi
+i1p2l
+i1pr
+i1q
+i1ra
+ir6bl
+i1re
+i1ri
+ir8me8d
+ir2m1o2
+ir8nak
+i1ro
+ir5rho
+ir6schl
+ir6sch5r
+i5rus
+i5ry
+i5rä
+i1sa
+i8samt
+i6sar
+i2s1au
+i8scheh
+i8schei
+isch5m
+isch3r
+ischä8
+is8ele
+ise3ra
+i4s3erh
+is3err
+isi6de
+i8sind
+is4kop
+ison5e
+is6por
+i8s5tum
+i5sty
+i5sö
+i1ta
+it5ab.
+i2t1a2m
+i8tax
+i1te
+i8tersc
+i1thi
+i1tho
+i5thr
+it8hä
+i1ti
+i8ti8d
+iti6kl
+itmen4
+i1to
+i8tof
+it3ran
+it3rau
+i1tri
+itri5o
+it1sc
+it2se
+it5spa
+it8tru
+i1tu
+it6z5erg
+it6z1w
+i1tä
+itä6r5e
+ität2
+itäts5
+i1tü
+i1u
+iu6r
+2i1v
+i6vad
+iva8tin
+i8vei
+i6v5ene
+i8verh
+i2vob
+i8vur
+i1w
+iwi2
+i5xa
+i1xe
+i1z
+ize8n
+i8zir
+i6z5w
+iä8m
+i1ä6r
+i5ät.
+i5äv
+i1ö8
+iü8
+i6ß5ers
+ja5la
+je2t3r
+6jm
+5jo
+jo5as
+jo1ra
+jou6l
+ju5cha
+jugen4
+jugend5
+jung5s6
+ju1s
+3jä
+1ka
+8kachs
+8kakz
+ka1la
+kal5d
+kam5t
+ka1na
+2kanl
+8kapf
+ka6pl
+ka5r6a
+6k3arbe
+ka1ro
+kar6p5f
+4k3arti
+8karz
+ka1rä
+kasi5e
+ka6teb
+kat8ta
+kauf6s
+kau3t2
+2k1b
+2k1c
+4k1d
+kehr6s
+kehrs5a
+8keic
+2k1eig
+6k5ein
+6k5eis
+ke6lar
+ke8leis
+ke8lo
+8kemp
+k5ente.
+k3entf
+8k5ents
+6kentz
+ke1ra
+k5erlau
+2k1f8
+2k1g
+2k1h
+ki5fl
+8kik
+king6s5
+6kinh
+ki5os
+ki5sp
+ki5th
+8ki8ö
+2k1k2
+kl8
+1kla
+8klac
+k5lager
+kle4br
+k3leib
+3kleid
+kle5isc
+4k3leit
+k3lek
+6k5ler.
+5klet
+2klic
+8klig
+k2lim
+k2lin
+5klip
+5klop
+k3lor
+1klä
+2k1m
+kmani5e
+kn8
+6kner
+k2ni
+knä8
+1k2o
+ko1a2
+ko6de.
+ko1i
+koi8t
+ko6min
+ko1op
+ko1or
+ko6pht
+ko3ra
+kor6d5er
+ko5ru
+ko5t6sc
+k3ou
+3kow
+6k5ox
+2k1p2
+k1q
+1kr8
+4k3rad
+2k1rec
+4k3reic
+kre5ie
+2krib
+6krig
+2krip
+6kroba
+2ks
+k1sa
+k6sab
+ksal8s
+k8samt
+k6san
+k1sc
+k2s1ex
+k5spat
+k5spe
+k8spil
+ks6por
+k1spr
+kst8
+k2s1uf
+2k1t
+kta8l
+kt5a6re
+k8tein
+kte8re
+k2t1h
+k8tinf
+kt3rec
+kt1s
+1ku
+ku1ch
+kuck8
+k3uhr
+ku5ie
+kum2s1
+kunfts5
+kun2s
+kunst3
+ku8rau
+ku4ro
+kurz1
+ku1st
+4kusti
+ku1ta
+ku8ß
+6k1v
+2k1w
+ky5n
+2k1z
+1kä
+kä4m
+4k3ämi
+käse5
+1kö
+kö1c
+kö1s
+1kü
+kü1c
+kür6sc
+kü1s
+1la.
+8labf
+8labh
+lab2r
+2l1abs
+lach3r
+la8dr
+5ladu
+8ladv
+6laff
+laf5t
+la2gn
+5laken
+8lamb
+la6mer
+5lampe.
+2l1amt
+la1na
+1land
+lan4d3a
+lan4d3r
+lan4gr
+8lanme
+6lann
+8lanw
+6lanä
+8lappa
+lap8pl
+lap6pr
+l8ar.
+la5ra
+lar4af
+la8rag
+la8ran
+la6r5a6s
+l3arbe
+la8rei
+6larm.
+la8sa
+la1sc
+la8sta
+lat8i
+6l5atm
+4lauss
+4lauto
+1law
+2lb
+l8bab
+l8bauf
+l8bede
+l4b3ins
+l5blo
+lbst5an
+lbst3e
+8lc
+l1che
+l8chert
+l1chi
+lch3m
+l5cho
+lch5w
+6ld
+l4d3ei
+ld1re
+l6düb
+le2bl
+le8bre
+lecht6s5
+led2r
+6leff
+le4gas
+1lehr
+lei6br
+le8inf
+8leinn
+5leistu
+4lektr
+le6l5ers
+lemo2
+8lemp
+l8en.
+8lends
+6lendun
+le8nend
+len8erw
+6l5ents
+4l3entw
+4lentz
+8lenzy
+8leoz
+6lepi
+le6pip
+8lepo
+1ler
+l6er.
+8lerbs
+6l5erde
+le8reis
+le8rend
+le4r3er
+4l3erg
+l8ergr
+6lerkl
+6l5erzie
+8lerö
+8lesel
+lesi5e
+le3sko
+le3tha
+let1s
+5leuc
+4leuro
+leu4s3t
+le5xe
+6lexp
+l1f
+2l1g
+lgend8
+l8gh
+lglie3
+lglied6
+6l1h
+1li
+li1ar
+li1as
+2lick
+li8dr
+li1en
+lien6n
+li8ers
+li8ert
+2ließ
+3lig
+li8ga8b
+li1g6n
+li1l8a
+8limb
+li1na
+4l3indu
+lings5
+4l3inh
+6linj
+link4s3
+4linkt
+2lint
+8linv
+lion5s6t
+4lipp
+5lipt
+4lisam
+livi5e
+6l1j
+6l1k
+l8keim
+l8kj
+lk2l
+lko8f
+lkor8
+lk2sa
+lk2se
+6ll
+l1la
+ll3a4be
+l8labt
+ll8anl
+ll1b
+ll1c
+ll1d6
+l1le
+l4l3eim
+l6l5eise
+ller3a
+l4leti
+l5lip
+l1lo
+ll3ort
+ll5ov
+ll6spr
+llte8
+l1lu
+ll3urg
+l1lä
+l5lü
+l6lüb
+2l1m
+l6m5o6d
+6ln
+l1na
+l1no
+8lobl
+lo6br
+3loch.
+l5o4fen
+5loge.
+5lohn
+4l3ohr
+1lok
+l2on
+4l3o4per
+lo1ra
+2l1ord
+6lorg
+4lort
+lo1ru
+1los.
+lo8sei
+3losig
+lo6ve
+lowi5
+6l1p
+lp2f
+l8pho
+l8pn
+lp4s3te
+l2pt
+l1q
+8l1r
+2ls
+l1sa
+l6sarm
+l1sc
+l8sec
+l6s5erg
+l4s3ers
+l8sh
+l5s6la
+l1sp
+ls4por
+ls2pu
+l1str
+l8suni
+l1sü
+2l1t
+lt5amp
+l4t3ein
+l5ten
+l6t5eng
+l6t5erp
+l4t3hei
+lt3her
+l2t1ho
+l6t5i6b
+lti1l
+l8trö
+lt1sc
+lt6ser
+lt4s3o
+lt5ums
+lu8br
+lu2dr
+lu1en8
+8lu8fe
+luft3a
+luf8tr
+lu6g5r
+2luh
+l1uhr
+lu5it
+5luk
+2l1umf
+2l1umw
+1lun
+6l5u6nio
+4l3unte
+lu5ol
+4lurg
+6lurs
+l3urt
+lu4sto
+lu3str
+lu6st5re
+lu8su
+lu6tal
+lu6t5e6g
+lu8terg
+lu3the
+lu6t5or
+lu2t1r
+lu6ß5
+l1v
+lve5r6u
+2l1w
+1ly
+lya6
+6lymp
+ly1no
+l8zess
+l8zo8f
+l3zwei
+lz5wu
+3länd
+lä5on
+lä6sc
+lät1s
+5läuf
+2läug
+läu6s5c
+lä5v
+l1öl
+1lös
+lö1ß6t
+6l1übe
+1ma
+8mabg
+ma5chan
+mad2
+ma5el
+4magg
+mag8n
+ma1la
+ma8lau
+mal5d
+8malde
+mali5e
+malu8
+ma8lut
+2m1amp
+3man
+mand2
+man3ds
+8mangr
+mani5o
+8m5anst
+6mappa
+4m3arbe
+mar8kr
+ma1r4o
+mar8schm
+3mas
+ma1sc
+ma1tö
+4m5auf
+ma5yo
+2m1b
+mb6r
+2m1c
+2m1d
+md6sä
+1me
+me1ch
+me5isc
+5meld
+mel8sa
+8memp
+me5nal
+men4dr
+men8schl
+men8schw
+8mentsp
+me1ra
+mer4gl
+me1ro
+3mes
+me6s5ei
+me1th
+me8ß
+2m1f6
+2m1g
+2m1h
+1mi
+mi1a
+mi6ale
+mi1la
+2m1imm
+mi1na
+mi5nü
+mi4s3an
+mit1h
+mi5t6ra
+3mitt
+mitta8
+mi6ß5
+6mj
+2m1k8
+2m1l
+2m1m
+m6mad
+m6m5ak
+m8menth
+m8mentw
+mme6ra
+m2mn
+mm5sp
+mm5ums
+mmut5s
+m8män
+m1n8
+m5ni
+1mo
+mo5ar
+mo4dr
+8mof
+mo8gal
+mo4kla
+mol5d
+m2on
+mon8do
+mo4n3od
+mont8a
+6m5ony
+mopa6
+mo1ra
+mor8d5a
+mo1sc
+mo1sp
+5mot
+moy5
+2mp
+m1pa
+mpfa6
+mpf3l
+mphe6
+m1pi
+mpin6
+m1pl
+mp2li
+m2plu
+mpo8ste
+m1pr
+mprä5
+mp8th
+mput6
+mpu5ts
+m1pö
+8m1q
+2m1r
+2ms
+ms5au
+m1sc
+msch4l
+ms6po
+m3spri
+m1str
+2m1t
+mt1ar
+m8tein
+m2t1h
+mt6se
+mt8sä
+mu5e
+6m5uh
+mumi1
+1mun
+mun6dr
+muse5e
+mu1ta
+2m1v
+mvol2
+mvoll3
+2m1w
+1my
+2m1z
+mä6kl
+1män
+mä1s
+mä5tr
+mäu4s3c
+3mäß
+möb2
+6möl
+1mü
+5mün
+3müt
+1na.
+n5ab.
+8nabn
+n1abs
+n1abz
+na6bä
+na2c
+nach3e
+3nacht
+1nae
+na5el
+n1afr
+1nag
+1n2ah
+na8ha
+na8ho
+1nai
+6nair
+na4kol
+n1akt
+nal1a
+8naly
+1nama
+na4mer
+na1mn
+n1amp
+8n1amt
+5nanc
+nan6ce
+n1and
+n6and.
+2n1ang
+1nani
+1nann
+n1ans
+8nanw
+5napf.
+1n2ar.
+na2ra
+2n1arc
+n8ard
+1nari
+n8ark
+6n1arm
+5n6ars
+2n1art
+n8arv
+6natm
+nat6s5e
+1naue
+4nauf
+n3aug
+5naui
+n5auk
+na5um
+6nausb
+6nauto
+1nav
+2nax
+3naz
+1naß
+n1b2
+nbau5s
+n1c
+nche5e
+nch5m
+2n1d
+nda8d
+n2d1ak
+nd5ans
+n2d1ei
+nde8lac
+ndel6sa
+n8derhi
+nde4se
+nde8stal
+n2dj
+ndnis5
+n6d5or6t
+nd3rec
+nd3rot
+nd8samt
+nd6sau
+ndt1h
+n8dumd
+1ne
+ne5as
+ne2bl
+6n5ebn
+2nec
+5neei
+ne5en
+ne1g4l
+2negy
+4n1ein
+8neis
+4n3e4lem
+8nemb
+2n1emp
+nen1a
+6n5energ
+nen3k
+8nentb
+4n3en3th
+8nentl
+8n5entn
+8n5ents
+ne1ra
+ne5r8al
+ne8ras
+8nerbi
+6n5erde.
+nere5i6d
+nerfor6
+6n5erhö
+8nerlö
+2n1err
+n8ers.
+6n5ertra
+2n1erz
+nesi3e
+net1h
+neu4ra
+neu5sc
+8neuß
+n1f
+nf5f
+nf2l
+nflei8
+nf5lin
+nft8st
+n8g5ac
+ng5d
+ng8en
+nge8ram
+ngg2
+ng1h
+n6glic
+ng3rip
+ng8ru
+ng2se4
+ng2si
+n2g1um
+n1gy
+n8gäl
+n1h
+nhe6r5e
+1ni
+ni1bl
+ni5chä
+ni8dee
+n6ie
+ni1en
+nie6s5te
+niet5h
+ni8etn
+4n3i6gel
+n6ik
+ni1la
+2n1imp
+ni5na
+2n1ind
+8ninf
+6n5inh
+ni8nit
+6n5inn
+2n1ins
+4n1int
+n6is
+ni3str
+ni1th
+ni1tr
+n1j
+n6ji
+n8kad
+nk5ans
+n1ke
+n8kerla
+n1ki
+nk5inh
+n5klö
+n1k2n
+n8k5not
+nk3rot
+n8krü
+nk5spo
+nk6t5r
+n8kuh
+n6küb
+n5l6
+nli4mi
+n1m
+nmen4s
+n1na
+n8nerg
+nni5o
+n1no
+nn4t3ak
+nnt1h
+nnu1e
+n1ny
+n1nä
+n1nö
+n1nü
+no5a
+no4b3la
+4n3obs
+2nobt
+noche8
+no6die
+no4dis
+no8ia
+no5isc
+6n5o6leu
+no4mal
+noni6er
+2n1onk
+n1ony
+4n3o4per
+6nopf
+6nopti
+no3ra
+no4ram
+nor6da
+4n1org
+2n1ort
+n6os
+no1st
+8nost.
+no8tan
+no8ter
+noty6pe
+6n5ox
+n1p2
+n1q
+n1r
+nrös3
+6ns
+n1sac
+ns3ang
+n1sc
+n8self
+n8s5erf
+n8serg
+n6serk
+ns5erw
+n8sint
+n1s2pe
+n1spr
+n6s5tat.
+n5s6te.
+n6stob
+n1str
+n1ta
+n4t3a4go
+nt5anh
+nt3ark
+nt3art
+n1te
+nt3eis
+nte5n6ar
+nte8nei
+nter3a
+nte6rei
+nt1ha
+nt6har
+n3ther
+nt5hie
+n3thus
+n1ti
+nti1c
+n8tinh
+nti1t
+ntlo6b
+ntmen8
+n1to
+nt3o4ti
+n1tr
+ntra5f
+ntra5ut
+nt8rea
+nt3rec
+nt8rep
+n4t3rin
+nt8rop
+n4t3rot
+n4trü
+nt1s
+nts6an
+nt2sk
+n1tu
+nt1z
+n1tä
+n1tö
+n8töl
+n1tü
+1nu
+nu1a
+nu5el
+nu5en
+4n1uhr
+nu5ie
+8numl
+6n5ums
+6n5umw
+2n1und
+6nuni
+6n5unr
+2n1unt
+2nup
+2nu6r
+n5uri
+nu3skr
+nu5ta
+n1v
+8n1w
+1nys
+n1za
+n6zab
+n2z1ar
+n6zaus
+nzi4ga
+n8zof
+n6z5unt
+n1zw
+n6zwir
+1näc
+5näe
+5näi
+n8äl
+nä6m
+nä6re
+n5ärz
+5näus
+n1öl
+1nöt
+n5öz
+5nü.
+6n1ü2b
+5nüß
+o5ab.
+oa2l
+o8ala
+o1a2m
+o1an
+ob1ac
+obe4ra
+o6berh
+5o4bers
+o4beru
+obe6ser
+1obj
+o1bl
+o2bli
+ob5sk
+3obst.
+ob8sta
+obst5re
+ob5sz
+o1che
+oche8b
+o8chec
+o3chi
+och1l
+och3m
+ocho8f
+o3chro
+och3to
+o3chu
+och1w
+o1d
+o2d1ag
+od2dr
+ode5i
+ode6n5e
+od1tr
+o5e6b
+o5e6der.
+oe8du
+o1ef
+o1e2l
+o1e2p
+o1er.
+o5e8x
+o1fa
+of8fan
+1offi
+of8fin
+of6f5la
+o5fla
+o1fr
+8o1g
+og2n
+o1ha
+o1he
+o6h5eis
+o1hi
+ohl1a
+oh1le
+oh4l3er
+5ohm.
+oh2ni
+o1ho
+oh1re
+oh1ru
+o1hu
+oh1w
+o1hy
+o1hä
+o5ia
+o1id.
+o8idi
+oi8dr
+o5ids
+o5isch.
+oiset6
+o1ism
+o3ist.
+o5i6tu
+o1j
+o1k
+ok2l
+ok3lau
+o8klä
+1okta
+o1la
+old5am
+old5r
+o1le
+ole5in
+ole1r
+ole3u
+ol6gl
+ol2kl
+olk4s1
+ol8lak
+ol8lauf.
+ol6lel
+ol8less
+o1lo
+ol1s
+ol6sk
+o1lu
+oly1e2
+5olym
+o2mab
+om6an
+o8mau
+ombe4
+o8merz
+om5sp
+o1mu
+o8munt
+o1mä
+o1mö
+o1na
+ona8m
+on1ax
+on8ent
+o6n5erb
+8oni
+oni5er.
+on1k
+on6n5a6b
+o1no
+ono1c
+o4nokt
+1ons
+onts8
+o1nä
+oo8f
+1oog
+oo2pe
+oo2sa
+o1pa
+3o4pera
+o3pfli
+opf3lo
+opf3r
+o1pi
+o1pl
+o2pli
+o5p6n
+op8pa
+op6pl
+o1pr
+o3p4ter
+1opti
+o1pä
+o5pö
+o1q
+o1ra.
+o3rad
+o8radd
+1oram
+o6rang
+o5ras
+o8rauf
+or5cha
+or4d3a4m
+or8dei
+or8deu
+1ordn
+or4dos
+o1re
+o5re.
+ore2h
+o8r5ein
+ore5isc
+or6enn
+or8fla
+or8fli
+1orga
+5orgel.
+or2gl
+o1ri
+5o6rient
+or8nan
+or8nä
+o1ro
+or1r2h
+or6t5an
+or8tau
+or8tere
+o1rus
+o1ry
+o1rä
+or1ü2
+o1sa
+osa3i
+6ose
+o8serk
+o1sk
+o6ske
+o6ski
+os2kl
+os2ko
+os2kr
+osni5e
+o2s1o2d
+o3s4per
+o4stam
+o6stau
+o3stra
+ost3re
+osu6
+o6s5ur
+o5s6ze
+o1ta
+ot3auf
+o6taus
+o1te
+o6terw
+o1th
+othe5u
+o2th1r
+o1ti
+o1to
+oto1a
+ot1re
+o1tri
+o1tro
+ot1sc
+o3tsu
+ot6t5erg
+ot2t3h
+ot2t5r
+ot8tö
+o1tu
+ou3e
+ouf1
+ou5f6l
+o5u6gr
+ou5ie
+ou6rar
+ou1t6a
+o1v
+o1wa
+o1we
+o6wer.
+o1wi
+owid6
+o1wo
+o5wu
+o1xe
+oy5al.
+oy1e
+oy1i
+o5yo
+o1z
+oza2r
+1o2zea
+ozo3is
+oö8
+oß5elt
+oß1t
+3paa
+pa6ce
+5pad
+pag2
+1pak
+pa1la
+pa8na8t
+pani5el
+pa4nor
+pan1s2
+1pap
+pap8s
+pa8rei
+par8kr
+paro8n
+par5o6ti
+part8e
+5partei
+3partn
+pas6sep
+pa4tha
+1pau
+6paug
+pau3sc
+p1b
+8p5c
+4p1d
+1pe
+4peic
+pe5isc
+2pek
+pen3k
+pen8to8
+p8er
+pe1ra
+pere6
+per5ea
+per5eb
+pe4rem
+2perr
+per8ran
+3pers
+4persi
+pe3rü
+pe4sta
+pet2s
+p2f1ec
+p4fei
+pf1f
+pf2l
+5pflanz
+pf8leg
+pf3lei
+2pft
+pf3ta
+p1g
+1ph
+2ph.
+2p1haf
+6phb
+8phd
+6p5heit
+ph5eme
+6phg
+phi6e
+8phk
+6phn
+p5holl
+pht2
+ph3tha
+4ph3the
+phu6
+6phz
+pi1en
+pi5err
+pi1la
+pi1na
+5pinse
+pioni8e
+1pis
+pi1s2k
+pi1th
+p1k
+pl8
+5pla
+p2lau
+4plei
+p3lein
+2pler
+6p5les
+2plig
+p6lik
+6p5ling
+p2liz
+plo8min
+6p1m
+p1n
+1p2o
+8poh
+5pol
+po8lan
+poly1
+po3ny
+po1ra
+2porn
+por4t3h
+po5rö
+5poti
+p1pa
+p6p5ei
+ppe6la
+pp5f
+p2p1h
+p1pi
+pp1l
+ppp6
+pp5ren
+pp1s
+p5pö
+pr6
+3preis
+1pres
+2p3rig
+5prinz
+1prob
+1prod
+5prog
+pro8pt
+pro6t5a
+prote5i
+8proß
+prä3l
+1präs
+präte4
+1prüf
+p5schl
+2pst
+1p2sy
+p1t
+p8to8d
+pt1s
+5p6ty
+1pu
+pu1b2
+2puc
+pu2dr
+puf8fr
+6p5uh
+pun8s
+pu8rei
+pu5s6h
+pu1ta
+p1v
+p3w
+5py
+py5l
+p1z
+pä6der
+p5ä6m
+pä8nu
+8pär
+pät5h
+pät1s
+qu6
+1qui
+8rabk
+ra6bla
+3rable
+ra2br
+r1abt
+6rabz
+ra4dan
+ra2dr
+5rafal
+ra4f3er
+ra5gla
+ra2g3n
+6raha
+ral5am
+5rald
+4ralg
+ra8lins
+2rall
+ral5t
+8ramei
+r3anal
+r6and
+ran8der
+ran4dr
+8ranf
+6ranga
+5rangi
+ran8gli
+r3angr
+rans5pa
+8ranw
+r8anz.
+ra5or
+6rapf
+ra5pl
+rap6s5er
+2r1arb
+1rarh
+r1arm
+ra5ro
+2r1art
+6r1arz
+ra8tei
+ra6t5he
+6ratl
+ra4t3ro
+r5atta
+raue4n
+6raus.
+r5austa
+rau8tel
+raut5s
+ray1
+r1b
+rb5lass
+r6bler
+rb4lie
+rbon6n
+r8brecht
+rb6s5tä
+r8ces
+r1che
+rch1l
+rch3m
+rch3re
+rch3tr
+rch1w
+8rd
+r1da
+r8dachs
+r8dap
+rda5ro
+rde5ins
+rdio5
+r8dir
+rd3ost
+r1dr
+r8drau
+1re.
+re1ak
+3reakt
+re3als
+re6am.
+re1as
+4reben
+re6bl
+rech5a
+r8edi
+re3er
+8reff
+3refl
+2reh
+5reha
+r4ei.
+reich6s5
+8reier
+6reign
+re5imp
+4r3eina
+6r3einb
+6reing
+6r5einn
+6reinr
+4r3eins
+r3eint
+reli3e
+8r5elt
+6rempf
+2remt
+ren5a6b
+ren8gl
+r3enni
+1reno
+5rente
+4r3enth
+8rentl
+4r3entw
+8rentz
+ren4zw
+re1on
+requi5
+1rer
+rer4bl
+6rerbs
+4r3erd
+8rerhö
+8rerkl
+4r3erla
+8rerlö
+4r3erns
+6r5ernä
+rer5o
+6r5erreg
+r5ertr
+r5erwec
+r5erö
+re2sa
+re8schm
+2ress
+re5u8ni
+6rewo
+2r1ex
+r1f
+r8ferd
+rf4lie
+8r1g
+r8gah
+rge4bl
+rge5na
+rgest4
+rg6ne
+r2gni2
+r8gob
+r4g3ret
+rg8sel
+r1h8
+r2hy
+5rhyt
+ri1ar
+ri5cha
+rid2g
+r2ie
+rieg4s5
+ri8ei
+ri1el
+ri6ele
+ri1en
+ri3er.
+ri5ers.
+ri6fan
+ri8fer
+ri8fr
+1r2ig
+ri8kn
+ri5la
+rimä8
+ri1na
+r8inde
+rin4ga
+rin6gr
+1rinn
+6rinner
+rino1
+r8insp
+4rinst
+ri1nä
+ri5o6ch
+ri1o2d
+ri3o6st
+2r1ir
+r2is
+ri3sko
+ri8spr
+ri8stü
+ri5sv
+r2it
+6r5i6tal
+ri5tr
+ri6ve.
+8r1j
+6rk
+r1ke
+rkehrs5
+r1ki
+r3klin
+r1k2n
+rk3str
+rk4t3an
+rk6to
+r6kuh
+rkä4s3t
+r1l
+r5li
+rline5a
+6r1m
+r6manl
+rma4p
+r4m3aph
+r8minf
+r8mob
+rm5sa
+2rn
+r1na
+rna8be
+r5ne
+rn2ei
+r6neif
+r6nex
+r6nh
+rn1k
+r1no
+r6n5oc
+rn1sp
+r1nä
+r1nü
+ro6bern
+6robs
+ro1ch
+3rock.
+ro5de
+ro1e
+4rofe
+ro8hert
+1rohr
+ro5id
+ro1in
+ro5isc
+6rolym
+r2on
+6roog
+ro6phan
+r3ort
+ro1s2p
+ro5s6w
+ro4tau
+ro1tr
+ro6ts
+5rout
+r1p
+rpe8re
+rp2f
+r2ps
+r2pt
+r1q
+2rr
+r1ra
+r1re
+rrer6
+rr6hos
+r5rhö
+r1ri
+r1ro
+rro8f
+rr8or
+rror5a
+r1ru
+r3ry
+r1rä
+r1rö
+r1rü
+2r1s
+r6sab
+r4sanf
+rse6e
+rse5na
+r2sh
+r6ska
+r6ski
+rs2kl
+r8sko
+r2sl
+rs2p
+r6stauf
+r8sterw
+r8stran
+rswi3d4
+r2sz
+2r1t
+rt3art
+r8taut
+r5tei
+rt5eige
+r8tepe
+r4t3erh
+r8terla
+r4t3hei
+r5t6hu
+r4t3int
+rt5reif
+rt1sc
+rt6ser
+rt6s5o
+rt6s5u
+rt5und
+r8turt
+rube6
+ru1en
+1r4uf
+ruf4st
+ru1ie
+2r1umg
+2r1uml
+2rums
+run8der
+run4d5r
+6rundz
+6runf
+8runs
+2r1unt
+2r1ur
+r6us
+ru6sta
+ru3str
+ru6tr
+1ruts
+r1v
+rven1
+rvi2c
+r1w
+r1x
+r1za
+rz5ac
+r6z5al
+r8z1ar
+r8zerd
+r6z5erf
+rz8erh
+rz4t3h
+r8zum
+rä4ste
+räu8sc
+r1öf
+5röhr
+rö5le
+3röll
+5römis
+r1ör
+rö2sc
+3rümp
+1sa.
+1saa
+s3a4ben
+sa2bl
+2s1abs
+6s1abt
+6sabw
+3sack.
+6s3a4der
+1saf
+sa1fa
+4s1aff
+sa5fr
+1sag
+1sai
+sa1i2k1
+4s1akt
+1sal
+sa1la
+4s3alpi
+6salter
+salz3a
+1sam
+s5anb
+san2c
+1sand
+s5angeh
+6sanl
+2s1ans
+6s3antr
+8s1anw
+s1ap
+s6aph
+8sapo
+sap5p6
+s8ar.
+2s1arb
+3sarg
+s1arm
+sa5ro
+2s1art
+6s1arz
+1sas
+1sat
+sat8a
+2s1atl
+sa8tom
+3s8aue
+s5auff
+sau5i
+s6aur
+2s1aus
+5s6ause
+2s1b2
+2sca
+s4ce
+8sch.
+3scha.
+5schade
+3schaf
+3schal
+sch5ame
+8schanc
+8schb
+1sche
+6schef
+8schex
+2schf
+2schg
+2schh
+1schi
+2schk
+5schlag
+5schlu
+6schmäß
+6schnaß
+1scho
+6schord
+6schp
+3schri
+8schric
+8schrig
+8schrou
+6schs
+2scht
+sch3ta
+sch3tr
+1schu
+8schunt
+6schv
+2schz
+5schö
+5schü
+2sco
+scre6
+6scu
+2s1d
+1se
+se5an
+se1ap
+se6ben
+se5ec
+see5i6g
+se3erl
+8seff
+se6han
+se8hi
+se8hö
+6s5eid.
+2s1eig
+s8eil
+5sein.
+sei5n6e
+6s5einh
+3s8eit
+3sel.
+se4lar
+selb4
+6s3e4lem
+se8lerl
+2s1emp
+sen3ac
+se5nec
+6s5ents
+4sentz
+s8er.
+se8reim
+ser5inn
+8sermä
+8s5erzi
+6seröf
+se1um
+8sexa
+6sexp
+2s1f2
+sfal8ler
+2s3g2
+sge5b2
+s1h
+s8hew
+5s6hip
+5s4hop
+1si
+2siat
+si1b
+sicht6s
+6s5i6dee
+siege6s5
+si1en
+si5err
+si1f2
+si1g2n
+si6g5r
+si8kau
+sik1i
+si4kin
+si2kl
+si8kü
+si1la
+sil6br
+si1na
+2s1inf
+sin5gh
+2s1inh
+sinne6s5
+2s1ins
+si5ru
+si5str
+4s1j
+s1k2
+6sk.
+2skau
+skel6c
+skelch5
+s6kele
+1s2ki.
+3s4kin.
+s6kiz
+s8kj
+6skn
+2skow
+3skrib
+3skrip
+2sku
+8skü
+s1l
+s8lal
+slei3t
+s4low
+2s1m
+s1n
+6sna
+6snot
+1so
+so1ch
+2s1odo
+so4dor
+6s5o4fen
+solo3
+s2on
+so5of
+4sope
+so1ra
+2s1ord
+4sorga
+sou5c
+so3un
+4s3ox
+sp2
+8spaa
+5spal
+1span
+2spap
+s2pec
+s4peis
+1spek
+s6perg
+4spers
+s6pes
+2s1pf
+8sphi
+1s2phä
+1spi
+spi4e
+6s5pig
+6spinse
+2spis
+2spla
+2spol
+5s6pom
+6s5pos
+6spoti
+1spra
+3s8prec
+6spreis
+5spring
+6sprob
+1spru
+s2pul
+1s2pur
+6spy
+5spän
+1spü
+s1q
+2s1r
+2s1s2
+sse8nu
+ssini6s
+ssoi6r
+2st.
+1sta
+4stafe
+2stag
+sta3la
+6stale
+4stalg
+8stalk
+8stamt
+6st5anf
+4stans
+6stanw
+6starb
+sta4te
+6staus
+2stb
+6stc
+6std
+1ste
+4steil
+3s2tel
+st3elb
+8stemb
+6steppi
+8stese
+8stesse
+6stf
+2stg
+2sth
+st1ha
+st3hei
+s8t1hi
+st1ho
+st5hu
+1sti
+sti4el
+4stigm
+sti3na
+6stind
+4stinf
+sti8r
+2stk
+2stl
+2stm
+1sto
+6stoll.
+4st3ope
+6stopf.
+6stord
+6stp
+5stra.
+4strai
+3s4tral
+6s5traum
+3straß
+3strec
+6s3tref
+8streib
+5streif
+6streno
+6stres
+6strev
+5s6tria
+6strig
+5strik
+8strisi
+3s4troa
+s8troma
+st5rose
+4struf
+3strum
+6sträg
+2st1s6
+2stt
+1stu
+stu5a
+4stuc
+2stue
+8stun.
+2stv
+2stw
+s2tyl
+6stz
+1stä
+8stäg
+1stö
+1stü
+8stüch
+4stür.
+1su
+su2b1
+3suc
+su1e
+su2fe
+su8mar
+6sumfa
+8sumk
+2s1unt
+sup1p2
+6s5u6ran
+6surte
+2s1v
+2s1w
+1sy
+8syl.
+sy5la
+syn1
+sy2na
+syne4
+s1z
+s4zend
+5s6zene.
+8szu
+1sä
+6s5änd
+6säugi
+6säuß
+5söm
+2s1ü2b
+1süc
+sü8di
+1sün
+5süß
+taats3
+4tab.
+taba6k
+ta8ban
+tab2l
+ta6bre
+4tabs
+t3absc
+8tabz
+6t3acht
+ta6der
+6tadr
+tad6s
+tad2t
+1tafe4
+1tag
+ta6ga6
+ta8gei
+tage4s
+tag6s5t
+tah8
+tahl3
+tai6ne.
+ta5ir.
+tak8ta
+tal3au
+1tale
+ta8leng
+tal5ert
+6t5a6mer
+6tamp
+tampe6
+2t1amt
+tan5d6a
+tan8dr
+tands5a
+tani5e
+6tanl
+2tanr
+t3ans
+8t5antr
+tanu6
+t5anw
+8tanwa
+tan8zw
+ta8rau
+6tarbe
+1tari
+2tark
+2t1arm
+ta1ro
+2tart
+t3arti
+6tarz
+ta1sc
+ta6sien
+ta8stem
+ta8sto
+t5aufb
+4taufn
+8taus.
+5tause
+8tausf
+6tausg
+t5ausl
+2t1b2
+2t1c
+t6chu
+2t1d
+te2am
+tea4s
+te8ben
+5techn
+4teff
+te4g3re
+te6hau
+2tehe
+te4hel
+2t1ehr
+te5id.
+teig5l
+6teign
+tei8gr
+1teil
+4teinh
+t5einhe
+4teis
+t5eisen
+8teiw
+te8lam
+te4lar
+4telek
+8telem
+te6man
+te6n5ag
+ten8erw
+ten5k
+tens4p
+ten8tro
+4t3entw
+8tentz
+te6pli
+5teppi
+ter5a6b
+te3ral
+ter5au
+8terbar
+t5erbe.
+6terben
+8terbs
+4t3erbt
+t5erde.
+ter5ebe
+ter5ein
+te8rers
+terf4
+8terhö
+6terklä
+ter8nor
+ter6re.
+t8erscha
+t5e6sel
+te8stau
+t3euro
+te1xa
+tex3e
+8texp
+tex6ta
+2t1f2
+2t1g2
+2th.
+th6a
+5tha.
+2thaa
+6t1hab
+6t5haf
+t5hah
+8thak
+3thal.
+6thals
+6t3hand
+2t1hau
+1the.
+3t4hea
+t1heb
+t5heil
+t3heit
+t3helf
+1theo
+5therap
+5therf
+6t5herz
+1thes
+1thet
+5thi.
+2t1hil
+t3him
+8thir
+3this
+t5hj
+2th1l
+2th1m
+th1n
+t5hob
+t5hof
+4tholz
+6thopti
+1thr6
+4ths
+t1hum
+1thy
+4t1hä
+2t1hö
+t1hü
+ti1a2m
+ti1b
+tie6fer
+ti1en
+ti8gerz
+tig3l
+ti8kin
+ti5lat
+1tilg
+t1ind
+tin4k3l
+ti3spa
+ti5str
+5tite
+ti5tr
+ti8vel
+ti8vr
+2t1j
+2t1k2
+2t1l
+tl8a
+2t1m8
+2t1n
+3tobe
+8tobj
+to3cha
+5tocht
+8tock
+tode4
+to8del
+to8du
+to1e
+6t5o6fen
+to1in
+toi6r
+5toll.
+to8mene
+t2ons
+2t1ony
+to4per
+5topf.
+6topt
+to1ra
+to1s
+to6ska
+tos2l
+2toti
+to1tr
+t8ou
+2t1p2
+6t1q
+tr6
+tra5cha
+tra8far
+traf5t
+1trag
+tra6gl
+tra6gr
+t3rahm
+1trai
+t6rans
+tra3sc
+tra6st
+3traue
+t4re.
+2trec
+t3rech
+t8reck
+6t1red
+t8ree
+4t1reg
+3treib
+4treif
+8t3reis
+8trepo
+tre6t5r
+t3rev
+4t3rez
+1trib
+t6rick
+tri6er
+2trig
+t8rink
+tri6o5d
+trizi5
+tro1a
+3troc
+trocke6
+troi8d
+tro8man.
+tro3ny
+5tropf
+6t5rosa
+t5roß
+5trub
+5trup
+trut5
+1träg
+6t1röh
+5trüb
+trü3bu
+t1rüc
+t1rüs
+2ts
+ts1ab
+t1sac
+tsa8d
+ts1ak
+t6s5alt
+ts1an
+ts1ar
+ts3auf
+t3schr
+t5schä
+tse6e
+tsee5i
+tsein6s
+ts3ent
+ts1er
+t8serf
+t4serk
+t8sh
+5t6sik
+t4s3int
+ts5ort.
+t5s6por
+t6sprei
+t1st
+t6s5tanz
+ts1th
+t6stit
+t4s3tor
+1t2sua
+t2s1uf
+t8sum.
+t2s1u8n
+t2s1ur
+2t1t
+tt5eif
+tte6sa
+tt1ha
+tt8ret
+tt1sc
+tt8ser
+tt5s6z
+1tuc
+tuch5a
+1tu1e
+6tuh
+t5uhr
+tu1i
+tu6it
+1tumh
+6t5umr
+1tums
+8tumt
+6tund
+6tunf
+2t1unt
+tu5ra
+tu6rau
+tu6re.
+tu4r3er
+2t1v
+2t1w
+1ty1
+ty6a
+ty8la
+8tym
+6ty6o
+2tz
+tz5al
+tz1an
+tz1ar
+t8zec
+tzeh6
+tzehn5
+t6z5ei.
+t6zor
+t4z3um
+t6zäu
+5täg
+6täh
+t5ält
+t8än
+täre8
+8tä8st
+6täuß
+t5öffen
+8tö8k
+1tön
+4tüb
+t6ü5ber.
+5tüch
+1tür.
+u3al.
+u5alb
+u5alf
+u3alh
+u5alk
+u3alp
+u3an.
+ua5na
+u3and
+u5ans
+u5ar.
+ua6th
+u1au
+ua1y
+u2bab
+ubi5er.
+u6b5rit
+ubs2k
+u5bö
+u8büb
+2uc
+u1che
+u6ch5ec
+u1chi
+uch1l
+uch3m
+uch5n
+uch1r
+uch5to
+ucht5re
+u1chu
+uch1w
+uck1a
+uck5in
+u1d
+ud4a
+u1ei
+u6ela
+uene8
+u6ep
+u1er
+uer1a
+ue8rerl
+uer5o
+u8esc
+u2est
+u8ev
+u1fa
+u2f1ei
+u4f3ent
+u8ferh
+uf1fr
+uf1l
+uf1ra
+uf1re
+uf1rä
+uf1rü
+uf1s2p
+uf1st
+uft1s
+u8gabt
+u8gad
+u6gap
+ugeb8
+u8gn
+ugo3s4
+u1ha
+u1he
+u1hi
+uh1le
+u1ho
+uh1re
+u1hu
+uh1w
+u1hä
+u1hö
+6ui
+ui5en
+u1ig
+u3ins
+uin8tes
+u5isch.
+u1j
+6uk
+u1ke
+u1ki
+u1kl
+u8klu
+u1k6n
+u5ky
+u1la
+uld8se
+u1le
+ul8lac
+ul6lau
+ul6le6l
+ul6lo
+ulni8
+u1lo
+ulo6i
+ult6a
+ult8e
+u1lu
+ul2vr
+u1lä
+u1lö
+3umfan
+5umlau
+umo8f
+um8pho
+u1mu
+umu8s
+u5mö
+u1n1a
+un2al
+un6at
+unau2
+6und.
+5undein
+un4d3um
+3undzw
+undü8
+un8düb
+une2b
+un1ec
+une2h
+un3eis
+3unfal
+1unfä
+5ungea
+3unglü
+ung2s1
+un8gä
+1u2nif
+un4it
+un8kro
+unk5s
+u1no
+unpa2
+uns2p
+unvol4
+unvoll5
+u5os.
+u1pa
+u1pi
+u1p2l
+u1pr
+up4s3t
+up2t1a
+u1q
+u1ra
+ur5abs
+ura8d
+ur5ah
+u6rak
+ur3alt
+u6rana
+u6r5ans
+u8rap
+ur5a6ri
+u8ratt
+u1re
+ur3eig
+ur8gri
+u1ri
+ur5ins
+3urlau
+urmen6
+ur8nan
+u1ro
+3ursac
+ur8sau
+ur8sei
+ur4sk
+3urtei
+u1ru
+uru5i6
+uru6r
+u1ry
+ur2za
+ur6zä
+ur5ä6m
+u5rö
+u1rü
+urück3
+u1sa
+usa4gi
+u2s1ar
+u2s1au
+u8schec
+usch5wi
+u2s1ei
+use8kel
+u8sl
+u4st3a4b
+us3tau
+u3s4ter
+u2s1uf
+u8surn
+ut1ac
+u1tal
+uta8m
+u1tan
+ut1ar
+u1tas
+ut1au
+u1te
+u8teic
+u4tent
+u8terf
+u6terin
+u4t3hei
+ut5ho
+ut1hu
+u1ti
+utine5
+uti6q
+u1to
+uto5c
+u1tr
+ut1sa
+ut1s6p
+ut6stro
+u1tu
+utz5w
+u1u
+u1v
+uve5n
+uve3r4ä
+u1w
+u1xe
+u5ya
+uy5e6
+u1yi
+u2z1eh
+u8zerh
+u5ö
+uße6n
+ußen5e
+8vanb
+6vang
+6varb
+var8d
+va6t5a
+va8tei
+va2t1r
+2v1b
+6v5c
+6vd
+1ve
+6ve5g6
+ver1
+ver5b
+verb8l
+ve2re2
+verg8
+ve2ru8
+ve1s
+ve2s3p
+ve3xe
+2v1f
+2v1g
+6v5h
+vi6el
+vie6w5
+vi1g4
+vi8leh
+vil6le.
+8vint
+vi1ru
+vi1tr
+2v1k
+2v1l
+2v1m
+4v5n
+8vo8f
+voi6le
+vol8lend
+vol8li
+v2or1
+vo2re
+vo8rin
+vo2ro
+2v1p
+8vra
+v6re
+2v1s
+2v1t
+2v1v
+4v3w
+2v1z
+waffe8
+wa6g5n
+1wah
+wah8n
+wa5la
+wal8din
+wal6ta
+wan4dr
+5ware
+wa8ru
+war4za
+1was
+w5c
+w1d
+5wech
+we6fl
+1weg
+we8geng
+weg5h
+weg3l
+we2g1r
+weh6r5er
+5weise
+weit3r
+wel2t
+welt3r
+we6rat
+8werc
+5werdu
+wer4fl
+5werk.
+wer4ka
+wer8ku
+wer4ta
+wer8term
+we2sp
+we8stend
+we6steu
+we8str
+we8stö
+wet8ta
+wich6s5t
+1wid
+wi2dr
+wiede4
+wieder5
+wik6
+wim6ma
+win4d3r
+5wirt
+wisch5l
+1wj
+6wk
+2w1l
+8w1n
+wo1c
+woche6
+wol6f
+wor6t5r
+6ws2
+w1sk
+6w5t
+5wunde.
+wun6gr
+wu1sc
+wu2t1
+6w5w
+wy5a
+wärme5
+wä1sc
+1xag
+x1ak
+x3a4men
+8xamt
+x1an
+8x1b
+x1c
+1xe.
+x3e4g
+1xen
+xe1ro
+x1erz
+1xes
+8xf
+x1g
+8x1h
+1xi
+8xid
+xi8so
+4xiste
+x1k
+6x1l
+x1m
+8xn
+1xo
+8x5o6d
+8x3p2
+x1r
+x1s6
+8x1t
+x6tak
+x8terf
+x2t1h
+1xu
+xu1e
+x5ul
+6x3w
+x1z
+5ya.
+y5an.
+y5ank
+y1b
+y1c
+y6cha
+y4chia
+y1d
+yen6n
+y5ern
+y1g
+y5h
+y5in
+y1j
+y1k2
+y1lak
+yl1al
+yla8m
+y5lax
+y1le
+y1lo
+y5lu
+y8mn
+ym1p2
+y3mu
+y1na
+yno2d
+yn1t
+y1on.
+y1o4p
+y5ou
+ypo1
+y1pr
+y8ps
+y1r
+yri3e
+yr1r2
+y1s
+ys5iat
+ys8ty
+y1t
+y3w
+y1z
+yä8m
+z5a6b
+zab5l
+8za6d
+1zah
+za5is
+4z3ak
+6z1am
+5zange.
+8zanl
+2z1ara
+6z5as
+z5auf
+3zaun
+2z1b
+6z1c
+6z1d
+1ze
+ze4dik
+4z3eff
+8zein
+zei4ta
+zei8ters
+ze6la
+ze8lec
+zel8th
+4zemp
+6z5engel
+zen8zin
+8zergä
+zer8i
+ze1ro
+zers8
+zerta8
+zer8tab
+zer8tag
+8zerz
+ze8ste
+zeu6gr
+2z1ex
+2z1f8
+z1g
+4z1h
+1zi
+zi1en
+zi5es.
+4z3imp
+zi1na
+6z5inf
+6z5inni
+zin6s5er
+8zinsuf
+zist5r
+zi5th
+zi1tr
+6z1j
+2z1k
+2z1l
+2z1m
+6z1n
+1zo
+zo6gl
+4z3oh
+zo1on
+zor6na8
+4z1p
+z5q
+6z1r
+2z1s8
+2z1t
+z4t3end
+z4t3hei
+z8thi
+1zu
+zu3al
+zu1b4
+zu1f2
+6z5uhr
+zun2a
+8zunem
+zunf8
+8zungl
+zu1o
+zup8fi
+zu1s8
+zu1z
+2z1v
+zw8
+z1wal
+5zweck
+zwei3s
+z1wel
+z1wer
+z6werg
+8z5wes
+1zwi
+zwi1s
+6z1wo
+1zy
+2z1z
+zz8a
+zzi1s
+1zä
+1zö
+6zöl.
+zö1le
+1zü
+2z1ü2b
+ä1a6
+äb1l
+ä1che
+ä3chi
+äch8sc
+äch8sp
+ä5chu
+äck5a
+äd1a
+äd5era
+ä6d5ia
+ä1e
+ä5fa
+äf1l
+äft6s
+äg1h
+äg3le
+ä6g5nan
+äg5str
+ä1he
+ä1hi
+äh1le
+äh5ne
+1ähnl
+äh1re
+äh5ri
+äh1ru
+ä1hu
+äh1w
+6äi
+ä1isc
+ä6ische
+ä5ism
+ä5j
+ä1k
+äl1c
+ä1le
+ä8lei
+äl6schl
+ämi1e
+äm8n
+äm8s
+ä5na
+5änderu
+äne5i8
+äng3l
+änk5l
+ä1no
+än6s5c
+ä1pa
+äp6s5c
+3äq
+är1c
+ä1re
+äre8m
+5ärgern
+är6gl
+ä1ri
+3ärmel
+ä1ro
+ärt6s5
+ä1ru
+3ärztl
+ä5rö
+ä6s5chen
+äsen8s
+äs1th
+äta8b
+ä1te
+äteri4
+äter5it
+ä6thy
+ä1ti
+3ätk
+ä1to
+ät8schl
+äts1p
+ä5tu
+äub1l
+äu1e
+1äug
+äu8ga
+äu5i
+ä1um.
+ä1us.
+1äuß
+ä1z
+ö1b
+ö1che
+ö5chi
+öch8stei
+öch8str
+öcht6
+5ö6dem
+5öffn
+ö1he
+öh1l8
+öh1re
+ö1hu
+ö1is
+ö1ke
+1ö2ko
+1öl.
+öl6k5l
+öl8pl
+ö1mu
+ö5na
+önig6s3
+ö1no
+ö5o6t
+öpf3l
+öp6s5c
+ö1re
+ör8gli
+ö1ri
+ör8tr
+ö1ru
+5österr
+ö1te
+ö5th
+ö1ti
+ö1tu
+ö1v
+ö1w
+öwe8
+ö2z
+üb6e2
+3ü4ber1
+üb1l
+üb1r
+5ü2bu
+ü1che
+ü1chi
+ü8ch3l
+üch6s5c
+ü8ck
+ück1a
+ück5ers
+üd1a2
+ü6deu
+üdi8t
+ü2d1o4
+üd5s6
+üge4l5a
+üg1l
+üh5a
+ü1he
+ü8heh
+ü6h5erk
+üh1le
+üh1re
+üh1ru
+ü1hu
+üh1w
+ü3k
+ü1le
+ül4l5a
+ül8lo
+ül4ps
+ül6s5c
+ü1lu
+ün8da
+ün8fei
+ünk5l
+ün8za
+ün6zw
+ü5pi
+ü1re
+ü8rei
+ür8fl
+ür8fr
+ür8geng
+ü1ri
+ü1ro
+ür8sta
+ür8ster
+ü1ru
+üse8n
+ü8sta
+ü8stes
+ü6s5tete
+ü3ta
+ü1te
+ü1ti
+üt8tr
+ü1tu
+üt8zei
+ü1v
+ß1a8
+5ßa.
+ß8as
+ß1b8
+ß1c
+ß1d
+1ße
+ß5ec
+8ße8g
+8ße8h
+2ß1ei
+8ßem
+ß1f8
+ß1g
+ß1h
+1ßi
+ß1k
+ß1l
+ß1m
+ßmana8
+ß1n
+ß1o
+ß1p8
+ß5q
+ß1r
+ß1s2
+ßst8
+ß1ta
+ß1te
+ßt3hei
+ß1ti
+ß5to
+ß1tr
+1ßu8
+6ß5um
+ß1v
+ß1w
+ß1z
}
% end pattern data