diff options
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 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} </th>\n" + end + + def td(str) + "<td><code>#{str || ''}  </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!("&","&") + val.gsub!("<","<") + val.gsub!(">",">") + 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> (#{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 |