merge of localization branch into HEAD. mh and zap
authormh <mh>
Sun, 25 Aug 2002 19:00:06 +0000 (19:00 +0000)
committermh <mh>
Sun, 25 Aug 2002 19:00:06 +0000 (19:00 +0000)
158 files changed:
bundles/admin_ay.properties [new file with mode: 0755]
bundles/admin_en.properties
bundles/admin_es.properties
bundles/admin_gn.properties [new file with mode: 0755]
bundles/admin_qu.properties [new file with mode: 0755]
bundles/producer_en.properties [new file with mode: 0755]
bundles/producer_es.properties [new file with mode: 0755]
lib/lucene-1.2.jar [new file with mode: 0755]
lib/multex2c.jar [new file with mode: 0755]
scripts/createIndex.java [new file with mode: 0755]
source/Mir.java
source/OpenMir.java
source/config.properties-dist
source/mir/config/ConfigChecker.java
source/mir/config/ConfigNode.java
source/mir/config/ConfigReader.java
source/mir/config/MirConfiguration.java
source/mir/config/exceptions/ConfigDefineNotKnownException.java
source/mir/config/exceptions/ConfigException.java [deleted file]
source/mir/config/exceptions/ConfigFailure.java [new file with mode: 0755]
source/mir/config/exceptions/ConfigInvalidPropertyTypeException.java
source/mir/config/exceptions/ConfigMissingPropertyException.java
source/mir/entity/EntityBrowser.java [new file with mode: 0755]
source/mir/entity/QueryBuilder.java [new file with mode: 0755]
source/mir/entity/adapter/EntityAdapter.java [new file with mode: 0755]
source/mir/entity/adapter/EntityAdapterDefinition.java [new file with mode: 0755]
source/mir/entity/adapter/EntityAdapterModel.java [new file with mode: 0755]
source/mir/entity/adapter/EntityIteratorAdapter.java [new file with mode: 0755]
source/mir/entity/adapter/EntityListAdapter.java [new file with mode: 0755]
source/mir/generator/CompositeGeneratorLibrary.java [new file with mode: 0755]
source/mir/generator/FreemarkerGenerator.java [new file with mode: 0755]
source/mir/generator/Generator.java [new file with mode: 0755]
source/mir/generator/GeneratorExc.java [new file with mode: 0755]
source/mir/generator/GeneratorFailure.java [new file with mode: 0755]
source/mir/generator/WriterEngine.java [new file with mode: 0755]
source/mir/misc/HTMLTemplateProcessor.java
source/mir/misc/MirConfig.java
source/mir/misc/PDFUtil.java [new file with mode: 0755]
source/mir/producer/AssignmentProducerNode.java [new file with mode: 0755]
source/mir/producer/CompositeProducerNode.java [new file with mode: 0755]
source/mir/producer/ConditionalProducerNode.java [new file with mode: 0755]
source/mir/producer/EntityBatchingProducerNode.java [new file with mode: 0755]
source/mir/producer/EntityEnumeratingProducerNode.java [new file with mode: 0755]
source/mir/producer/EntityListProducerNode.java [new file with mode: 0755]
source/mir/producer/EntityModifyingProducerNode.java [new file with mode: 0755]
source/mir/producer/EvaluatedAssignmentProducerNode.java [new file with mode: 0755]
source/mir/producer/ExpandedAssignmentProducerNode.java [new file with mode: 0755]
source/mir/producer/FileDateSettingProducerNode.java [new file with mode: 0755]
source/mir/producer/FileDeletingProducerNode.java [new file with mode: 0755]
source/mir/producer/FileOperationProducerNode.java [new file with mode: 0755]
source/mir/producer/GeneratingProducerNode.java [new file with mode: 0755]
source/mir/producer/LoggingProducerNode.java [new file with mode: 0755]
source/mir/producer/NodedProducer.java [new file with mode: 0755]
source/mir/producer/NodedProducerFactory.java [new file with mode: 0755]
source/mir/producer/Producer.java [new file with mode: 0755]
source/mir/producer/ProducerExc.java [new file with mode: 0755]
source/mir/producer/ProducerFactory.java [new file with mode: 0755]
source/mir/producer/ProducerFailure.java [new file with mode: 0755]
source/mir/producer/ProducerNode.java [new file with mode: 0755]
source/mir/producer/ProducerNodeDecorator.java [new file with mode: 0755]
source/mir/producer/ResourceBundleProducerNode.java [new file with mode: 0755]
source/mir/producer/ScriptCallingProducerNode.java [new file with mode: 0755]
source/mir/producer/ValuesMapProducerNode.java [new file with mode: 0755]
source/mir/producer/reader/DefaultProducerNodeBuilders.java [new file with mode: 0755]
source/mir/producer/reader/ProducerConfigExc.java [new file with mode: 0755]
source/mir/producer/reader/ProducerConfigFailure.java [new file with mode: 0755]
source/mir/producer/reader/ProducerConfigReader.java [new file with mode: 0755]
source/mir/producer/reader/ProducerNodeBuilder.java [new file with mode: 0755]
source/mir/producer/reader/ProducerNodeBuilderLibrary.java [new file with mode: 0755]
source/mir/producer/reader/ReaderTool.java [new file with mode: 0755]
source/mir/producer/reader/ScriptedProducerFactory.java [new file with mode: 0755]
source/mir/producer/reader/ScriptedProducerNode.java [new file with mode: 0755]
source/mir/producer/reader/ScriptedProducerNodeDefinition.java [new file with mode: 0755]
source/mir/producer/reader/ScriptedProducerNodeTool.java [new file with mode: 0755]
source/mir/storage/Database.java
source/mir/util/CachingRewindableIterator.java [new file with mode: 0755]
source/mir/util/DateToMapAdapter.java [new file with mode: 0755]
source/mir/util/FileMonitor.java [new file with mode: 0755]
source/mir/util/GeneratorHTMLFunctions.java [new file with mode: 0755]
source/mir/util/NullWriter.java [new file with mode: 0755]
source/mir/util/ParameterExpander.java [new file with mode: 0755]
source/mir/util/ResourceBundleGeneratorFunction.java [new file with mode: 0755]
source/mir/util/RewindableIterator.java [new file with mode: 0755]
source/mircoders/global/JobQueue.java [new file with mode: 0755]
source/mircoders/global/MirGlobal.java [new file with mode: 0755]
source/mircoders/global/ProducerEngine.java [new file with mode: 0755]
source/mircoders/localizer/MirAdminInterfaceLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/MirCachingLocalizerDecorator.java [new file with mode: 0755]
source/mircoders/localizer/MirDataModelLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/MirGeneratorLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/MirLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/MirLocalizerException.java [new file with mode: 0755]
source/mircoders/localizer/MirLocalizerFailure.java [new file with mode: 0755]
source/mircoders/localizer/MirOpenPostingLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/MirProducerAssistantLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/MirProducerLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/basic/MirBasicAdminInterfaceLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/basic/MirBasicDataModelLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/basic/MirBasicGeneratorLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/basic/MirBasicLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/basic/MirBasicOpenPostingLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/basic/MirBasicProducerAssistantLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/basic/MirBasicProducerLocalizer.java [new file with mode: 0755]
source/mircoders/localizer/basic/MirBasicWriterEngine.java [new file with mode: 0755]
source/mircoders/media/MediaHandlerGeneric.java
source/mircoders/producer/CompositeProducer.java [new file with mode: 0755]
source/mircoders/producer/CompositeProducerFactory.java [new file with mode: 0755]
source/mircoders/producer/ContentMarkingProducerNode.java [new file with mode: 0755]
source/mircoders/producer/ContentModifyingProducerNode.java [new file with mode: 0755]
source/mircoders/producer/IndexingProducerNode.java [new file with mode: 0755]
source/mircoders/producer/MediaGeneratingProducerNode.java [new file with mode: 0755]
source/mircoders/producer/OldProducerAdapter.java [new file with mode: 0755]
source/mircoders/producer/OldProducerAdapterFactory.java [new file with mode: 0755]
source/mircoders/producer/PDFGeneratingProducerNode.java [new file with mode: 0755]
source/mircoders/producer/ProducerAll.java [deleted file]
source/mircoders/producer/ProducerContent.java [deleted file]
source/mircoders/producer/ProducerFeature.java [deleted file]
source/mircoders/producer/ProducerList.java [deleted file]
source/mircoders/producer/ProducerMedia.java
source/mircoders/producer/ProducerNavigation.java [deleted file]
source/mircoders/producer/ProducerOpenPosting.java [deleted file]
source/mircoders/producer/ProducerStartPage.java [deleted file]
source/mircoders/producer/ProducerTopics.java [deleted file]
source/mircoders/producer/reader/SupplementalProducerNodeBuilders.java [new file with mode: 0755]
source/mircoders/servlet/ServletModuleComment.java
source/mircoders/servlet/ServletModuleContent.java
source/mircoders/servlet/ServletModuleLocalizer.java [new file with mode: 0755]
source/mircoders/servlet/ServletModuleOpenIndy.java
source/mircoders/servlet/ServletModuleProducer.java
templates-dist/admin/start_admin.template
templates-dist/de/open/comment.template [deleted file]
templates-dist/de/open/comment_done.template [deleted file]
templates-dist/de/open/comment_dupe.template [deleted file]
templates-dist/de/open/comment_en.template [deleted file]
templates-dist/de/open/posting.template [deleted file]
templates-dist/de/open/posting_done.template [deleted file]
templates-dist/de/open/posting_dupe.template [deleted file]
templates-dist/de/open/posting_en.template [deleted file]
templates-dist/en/open/comment.template [deleted file]
templates-dist/en/open/comment.template.en [deleted file]
templates-dist/en/open/comment_done.template [deleted file]
templates-dist/en/open/comment_dupe.template [deleted file]
templates-dist/en/open/minimal_posting.template [deleted file]
templates-dist/en/open/posting.template [deleted file]
templates-dist/en/open/posting.template.en [deleted file]
templates-dist/en/open/posting_done.template [deleted file]
templates-dist/en/open/posting_dupe.template [deleted file]
templates-dist/nl/open/comment.template [deleted file]
templates-dist/nl/open/comment_done.template [deleted file]
templates-dist/nl/open/comment_dupe.template [deleted file]
templates-dist/nl/open/posting.template [deleted file]
templates-dist/nl/open/posting_done.template [deleted file]
templates-dist/nl/open/posting_dupe.template [deleted file]
templates-dist/open/comment_en.template [deleted file]
templates-dist/open/posting.template
templates-dist/open/posting_en.template [deleted file]
templates-dist/producer/content.template
templates-dist/producer/producers.xml [new file with mode: 0755]

diff --git a/bundles/admin_ay.properties b/bundles/admin_ay.properties
new file mode 100755 (executable)
index 0000000..beac478
--- /dev/null
@@ -0,0 +1,382 @@
+########## admin ##########\r
+\r
+# general\r
+yes=sí\r
+no=no\r
+dontcare=no importa\r
+all=todo\r
+\r
+# actions\r
+insert=insertar\r
+save=guardar\r
+edit=editar\r
+delete=borrar\r
+add=añadir\r
+filter=filtrar\r
+attach=vincular\r
+list=mostrar lista\r
+back=atrás\r
+cancel=cancelar\r
+\r
+# records\r
+records=registros\r
+show_from_to=mostrando entradas desde {0} hasta {1}\r
+no_matches_found=No se encontraron resultados!\r
+list.next=siguiente\r
+list.previous=anterior\r
+\r
+# media - used by image, audio, video and other media\r
+media.created=creado\r
+media.changed=cambiado\r
+media.published=publicado\r
+media.format=Formato\r
+media.rights=Copyright\r
+media.type=Tipo\r
+media.mediafolder=Carpeta de recursos mediáticos\r
+media.title=Título\r
+media.description=Descripción\r
+media.date=Fecha\r
+media.location=Lugar de origen\r
+media.creator=Creador\r
+media.keywords=Palabras clave\r
+media.comment=Comentario\r
+media.source=Origen\r
+media.is_published=Disponible para publicación\r
+media.icon=Icono\r
+medialist.search_text_in=Buscar texto en\r
+\r
+# image\r
+image.htmltitle=indymedia | imagen\r
+imagelist.htmltitle=indymedia | lista de imagenes\r
+\r
+# audio\r
+audio.htmltitle=indymedia | audio\r
+audiolist.htmltitle=indymedia | lista de audio\r
+\r
+# video\r
+video.htmltitle=indymedia | video\r
+videolist.htmltitle=indymedia | lista de video\r
+\r
+# other\r
+other_media.htmltitle=indymedia | otros recursos mediáticos\r
+other_media.htmltitle=indymedia | lista de recursos mediáticos\r
+\r
+# breaking\r
+breaking.htmltitle=indymedia | últimas noticias\r
+breakinglist.htmltitle=indymedia | listado de últimas noticias\r
+breaking.textinfo=(max. 5 líneas / 250 caracteres)\r
+breaking.text=texto\r
+breaking.date=fecha\r
+\r
+\r
+# comment\r
+comment.htmltitle=indymedia | commentario\r
+comment.date=fecha\r
+comment.title=título\r
+comment.published=publicado\r
+comment.text=texto-del-comentario\r
+comment.address=dirección\r
+comment.phone=teléfono\r
+comment.email=email\r
+comment.url=url\r
+comment.creator=autor\r
+comment.article=del artículo\r
+\r
+commentlist.htmltitle=indymedia | lista de comentarios\r
+commentlist.produced=producido\r
+commentlist.hidden=oculto\r
+commentlist.search=buscar!\r
+\r
+# confirm\r
+confirm.htmltitle=indymedia | confirmar borrado\r
+confirm.really_delete=Desea borrar esta entrada?\r
+\r
+# content\r
+content.htmltitle=indymedia | contenido\r
+content.owner=Propietario\r
+content.topic=Tema\r
+content.feature=Característica\r
+content.title=titulo largo\r
+content.subtitle=subtítulo/título de contexto\r
+content.location=Lugar de origen\r
+content.creator=autor\r
+content.creator.email=Email\r
+content.creator.url=Web\r
+content.creator.address=Dirección\r
+content.creator.telephone=Teléfono\r
+content.abstract=Descripción breve\r
+content.content=Contenido\r
+content.html=es HTML?\r
+content.comment=Comentario interno\r
+content.internal=(propósito interno)\r
+content.attachments=Vínculos\r
+content.images=Imágenes\r
+content.audio=Audio\r
+content.video=Video\r
+content.other=Otros recursos mediáticos\r
+content.media=Recursos mediáticos\r
+content.addimage=añadir imagen\r
+content.addaudio=añadir audio\r
+content.addvideo=añadir video\r
+content.addother=añadir otros recursos mediáticos\r
+content.creationdate=fecha\r
+content.modificationdate=último cambio\r
+content.status=Estado\r
+content.type=Tipo de artículo\r
+\r
+contentlist.htmltitle=indymedia | lista de contenidos\r
+\r
+# language\r
+language.htmltitle=indymedia | idiomas\r
+language.name=idioma\r
+language.code=Código del idioma\r
+\r
+languagelist.htmltitle=indymedia | lista de idiomas\r
+\r
+# imcs\r
+linkimcs.htmltitle=indymedia | Enlaces a IMCs\r
+linkimcs.name=Nombre\r
+linkimcs.continent=Continente\r
+linkimcs.new_parent=Nuevo Ancestro\r
+linkimcs.url=URL\r
+linkimcs.sort_by=Criterio de orden\r
+linkimcs.language=Idioma\r
+linkimcs.parent=ancestro\r
+\r
+linkimcslist.htmltitle=indymedia | Lista de enlaces a IMCs\r
+linkimcslist.search_in=Buscar texto en\r
+\r
+# login\r
+login.htmltitle=indymedia | registro\r
+login.info=Esta zona es accesible exclusivamente a grupos autorizados. Si desea colaborar como editor, por favor contacte con nosotros en\r
+login.title=login\r
+login.name=Login\r
+login.password=Password\r
+login.language=Idioma\r
+login.language.german=Alem\87n\r
+login.language.spanish=Espa\96ol\r
+login.language.guarani=Guaran\92\r
+login.language.aymara=Aymara\r
+login.language.quechua=Quechua\r
+login.submit=  Envíar\r
+\r
+# mediafolder\r
+mediafolder.htmltitle=indymedia | carpeta de recursos mediáticos\r
+mediafolder.date=fecha\r
+mediafolder.name=nombre\r
+mediafolder.location=lugar de origen\r
+mediafolder.keywords=palabras clave\r
+mediafolder.comment=commentario\r
+\r
+mediafolderlist.htmltitle=indymedia | lista de carpetas de recursos mediáticos\r
+\r
+# message\r
+message.htmltitle=indymedia | mensajes\r
+message.date=fecha\r
+message.title=título\r
+message.creator=Autor\r
+message.text=texto\r
+message.textinfo=(max. 5 líneas / 250 caracteres)\r
+\r
+messagelist.htmltitle=indymedia | lista de mensajes\r
+\r
+# feature\r
+feature.htmltitle=indymedia | presentación\r
+feature.title=Título\r
+feature.published=publicado\r
+feature.is_published=está publicado\r
+feature.is_not_published=no está publicado\r
+feature.filename=Nombre del fichero\r
+feature.abstract=Descripción breve\r
+feature.link=Enlace\r
+\r
+featurelist.htmltitle=indymedia | lista de presentaciones\r
+\r
+# admin start page\r
+start.htmltitle=indymedia | administración\r
+start.openpostings.title=ENVÍOSABIERTOS\r
+start.comments.title=COMENTARIOS\r
+start.breaking.title=ÚLTIMAS NOTICIAS\r
+start.breaking.new=últimas noticias recientes\r
+start.content.title=ARTICULOS\r
+start.content.new=nuevos artículos\r
+start.show=mostrar\r
+start.content.newswire=newswire\r
+start.content.feature=presentación\r
+start.content.topicspecial=especiales-por-tema\r
+start.content.startspecial=especiales-página-de-inicio\r
+start.content.not_published=artículos aun sin publicar\r
+start.content.with_media=con recursos mediáticos\r
+start.content.last_changes=últimos cambios\r
+start.content.with_comments=con comentarios de propósito interno\r
+start.content.search=buscar\r
+start.generate.title=GENERAR MANUALMENTE\r
+start.generate.all.title=todas las areas\r
+start.generate.all.new=todo nuevo (estándar, actualización en la web > 5min.)\r
+start.generate.parts.title=partes específicas del website\r
+start.generate.startpages.new=nueva página de inicio\r
+start.generate.all_forced=todos (forzado)\r
+start.generate.all_sync=todos (forzado y sincronizado)\r
+start.generate.content.new=nuevo contenido\r
+start.generate.topics.new=nuevos temas\r
+start.generate.postings.new=nuevos envios abiertos\r
+start.generate.images.new=nuevas imágenes\r
+start.generate.audio.new=nuevos ficheros de audio\r
+start.generate.video.new=nuevos ficheros de video\r
+start.generate.other.new=otros recursos mediáticos nuevos\r
+start.generate.navigation=navegación\r
+start.coverage.title=COBERTURA\r
+start.topics.title=TEMAS\r
+start.images.title=MATERIAL GRAFICO\r
+start.mediafolder.title=CARPETA DE RECURSOS MEDIATICOS\r
+start.languages.title=TÍTULO\r
+start.imcs.title=IMCS\r
+start.messageboard.title=Mensajería Interna\r
+start.messageboard.no_messages=no hay mensajes\r
+\r
+# topic\r
+topic.htmltitle=indymedia | tema\r
+topic.title=Nombre\r
+topic.description=descripción\r
+topic.filename=Nombre del fichero\r
+topic.main_url=página de información principal\r
+topic.archive_url=URL del archivo\r
+\r
+topiclist.htmltitle=indymedia | lista de temas\r
+\r
+# users\r
+user.htmltitle=indymedia | usuario\r
+user.login=login\r
+user.password=password\r
+user.admin=administrador\r
+\r
+userlist.htmltitle=indymedia | lista de usuarios\r
+\r
+# head\r
+head.start=inicio\r
+head.logout=salir\r
+head.help=ayuda\r
+head.search=buscar\r
+head.logged_in=estás registrado\r
+\r
+# foot\r
+foot.top=arriba\r
+\r
+\r
+########## error ##########\r
+\r
+error.htmltitle=indymedia | error\r
+error.title=oi! oi! oi!\r
+error.text=El siguiente mensaje puede que no le sea de mucha ayuda, pero seguramente lo será para <a href="mailto:{0}">{1}</a>:\r
+error.text2=Por favor envíe un mensaje con el <font color="Red">texto que aparece en rojo</font> y una descripción detallada a la siguiente dirección <a href="mailto:{0}">{1}</a>. Gracias!\r
+\r
+\r
+usererror.htmltitle=indymedia | error de datos\r
+usererror.title=oi! oi! oi!\r
+usererror.text=Los datos que ha introducido han causado el siguiente error:\r
+usererror.what_to_do=Por favor, pulse el botón para volver e intentelo de nuevo\r
+\r
+\r
+########## producer ##########\r
+\r
+producer.content.htmltitle=mir.indymedia:\r
+producer.content.email=email\r
+producer.content.homepage=Homepage\r
+producer.content.comment=Haga un comentario sobre este artículo\r
+producer.copyright= Copyright © 2002 Indymedia Bolivia - Qollasuyu - Ivi Iyambae<br> Esta publicaci\97n es <a href="http://www.gnu.org/copyleft/copyleft.es.html">copyleft</a>. Por tanto, se permite difundir, citar y copiar literalmente sus materiales, de forma \92ntegra o parcial, por cualquier medio y para cualquier prop\97sito, siempre que se mantenga esta nota y se cite procedencia. Indymedia Euskal Herria no asume ninguna responsabilidad por el material publicado en este sitio, salvo sobre lo que aparece en la columna central. Toda la responsabilidad para verificar la veracidad y los derechos de reproducci\97n de un env\92o corresponden al autor que lo publica. Al publicar material en este sitio, el o la autora del env\92o asume que puede ser redistribuido libremente. \r
+producer.contact=Contacto\r
+producer.openposting.htmltitle=mir.indymedia:\r
+producer.startpage.htmltitle=mir.indymedia: the mir-coders-website\r
+producer.topiclist.htmltitle=mir.indymedia:\r
+\r
+\r
+########## open ##########\r
+\r
+open.optional=opcional\r
+open.required=requerido\r
+\r
+open.comment.htmltitle=indymedia | confirmar comentario\r
+open.comment.title=Añadiendo un comentario al artículo\r
+open.comment.note=Unos comentarios sobre como escribir un comentario en Indymedia.\r
+open.comment.formtitle=Formulario-del-comentario\r
+open.comment.title=Título del comentario\r
+open.comment.name=su nombre\r
+open.comment.email=su email\r
+open.comment.url=su dirección web\r
+open.comment.phone=su número de teléfono\r
+open.comment.address=su dirección\r
+open.comment.language=idioma de su comentario\r
+open.comment.text=su comentario\r
+open.comment.submit=envíar comentario\r
+open.comment.reset=limpiar formulario\r
+\r
+\r
+open.commentdone.htmltitle=indymedia | envío abierto\r
+open.commentdone.thanks=Su comentario está de camino!\r
+open.commentdone.wait=In wenigen Minuten ist Deine Ergänzung unter dem ergänzten Artikel.<br>Manchmal kann es aber aufgrund technischer Probleme etwas dauern bis sie erscheint.<br>\r
+open.commentdone.criteria=Die Moderationskriterien von indymedia kannst Du <a href="http://de.indymedia.org/static/moderation.html" target="_blank">hier</a> nachlesen.\r
+open.commentdone.stay_calm=Gedulde Dich einen Moment - Es lohnt sich!\r
+open.commentdone.back=Zur&uuml;ck zum kommentierten Artikel\r
+\r
+\r
+open.commentdupe.htmltitle=indymedia | envío abierto - comentario duplicado\r
+open.commentdupe.title=Mantenga la calma unos breves instantes.\r
+open.commentdupe.explanation=Probablemente haya apretado el botón de recarga o enviado el comentario en una segunda ocasión. Si puede leer esto, significa que su comentario ha sido recibido con éxito y será incluido en la página de artículos en breves instantes.\r
+open.commentdupe.no_panic=No se altere!\r
+open.commentdupe.back=Volver al artículo comentado\r
+\r
+\r
+open.posting.htmltitle=indymedia | envío abierto\r
+open.posting.meta.description=Indymedia | Centro de Periodismo Independiente\r
+open.posting.meta.author=Colectivo IMC\r
+open.posting.meta.keywords=Periodismo Libre\r
+open.posting.jump_to_form=Ir directamente al formulario.\r
+open.posting.title=Publique su artículo\r
+open.posting.nr_of_media=Número de recursos mediáticos\r
+open.posting.nr_of_media.info=(wenn Du mehr als eine Datei hochladen willst, bitte hier die Anzahl eintragen und den Knopf drücken, <b>bevor</b> Du weitere Felder ausfüllst.)\r
+open.posting.nr_of_media.submit=Anzahl festlegen\r
+open.posting.form.title=Formulario de publicación\r
+open.posting.title=<b>Título</b> de su artículo\r
+open.posting.title.info=(Bitte wähle einen möglichst klaren, aussagekräftigen Titel.)\r
+open.posting.topic=<b>Thema</b> Deines Beitrags\r
+open.posting.topic.info=(Mehrfachwahl ist möglich. Bitte dazu die [Strg]- bzw [Ctrl]-Taste benutzen)\r
+open.posting.author=<b>autor</b> de este artículo\r
+open.posting.abstract=Descripción <b>breve</b> de su artículo\r
+open.posting.abstract.info=(Sie soll den LeserInnen schnell vermitteln, worum es in Deinem Beitrag geht. Falls Du den ersten Absatz Deines Artikels dazu wählst, achte bitte darauf ihn im Haupttextfeld weiter unten nicht nochmal einzusetzen.)\r
+open.posting.abstract.constraint=(que no exceda de <b>5 líneas</b>)\r
+open.posting.contact.info=La información de contacto es opcional pero ayuda a que otras personas puedan ponerse en contacto con usted.\r
+open.posting.email=su dirección de email\r
+open.posting.url=su dirección web\r
+open.posting.address=su dirección personal\r
+open.posting.phone=su número de teléfono\r
+open.posting.language=idioma de su artículo\r
+open.posting.text=su <b>artículo</b>\r
+open.posting.text.info=ponga aquí el texto de su artículo\r
+open.posting.media=recursos mediáticos\r
+open.posting.media.info=cargue sus ficheros de medios (de momento tan solo se aceptan jpg|gif|mp3|avi|qt|mpeg)\r
+open.posting.media.howto=(Dazu wählst Du mit "Durchsuchen.." die entsprechende Datei auf Deiner Festplatte aus.\r
+open.posting.media.media=Media\r
+open.posting.media.title=subtítulo de los recursos mediáticos\r
+open.posting.submit.info=Bitte drücke den Verschicken-Knopf<b> nur einmal</b>!<br> In wenigen Minuten erscheind Dein Beitrag dann auf der <a href="http://de.indymedia.org/open.html" target="_blank"> <b>"Open Posting"</b></a> - Seite. &nbsp; Das ist nicht die Startseite.<br> Manchmal kann es aber aufgrund technischer Probleme etwas dauern bis er erscheint.\r
+open.posting.criteria=Die <b>Moderationskriterien</b> kannst Du <a href="http://de.indymedia.org/static/moderation.html" target="_blank"><b>hier nachlesen</b></a>\r
+open.posting.submit=Enviar (la paciencia es una virtud!!)\r
+open.posting.reset=Limpiar formulario\r
+\r
+\r
+open.postingdone.htmltitle=indymedia | open posting\r
+open.postingdone.title=Hurra, Du hast Deinen Artikel abgeschickt!\r
+open.postingdone.info=Dein Artikel landet in einigen Minuten auf der <a href="http://de.indymedia.org/open.html">"Open Posting"</a> - Seite. Das ist nicht die Startseite. Die Moderationskriterien kannst Du <a href="http://de.indymedia.org/static/moderation.html">hier lesen</a>\r
+open.postingdone.stay_calm=Gedulde Dich einen Moment! Es lohnt sich!\r
+open.postingdone.back=Zur&uuml;ck\r
+\r
+\r
+open.postingdupe.htmltitle=indymedia | envío abierto - envio duplicado\r
+open.postingdupe.title=Mantenga la calma, su envio será procesado en breves instantes.\r
+open.postingdupe.explanation=  Posiblemente haya pulsado el botón de recarga de su navegador, o enviado su articulo por segunda vez\r
+                                       Si está leyendo este texto, significa que su envío ha sido recibido con éxito\r
+                                       y que será incluido en la pagina de artículos en breves instantes.\r
+                               <br>\r
+                                       Como detalle técnico, este imc está conectado a un servidor proxy\r
+                                       que no es actualizado cada minuto.\r
+open.postingdupe.no_panic=No pierda los estribos!\r
+open.postingdupe.back=Atrás\r
index 1222118..0382681 100755 (executable)
@@ -1,5 +1,5 @@
 ########## admin ##########
-# $Id: admin_en.properties,v 1.14 2002/08/09 17:51:53 init Exp $
+# $Id: admin_en.properties,v 1.15 2002/08/25 19:00:06 mh Exp $
 
 # general
 yes=yes
@@ -291,32 +291,6 @@ usererror.text=Your input caused the following error:
 usererror.what_to_do=Please press the back button and try it again
 
 
-########## producer ##########
-
-producer.content.htmltitle=mir.indymedia.de:
-producer.content.email=eMail
-producer.content.homepage=Homepage
-producer.content.comment=Make a quick comment on this article
-
-producer.copyright=Jegliche Inhalte, die bei germany.indymedia 
-ver&ouml;ffentlicht werden, bleiben Eigentum der Autorin/ des Autors. Soweit 
-nicht anders vermerkt, k&ouml;nnen und sollen sie weiterverwertet werden. 
-germany.indymedia &uuml;bernimmt keine Gew&auml;hr f&uuml;r die Inhalte.<br>Eine 
-
-spezielle  Form des Copyrights wird diskutiert und folgt.
-
-producer.contact=Kontakt
-
-producer.openposting.htmltitle=mir.indymedia.de:
-
-producer.startpage.htmltitle=mir.indymedia.de: the mir-coders-website
-
-producer.topiclist.htmltitle=mir.indymedia.de:
-
-producer.previous=previous page
-producer.next=next page
-
-
 ########## open ##########
 
 open.optional=optional
index 6510e99..31b17e0 100755 (executable)
@@ -1,5 +1,5 @@
 ########## admin ##########\r
-# $Id: admin_es.properties,v 1.3 2002/07/01 21:50:22 mh Exp $\r
+# $Id: admin_es.properties,v 1.4 2002/08/25 19:00:06 mh Exp $\r
 \r
 # general\r
 yes=sí\r
@@ -154,9 +154,12 @@ login.title=login
 login.name=Login\r
 login.password=Password\r
 login.language=Idioma\r
-login.language.english=Inglés\r
-login.language.german=Alemán\r
-login.language.spanish=Español\r
+login.language.english=Ingl\8es\r
+login.language.german=Alem\87n\r
+login.language.spanish=Espa\96ol\r
+login.language.guarani=Guaran\92\r
+login.language.aymara=Aymara\r
+login.language.quechua=Quechua\r
 login.submit=  Envíar\r
 \r
 # mediafolder\r
@@ -285,7 +288,7 @@ producer.content.htmltitle=mir.indymedia:
 producer.content.email=email\r
 producer.content.homepage=Homepage\r
 producer.content.comment=Haga un comentario sobre este artículo\r
-producer.copyright=Jegliche Inhalte, die bei germany.indymedia ver&ouml;ffentlicht werden, bleiben Eigentum der Autorin/ des Autors. Soweit nicht anders vermerkt, k&ouml;nnen und sollen sie weiterverwertet werden. germany.indymedia &uuml;bernimmt keine Gew&auml;hr f&uuml;r die Inhalte.<br>Eine spezielle  Form des Copyrights wird diskutiert und folgt.\r
+producer.copyright= Copyright © 2002 Indymedia Bolivia - Qollasuyu - Ivi Iyambae<br> Esta publicaci\97n es <a href="http://www.gnu.org/copyleft/copyleft.es.html">copyleft</a>. Por tanto, se permite difundir, citar y copiar literalmente sus materiales, de forma \92ntegra o parcial, por cualquier medio y para cualquier prop\97sito, siempre que se mantenga esta nota y se cite procedencia. Indymedia Euskal Herria no asume ninguna responsabilidad por el material publicado en este sitio, salvo sobre lo que aparece en la columna central. Toda la responsabilidad para verificar la veracidad y los derechos de reproducci\97n de un env\92o corresponden al autor que lo publica. Al publicar material en este sitio, el o la autora del env\92o asume que puede ser redistribuido libremente. \r
 producer.contact=Contacto\r
 producer.openposting.htmltitle=mir.indymedia:\r
 producer.startpage.htmltitle=mir.indymedia: the mir-coders-website\r
diff --git a/bundles/admin_gn.properties b/bundles/admin_gn.properties
new file mode 100755 (executable)
index 0000000..f8376a1
--- /dev/null
@@ -0,0 +1,383 @@
+########## admin ##########\r
+\r
+# general\r
+yes=sí\r
+no=no\r
+dontcare=no importa\r
+all=todo\r
+\r
+# actions\r
+insert=insertar\r
+save=guardar\r
+edit=editar\r
+delete=borrar\r
+add=añadir\r
+filter=filtrar\r
+attach=vincular\r
+list=mostrar lista\r
+back=atrás\r
+cancel=cancelar\r
+\r
+# records\r
+records=registros\r
+show_from_to=mostrando entradas desde {0} hasta {1}\r
+no_matches_found=No se encontraron resultados!\r
+list.next=siguiente\r
+list.previous=anterior\r
+\r
+# media - used by image, audio, video and other media\r
+media.created=creado\r
+media.changed=cambiado\r
+media.published=publicado\r
+media.format=Formato\r
+media.rights=Copyright\r
+media.type=Tipo\r
+media.mediafolder=Carpeta de recursos mediáticos\r
+media.title=Título\r
+media.description=Descripción\r
+media.date=Fecha\r
+media.location=Lugar de origen\r
+media.creator=Creador\r
+media.keywords=Palabras clave\r
+media.comment=Comentario\r
+media.source=Origen\r
+media.is_published=Disponible para publicación\r
+media.icon=Icono\r
+medialist.search_text_in=Buscar texto en\r
+\r
+# image\r
+image.htmltitle=indymedia | imagen\r
+imagelist.htmltitle=indymedia | lista de imagenes\r
+\r
+# audio\r
+audio.htmltitle=indymedia | audio\r
+audiolist.htmltitle=indymedia | lista de audio\r
+\r
+# video\r
+video.htmltitle=indymedia | video\r
+videolist.htmltitle=indymedia | lista de video\r
+\r
+# other\r
+other_media.htmltitle=indymedia | otros recursos mediáticos\r
+other_media.htmltitle=indymedia | lista de recursos mediáticos\r
+\r
+# breaking\r
+breaking.htmltitle=indymedia | últimas noticias\r
+breakinglist.htmltitle=indymedia | listado de últimas noticias\r
+breaking.textinfo=(max. 5 líneas / 250 caracteres)\r
+breaking.text=texto\r
+breaking.date=fecha\r
+\r
+\r
+# comment\r
+comment.htmltitle=indymedia | commentario\r
+comment.date=fecha\r
+comment.title=título\r
+comment.published=publicado\r
+comment.text=texto-del-comentario\r
+comment.address=dirección\r
+comment.phone=teléfono\r
+comment.email=email\r
+comment.url=url\r
+comment.creator=autor\r
+comment.article=del artículo\r
+\r
+commentlist.htmltitle=indymedia | lista de comentarios\r
+commentlist.produced=producido\r
+commentlist.hidden=oculto\r
+commentlist.search=buscar!\r
+\r
+# confirm\r
+confirm.htmltitle=indymedia | confirmar borrado\r
+confirm.really_delete=Desea borrar esta entrada?\r
+\r
+# content\r
+content.htmltitle=indymedia | contenido\r
+content.owner=Propietario\r
+content.topic=Tema\r
+content.feature=Característica\r
+content.title=titulo largo\r
+content.subtitle=subtítulo/título de contexto\r
+content.location=Lugar de origen\r
+content.creator=autor\r
+content.creator.email=Email\r
+content.creator.url=Web\r
+content.creator.address=Dirección\r
+content.creator.telephone=Teléfono\r
+content.abstract=Descripción breve\r
+content.content=Contenido\r
+content.html=es HTML?\r
+content.comment=Comentario interno\r
+content.internal=(propósito interno)\r
+content.attachments=Vínculos\r
+content.images=Imágenes\r
+content.audio=Audio\r
+content.video=Video\r
+content.other=Otros recursos mediáticos\r
+content.media=Recursos mediáticos\r
+content.addimage=añadir imagen\r
+content.addaudio=añadir audio\r
+content.addvideo=añadir video\r
+content.addother=añadir otros recursos mediáticos\r
+content.creationdate=fecha\r
+content.modificationdate=último cambio\r
+content.status=Estado\r
+content.type=Tipo de artículo\r
+\r
+contentlist.htmltitle=indymedia | lista de contenidos\r
+\r
+# language\r
+language.htmltitle=indymedia | idiomas\r
+language.name=idioma\r
+language.code=Código del idioma\r
+\r
+languagelist.htmltitle=indymedia | lista de idiomas\r
+\r
+# imcs\r
+linkimcs.htmltitle=indymedia | Enlaces a IMCs\r
+linkimcs.name=Nombre\r
+linkimcs.continent=Continente\r
+linkimcs.new_parent=Nuevo Ancestro\r
+linkimcs.url=URL\r
+linkimcs.sort_by=Criterio de orden\r
+linkimcs.language=Idioma\r
+linkimcs.parent=ancestro\r
+\r
+linkimcslist.htmltitle=indymedia | Lista de enlaces a IMCs\r
+linkimcslist.search_in=Buscar texto en\r
+\r
+# login\r
+login.htmltitle=indymedia | registro\r
+login.info=Esta zona es accesible exclusivamente a grupos autorizados. Si desea colaborar como editor, por favor contacte con nosotros en\r
+login.title=login\r
+login.name=Login\r
+login.password=Password\r
+login.language=Idioma\r
+login.language.english=Ingl\8es\r
+login.language.german=Alem\87n\r
+login.language.spanish=Espa\96ol\r
+login.language.guarani=Guaran\92\r
+login.language.aymara=Aymara\r
+login.language.quechua=Quechua\r
+login.submit=  Envíar\r
+\r
+# mediafolder\r
+mediafolder.htmltitle=indymedia | carpeta de recursos mediáticos\r
+mediafolder.date=fecha\r
+mediafolder.name=nombre\r
+mediafolder.location=lugar de origen\r
+mediafolder.keywords=palabras clave\r
+mediafolder.comment=commentario\r
+\r
+mediafolderlist.htmltitle=indymedia | lista de carpetas de recursos mediáticos\r
+\r
+# message\r
+message.htmltitle=indymedia | mensajes\r
+message.date=fecha\r
+message.title=título\r
+message.creator=Autor\r
+message.text=texto\r
+message.textinfo=(max. 5 líneas / 250 caracteres)\r
+\r
+messagelist.htmltitle=indymedia | lista de mensajes\r
+\r
+# feature\r
+feature.htmltitle=indymedia | presentación\r
+feature.title=Título\r
+feature.published=publicado\r
+feature.is_published=está publicado\r
+feature.is_not_published=no está publicado\r
+feature.filename=Nombre del fichero\r
+feature.abstract=Descripción breve\r
+feature.link=Enlace\r
+\r
+featurelist.htmltitle=indymedia | lista de presentaciones\r
+\r
+# admin start page\r
+start.htmltitle=indymedia | administración\r
+start.openpostings.title=ENVÍOSABIERTOS\r
+start.comments.title=COMENTARIOS\r
+start.breaking.title=ÚLTIMAS NOTICIAS\r
+start.breaking.new=últimas noticias recientes\r
+start.content.title=ARTICULOS\r
+start.content.new=nuevos artículos\r
+start.show=mostrar\r
+start.content.newswire=newswire\r
+start.content.feature=presentación\r
+start.content.topicspecial=especiales-por-tema\r
+start.content.startspecial=especiales-página-de-inicio\r
+start.content.not_published=artículos aun sin publicar\r
+start.content.with_media=con recursos mediáticos\r
+start.content.last_changes=últimos cambios\r
+start.content.with_comments=con comentarios de propósito interno\r
+start.content.search=buscar\r
+start.generate.title=GENERAR MANUALMENTE\r
+start.generate.all.title=todas las areas\r
+start.generate.all.new=todo nuevo (estándar, actualización en la web > 5min.)\r
+start.generate.parts.title=partes específicas del website\r
+start.generate.startpages.new=nueva página de inicio\r
+start.generate.all_forced=todos (forzado)\r
+start.generate.all_sync=todos (forzado y sincronizado)\r
+start.generate.content.new=nuevo contenido\r
+start.generate.topics.new=nuevos temas\r
+start.generate.postings.new=nuevos envios abiertos\r
+start.generate.images.new=nuevas imágenes\r
+start.generate.audio.new=nuevos ficheros de audio\r
+start.generate.video.new=nuevos ficheros de video\r
+start.generate.other.new=otros recursos mediáticos nuevos\r
+start.generate.navigation=navegación\r
+start.coverage.title=COBERTURA\r
+start.topics.title=TEMAS\r
+start.images.title=MATERIAL GRAFICO\r
+start.mediafolder.title=CARPETA DE RECURSOS MEDIATICOS\r
+start.languages.title=TÍTULO\r
+start.imcs.title=IMCS\r
+start.messageboard.title=Mensajería Interna\r
+start.messageboard.no_messages=no hay mensajes\r
+\r
+# topic\r
+topic.htmltitle=indymedia | tema\r
+topic.title=Nombre\r
+topic.description=descripción\r
+topic.filename=Nombre del fichero\r
+topic.main_url=página de información principal\r
+topic.archive_url=URL del archivo\r
+\r
+topiclist.htmltitle=indymedia | lista de temas\r
+\r
+# users\r
+user.htmltitle=indymedia | usuario\r
+user.login=login\r
+user.password=password\r
+user.admin=administrador\r
+\r
+userlist.htmltitle=indymedia | lista de usuarios\r
+\r
+# head\r
+head.start=inicio\r
+head.logout=salir\r
+head.help=ayuda\r
+head.search=buscar\r
+head.logged_in=estás registrado\r
+\r
+# foot\r
+foot.top=arriba\r
+\r
+\r
+########## error ##########\r
+\r
+error.htmltitle=indymedia | error\r
+error.title=oi! oi! oi!\r
+error.text=El siguiente mensaje puede que no le sea de mucha ayuda, pero seguramente lo será para <a href="mailto:{0}">{1}</a>:\r
+error.text2=Por favor envíe un mensaje con el <font color="Red">texto que aparece en rojo</font> y una descripción detallada a la siguiente dirección <a href="mailto:{0}">{1}</a>. Gracias!\r
+\r
+\r
+usererror.htmltitle=indymedia | error de datos\r
+usererror.title=oi! oi! oi!\r
+usererror.text=Los datos que ha introducido han causado el siguiente error:\r
+usererror.what_to_do=Por favor, pulse el botón para volver e intentelo de nuevo\r
+\r
+\r
+########## producer ##########\r
+\r
+producer.content.htmltitle=mir.indymedia:\r
+producer.content.email=email\r
+producer.content.homepage=Homepage\r
+producer.content.comment=Haga un comentario sobre este artículo\r
+producer.copyright= Copyright © 2002 Indymedia Bolivia - Qollasuyu - Ivi Iyambae<br> Esta publicaci\97n es <a href="http://www.gnu.org/copyleft/copyleft.es.html">copyleft</a>. Por tanto, se permite difundir, citar y copiar literalmente sus materiales, de forma \92ntegra o parcial, por cualquier medio y para cualquier prop\97sito, siempre que se mantenga esta nota y se cite procedencia. Indymedia Euskal Herria no asume ninguna responsabilidad por el material publicado en este sitio, salvo sobre lo que aparece en la columna central. Toda la responsabilidad para verificar la veracidad y los derechos de reproducci\97n de un env\92o corresponden al autor que lo publica. Al publicar material en este sitio, el o la autora del env\92o asume que puede ser redistribuido libremente. \r
+producer.contact=Contacto\r
+producer.openposting.htmltitle=mir.indymedia:\r
+producer.startpage.htmltitle=mir.indymedia: the mir-coders-website\r
+producer.topiclist.htmltitle=mir.indymedia:\r
+\r
+\r
+########## open ##########\r
+\r
+open.optional=opcional\r
+open.required=requerido\r
+\r
+open.comment.htmltitle=indymedia | confirmar comentario\r
+open.comment.title=Añadiendo un comentario al artículo\r
+open.comment.note=Unos comentarios sobre como escribir un comentario en Indymedia.\r
+open.comment.formtitle=Formulario-del-comentario\r
+open.comment.title=Título del comentario\r
+open.comment.name=su nombre\r
+open.comment.email=su email\r
+open.comment.url=su dirección web\r
+open.comment.phone=su número de teléfono\r
+open.comment.address=su dirección\r
+open.comment.language=idioma de su comentario\r
+open.comment.text=su comentario\r
+open.comment.submit=envíar comentario\r
+open.comment.reset=limpiar formulario\r
+\r
+\r
+open.commentdone.htmltitle=indymedia | envío abierto\r
+open.commentdone.thanks=Su comentario está de camino!\r
+open.commentdone.wait=In wenigen Minuten ist Deine Ergänzung unter dem ergänzten Artikel.<br>Manchmal kann es aber aufgrund technischer Probleme etwas dauern bis sie erscheint.<br>\r
+open.commentdone.criteria=Die Moderationskriterien von indymedia kannst Du <a href="http://de.indymedia.org/static/moderation.html" target="_blank">hier</a> nachlesen.\r
+open.commentdone.stay_calm=Gedulde Dich einen Moment - Es lohnt sich!\r
+open.commentdone.back=Zur&uuml;ck zum kommentierten Artikel\r
+\r
+\r
+open.commentdupe.htmltitle=indymedia | envío abierto - comentario duplicado\r
+open.commentdupe.title=Mantenga la calma unos breves instantes.\r
+open.commentdupe.explanation=Probablemente haya apretado el botón de recarga o enviado el comentario en una segunda ocasión. Si puede leer esto, significa que su comentario ha sido recibido con éxito y será incluido en la página de artículos en breves instantes.\r
+open.commentdupe.no_panic=No se altere!\r
+open.commentdupe.back=Volver al artículo comentado\r
+\r
+\r
+open.posting.htmltitle=indymedia | envío abierto\r
+open.posting.meta.description=Indymedia | Centro de Periodismo Independiente\r
+open.posting.meta.author=Colectivo IMC\r
+open.posting.meta.keywords=Periodismo Libre\r
+open.posting.jump_to_form=Ir directamente al formulario.\r
+open.posting.title=Publique su artículo\r
+open.posting.nr_of_media=Número de recursos mediáticos\r
+open.posting.nr_of_media.info=(wenn Du mehr als eine Datei hochladen willst, bitte hier die Anzahl eintragen und den Knopf drücken, <b>bevor</b> Du weitere Felder ausfüllst.)\r
+open.posting.nr_of_media.submit=Anzahl festlegen\r
+open.posting.form.title=Formulario de publicación\r
+open.posting.title=<b>Título</b> de su artículo\r
+open.posting.title.info=(Bitte wähle einen möglichst klaren, aussagekräftigen Titel.)\r
+open.posting.topic=<b>Thema</b> Deines Beitrags\r
+open.posting.topic.info=(Mehrfachwahl ist möglich. Bitte dazu die [Strg]- bzw [Ctrl]-Taste benutzen)\r
+open.posting.author=<b>autor</b> de este artículo\r
+open.posting.abstract=Descripción <b>breve</b> de su artículo\r
+open.posting.abstract.info=(Sie soll den LeserInnen schnell vermitteln, worum es in Deinem Beitrag geht. Falls Du den ersten Absatz Deines Artikels dazu wählst, achte bitte darauf ihn im Haupttextfeld weiter unten nicht nochmal einzusetzen.)\r
+open.posting.abstract.constraint=(que no exceda de <b>5 líneas</b>)\r
+open.posting.contact.info=La información de contacto es opcional pero ayuda a que otras personas puedan ponerse en contacto con usted.\r
+open.posting.email=su dirección de email\r
+open.posting.url=su dirección web\r
+open.posting.address=su dirección personal\r
+open.posting.phone=su número de teléfono\r
+open.posting.language=idioma de su artículo\r
+open.posting.text=su <b>artículo</b>\r
+open.posting.text.info=ponga aquí el texto de su artículo\r
+open.posting.media=recursos mediáticos\r
+open.posting.media.info=cargue sus ficheros de medios (de momento tan solo se aceptan jpg|gif|mp3|avi|qt|mpeg)\r
+open.posting.media.howto=(Dazu wählst Du mit "Durchsuchen.." die entsprechende Datei auf Deiner Festplatte aus.\r
+open.posting.media.media=Media\r
+open.posting.media.title=subtítulo de los recursos mediáticos\r
+open.posting.submit.info=Bitte drücke den Verschicken-Knopf<b> nur einmal</b>!<br> In wenigen Minuten erscheind Dein Beitrag dann auf der <a href="http://de.indymedia.org/open.html" target="_blank"> <b>"Open Posting"</b></a> - Seite. &nbsp; Das ist nicht die Startseite.<br> Manchmal kann es aber aufgrund technischer Probleme etwas dauern bis er erscheint.\r
+open.posting.criteria=Die <b>Moderationskriterien</b> kannst Du <a href="http://de.indymedia.org/static/moderation.html" target="_blank"><b>hier nachlesen</b></a>\r
+open.posting.submit=Enviar (la paciencia es una virtud!!)\r
+open.posting.reset=Limpiar formulario\r
+\r
+\r
+open.postingdone.htmltitle=indymedia | open posting\r
+open.postingdone.title=Hurra, Du hast Deinen Artikel abgeschickt!\r
+open.postingdone.info=Dein Artikel landet in einigen Minuten auf der <a href="http://de.indymedia.org/open.html">"Open Posting"</a> - Seite. Das ist nicht die Startseite. Die Moderationskriterien kannst Du <a href="http://de.indymedia.org/static/moderation.html">hier lesen</a>\r
+open.postingdone.stay_calm=Gedulde Dich einen Moment! Es lohnt sich!\r
+open.postingdone.back=Zur&uuml;ck\r
+\r
+\r
+open.postingdupe.htmltitle=indymedia | envío abierto - envio duplicado\r
+open.postingdupe.title=Mantenga la calma, su envio será procesado en breves instantes.\r
+open.postingdupe.explanation=  Posiblemente haya pulsado el botón de recarga de su navegador, o enviado su articulo por segunda vez\r
+                                       Si está leyendo este texto, significa que su envío ha sido recibido con éxito\r
+                                       y que será incluido en la pagina de artículos en breves instantes.\r
+                               <br>\r
+                                       Como detalle técnico, este imc está conectado a un servidor proxy\r
+                                       que no es actualizado cada minuto.\r
+open.postingdupe.no_panic=No pierda los estribos!\r
+open.postingdupe.back=Atrás\r
diff --git a/bundles/admin_qu.properties b/bundles/admin_qu.properties
new file mode 100755 (executable)
index 0000000..f8376a1
--- /dev/null
@@ -0,0 +1,383 @@
+########## admin ##########\r
+\r
+# general\r
+yes=sí\r
+no=no\r
+dontcare=no importa\r
+all=todo\r
+\r
+# actions\r
+insert=insertar\r
+save=guardar\r
+edit=editar\r
+delete=borrar\r
+add=añadir\r
+filter=filtrar\r
+attach=vincular\r
+list=mostrar lista\r
+back=atrás\r
+cancel=cancelar\r
+\r
+# records\r
+records=registros\r
+show_from_to=mostrando entradas desde {0} hasta {1}\r
+no_matches_found=No se encontraron resultados!\r
+list.next=siguiente\r
+list.previous=anterior\r
+\r
+# media - used by image, audio, video and other media\r
+media.created=creado\r
+media.changed=cambiado\r
+media.published=publicado\r
+media.format=Formato\r
+media.rights=Copyright\r
+media.type=Tipo\r
+media.mediafolder=Carpeta de recursos mediáticos\r
+media.title=Título\r
+media.description=Descripción\r
+media.date=Fecha\r
+media.location=Lugar de origen\r
+media.creator=Creador\r
+media.keywords=Palabras clave\r
+media.comment=Comentario\r
+media.source=Origen\r
+media.is_published=Disponible para publicación\r
+media.icon=Icono\r
+medialist.search_text_in=Buscar texto en\r
+\r
+# image\r
+image.htmltitle=indymedia | imagen\r
+imagelist.htmltitle=indymedia | lista de imagenes\r
+\r
+# audio\r
+audio.htmltitle=indymedia | audio\r
+audiolist.htmltitle=indymedia | lista de audio\r
+\r
+# video\r
+video.htmltitle=indymedia | video\r
+videolist.htmltitle=indymedia | lista de video\r
+\r
+# other\r
+other_media.htmltitle=indymedia | otros recursos mediáticos\r
+other_media.htmltitle=indymedia | lista de recursos mediáticos\r
+\r
+# breaking\r
+breaking.htmltitle=indymedia | últimas noticias\r
+breakinglist.htmltitle=indymedia | listado de últimas noticias\r
+breaking.textinfo=(max. 5 líneas / 250 caracteres)\r
+breaking.text=texto\r
+breaking.date=fecha\r
+\r
+\r
+# comment\r
+comment.htmltitle=indymedia | commentario\r
+comment.date=fecha\r
+comment.title=título\r
+comment.published=publicado\r
+comment.text=texto-del-comentario\r
+comment.address=dirección\r
+comment.phone=teléfono\r
+comment.email=email\r
+comment.url=url\r
+comment.creator=autor\r
+comment.article=del artículo\r
+\r
+commentlist.htmltitle=indymedia | lista de comentarios\r
+commentlist.produced=producido\r
+commentlist.hidden=oculto\r
+commentlist.search=buscar!\r
+\r
+# confirm\r
+confirm.htmltitle=indymedia | confirmar borrado\r
+confirm.really_delete=Desea borrar esta entrada?\r
+\r
+# content\r
+content.htmltitle=indymedia | contenido\r
+content.owner=Propietario\r
+content.topic=Tema\r
+content.feature=Característica\r
+content.title=titulo largo\r
+content.subtitle=subtítulo/título de contexto\r
+content.location=Lugar de origen\r
+content.creator=autor\r
+content.creator.email=Email\r
+content.creator.url=Web\r
+content.creator.address=Dirección\r
+content.creator.telephone=Teléfono\r
+content.abstract=Descripción breve\r
+content.content=Contenido\r
+content.html=es HTML?\r
+content.comment=Comentario interno\r
+content.internal=(propósito interno)\r
+content.attachments=Vínculos\r
+content.images=Imágenes\r
+content.audio=Audio\r
+content.video=Video\r
+content.other=Otros recursos mediáticos\r
+content.media=Recursos mediáticos\r
+content.addimage=añadir imagen\r
+content.addaudio=añadir audio\r
+content.addvideo=añadir video\r
+content.addother=añadir otros recursos mediáticos\r
+content.creationdate=fecha\r
+content.modificationdate=último cambio\r
+content.status=Estado\r
+content.type=Tipo de artículo\r
+\r
+contentlist.htmltitle=indymedia | lista de contenidos\r
+\r
+# language\r
+language.htmltitle=indymedia | idiomas\r
+language.name=idioma\r
+language.code=Código del idioma\r
+\r
+languagelist.htmltitle=indymedia | lista de idiomas\r
+\r
+# imcs\r
+linkimcs.htmltitle=indymedia | Enlaces a IMCs\r
+linkimcs.name=Nombre\r
+linkimcs.continent=Continente\r
+linkimcs.new_parent=Nuevo Ancestro\r
+linkimcs.url=URL\r
+linkimcs.sort_by=Criterio de orden\r
+linkimcs.language=Idioma\r
+linkimcs.parent=ancestro\r
+\r
+linkimcslist.htmltitle=indymedia | Lista de enlaces a IMCs\r
+linkimcslist.search_in=Buscar texto en\r
+\r
+# login\r
+login.htmltitle=indymedia | registro\r
+login.info=Esta zona es accesible exclusivamente a grupos autorizados. Si desea colaborar como editor, por favor contacte con nosotros en\r
+login.title=login\r
+login.name=Login\r
+login.password=Password\r
+login.language=Idioma\r
+login.language.english=Ingl\8es\r
+login.language.german=Alem\87n\r
+login.language.spanish=Espa\96ol\r
+login.language.guarani=Guaran\92\r
+login.language.aymara=Aymara\r
+login.language.quechua=Quechua\r
+login.submit=  Envíar\r
+\r
+# mediafolder\r
+mediafolder.htmltitle=indymedia | carpeta de recursos mediáticos\r
+mediafolder.date=fecha\r
+mediafolder.name=nombre\r
+mediafolder.location=lugar de origen\r
+mediafolder.keywords=palabras clave\r
+mediafolder.comment=commentario\r
+\r
+mediafolderlist.htmltitle=indymedia | lista de carpetas de recursos mediáticos\r
+\r
+# message\r
+message.htmltitle=indymedia | mensajes\r
+message.date=fecha\r
+message.title=título\r
+message.creator=Autor\r
+message.text=texto\r
+message.textinfo=(max. 5 líneas / 250 caracteres)\r
+\r
+messagelist.htmltitle=indymedia | lista de mensajes\r
+\r
+# feature\r
+feature.htmltitle=indymedia | presentación\r
+feature.title=Título\r
+feature.published=publicado\r
+feature.is_published=está publicado\r
+feature.is_not_published=no está publicado\r
+feature.filename=Nombre del fichero\r
+feature.abstract=Descripción breve\r
+feature.link=Enlace\r
+\r
+featurelist.htmltitle=indymedia | lista de presentaciones\r
+\r
+# admin start page\r
+start.htmltitle=indymedia | administración\r
+start.openpostings.title=ENVÍOSABIERTOS\r
+start.comments.title=COMENTARIOS\r
+start.breaking.title=ÚLTIMAS NOTICIAS\r
+start.breaking.new=últimas noticias recientes\r
+start.content.title=ARTICULOS\r
+start.content.new=nuevos artículos\r
+start.show=mostrar\r
+start.content.newswire=newswire\r
+start.content.feature=presentación\r
+start.content.topicspecial=especiales-por-tema\r
+start.content.startspecial=especiales-página-de-inicio\r
+start.content.not_published=artículos aun sin publicar\r
+start.content.with_media=con recursos mediáticos\r
+start.content.last_changes=últimos cambios\r
+start.content.with_comments=con comentarios de propósito interno\r
+start.content.search=buscar\r
+start.generate.title=GENERAR MANUALMENTE\r
+start.generate.all.title=todas las areas\r
+start.generate.all.new=todo nuevo (estándar, actualización en la web > 5min.)\r
+start.generate.parts.title=partes específicas del website\r
+start.generate.startpages.new=nueva página de inicio\r
+start.generate.all_forced=todos (forzado)\r
+start.generate.all_sync=todos (forzado y sincronizado)\r
+start.generate.content.new=nuevo contenido\r
+start.generate.topics.new=nuevos temas\r
+start.generate.postings.new=nuevos envios abiertos\r
+start.generate.images.new=nuevas imágenes\r
+start.generate.audio.new=nuevos ficheros de audio\r
+start.generate.video.new=nuevos ficheros de video\r
+start.generate.other.new=otros recursos mediáticos nuevos\r
+start.generate.navigation=navegación\r
+start.coverage.title=COBERTURA\r
+start.topics.title=TEMAS\r
+start.images.title=MATERIAL GRAFICO\r
+start.mediafolder.title=CARPETA DE RECURSOS MEDIATICOS\r
+start.languages.title=TÍTULO\r
+start.imcs.title=IMCS\r
+start.messageboard.title=Mensajería Interna\r
+start.messageboard.no_messages=no hay mensajes\r
+\r
+# topic\r
+topic.htmltitle=indymedia | tema\r
+topic.title=Nombre\r
+topic.description=descripción\r
+topic.filename=Nombre del fichero\r
+topic.main_url=página de información principal\r
+topic.archive_url=URL del archivo\r
+\r
+topiclist.htmltitle=indymedia | lista de temas\r
+\r
+# users\r
+user.htmltitle=indymedia | usuario\r
+user.login=login\r
+user.password=password\r
+user.admin=administrador\r
+\r
+userlist.htmltitle=indymedia | lista de usuarios\r
+\r
+# head\r
+head.start=inicio\r
+head.logout=salir\r
+head.help=ayuda\r
+head.search=buscar\r
+head.logged_in=estás registrado\r
+\r
+# foot\r
+foot.top=arriba\r
+\r
+\r
+########## error ##########\r
+\r
+error.htmltitle=indymedia | error\r
+error.title=oi! oi! oi!\r
+error.text=El siguiente mensaje puede que no le sea de mucha ayuda, pero seguramente lo será para <a href="mailto:{0}">{1}</a>:\r
+error.text2=Por favor envíe un mensaje con el <font color="Red">texto que aparece en rojo</font> y una descripción detallada a la siguiente dirección <a href="mailto:{0}">{1}</a>. Gracias!\r
+\r
+\r
+usererror.htmltitle=indymedia | error de datos\r
+usererror.title=oi! oi! oi!\r
+usererror.text=Los datos que ha introducido han causado el siguiente error:\r
+usererror.what_to_do=Por favor, pulse el botón para volver e intentelo de nuevo\r
+\r
+\r
+########## producer ##########\r
+\r
+producer.content.htmltitle=mir.indymedia:\r
+producer.content.email=email\r
+producer.content.homepage=Homepage\r
+producer.content.comment=Haga un comentario sobre este artículo\r
+producer.copyright= Copyright © 2002 Indymedia Bolivia - Qollasuyu - Ivi Iyambae<br> Esta publicaci\97n es <a href="http://www.gnu.org/copyleft/copyleft.es.html">copyleft</a>. Por tanto, se permite difundir, citar y copiar literalmente sus materiales, de forma \92ntegra o parcial, por cualquier medio y para cualquier prop\97sito, siempre que se mantenga esta nota y se cite procedencia. Indymedia Euskal Herria no asume ninguna responsabilidad por el material publicado en este sitio, salvo sobre lo que aparece en la columna central. Toda la responsabilidad para verificar la veracidad y los derechos de reproducci\97n de un env\92o corresponden al autor que lo publica. Al publicar material en este sitio, el o la autora del env\92o asume que puede ser redistribuido libremente. \r
+producer.contact=Contacto\r
+producer.openposting.htmltitle=mir.indymedia:\r
+producer.startpage.htmltitle=mir.indymedia: the mir-coders-website\r
+producer.topiclist.htmltitle=mir.indymedia:\r
+\r
+\r
+########## open ##########\r
+\r
+open.optional=opcional\r
+open.required=requerido\r
+\r
+open.comment.htmltitle=indymedia | confirmar comentario\r
+open.comment.title=Añadiendo un comentario al artículo\r
+open.comment.note=Unos comentarios sobre como escribir un comentario en Indymedia.\r
+open.comment.formtitle=Formulario-del-comentario\r
+open.comment.title=Título del comentario\r
+open.comment.name=su nombre\r
+open.comment.email=su email\r
+open.comment.url=su dirección web\r
+open.comment.phone=su número de teléfono\r
+open.comment.address=su dirección\r
+open.comment.language=idioma de su comentario\r
+open.comment.text=su comentario\r
+open.comment.submit=envíar comentario\r
+open.comment.reset=limpiar formulario\r
+\r
+\r
+open.commentdone.htmltitle=indymedia | envío abierto\r
+open.commentdone.thanks=Su comentario está de camino!\r
+open.commentdone.wait=In wenigen Minuten ist Deine Ergänzung unter dem ergänzten Artikel.<br>Manchmal kann es aber aufgrund technischer Probleme etwas dauern bis sie erscheint.<br>\r
+open.commentdone.criteria=Die Moderationskriterien von indymedia kannst Du <a href="http://de.indymedia.org/static/moderation.html" target="_blank">hier</a> nachlesen.\r
+open.commentdone.stay_calm=Gedulde Dich einen Moment - Es lohnt sich!\r
+open.commentdone.back=Zur&uuml;ck zum kommentierten Artikel\r
+\r
+\r
+open.commentdupe.htmltitle=indymedia | envío abierto - comentario duplicado\r
+open.commentdupe.title=Mantenga la calma unos breves instantes.\r
+open.commentdupe.explanation=Probablemente haya apretado el botón de recarga o enviado el comentario en una segunda ocasión. Si puede leer esto, significa que su comentario ha sido recibido con éxito y será incluido en la página de artículos en breves instantes.\r
+open.commentdupe.no_panic=No se altere!\r
+open.commentdupe.back=Volver al artículo comentado\r
+\r
+\r
+open.posting.htmltitle=indymedia | envío abierto\r
+open.posting.meta.description=Indymedia | Centro de Periodismo Independiente\r
+open.posting.meta.author=Colectivo IMC\r
+open.posting.meta.keywords=Periodismo Libre\r
+open.posting.jump_to_form=Ir directamente al formulario.\r
+open.posting.title=Publique su artículo\r
+open.posting.nr_of_media=Número de recursos mediáticos\r
+open.posting.nr_of_media.info=(wenn Du mehr als eine Datei hochladen willst, bitte hier die Anzahl eintragen und den Knopf drücken, <b>bevor</b> Du weitere Felder ausfüllst.)\r
+open.posting.nr_of_media.submit=Anzahl festlegen\r
+open.posting.form.title=Formulario de publicación\r
+open.posting.title=<b>Título</b> de su artículo\r
+open.posting.title.info=(Bitte wähle einen möglichst klaren, aussagekräftigen Titel.)\r
+open.posting.topic=<b>Thema</b> Deines Beitrags\r
+open.posting.topic.info=(Mehrfachwahl ist möglich. Bitte dazu die [Strg]- bzw [Ctrl]-Taste benutzen)\r
+open.posting.author=<b>autor</b> de este artículo\r
+open.posting.abstract=Descripción <b>breve</b> de su artículo\r
+open.posting.abstract.info=(Sie soll den LeserInnen schnell vermitteln, worum es in Deinem Beitrag geht. Falls Du den ersten Absatz Deines Artikels dazu wählst, achte bitte darauf ihn im Haupttextfeld weiter unten nicht nochmal einzusetzen.)\r
+open.posting.abstract.constraint=(que no exceda de <b>5 líneas</b>)\r
+open.posting.contact.info=La información de contacto es opcional pero ayuda a que otras personas puedan ponerse en contacto con usted.\r
+open.posting.email=su dirección de email\r
+open.posting.url=su dirección web\r
+open.posting.address=su dirección personal\r
+open.posting.phone=su número de teléfono\r
+open.posting.language=idioma de su artículo\r
+open.posting.text=su <b>artículo</b>\r
+open.posting.text.info=ponga aquí el texto de su artículo\r
+open.posting.media=recursos mediáticos\r
+open.posting.media.info=cargue sus ficheros de medios (de momento tan solo se aceptan jpg|gif|mp3|avi|qt|mpeg)\r
+open.posting.media.howto=(Dazu wählst Du mit "Durchsuchen.." die entsprechende Datei auf Deiner Festplatte aus.\r
+open.posting.media.media=Media\r
+open.posting.media.title=subtítulo de los recursos mediáticos\r
+open.posting.submit.info=Bitte drücke den Verschicken-Knopf<b> nur einmal</b>!<br> In wenigen Minuten erscheind Dein Beitrag dann auf der <a href="http://de.indymedia.org/open.html" target="_blank"> <b>"Open Posting"</b></a> - Seite. &nbsp; Das ist nicht die Startseite.<br> Manchmal kann es aber aufgrund technischer Probleme etwas dauern bis er erscheint.\r
+open.posting.criteria=Die <b>Moderationskriterien</b> kannst Du <a href="http://de.indymedia.org/static/moderation.html" target="_blank"><b>hier nachlesen</b></a>\r
+open.posting.submit=Enviar (la paciencia es una virtud!!)\r
+open.posting.reset=Limpiar formulario\r
+\r
+\r
+open.postingdone.htmltitle=indymedia | open posting\r
+open.postingdone.title=Hurra, Du hast Deinen Artikel abgeschickt!\r
+open.postingdone.info=Dein Artikel landet in einigen Minuten auf der <a href="http://de.indymedia.org/open.html">"Open Posting"</a> - Seite. Das ist nicht die Startseite. Die Moderationskriterien kannst Du <a href="http://de.indymedia.org/static/moderation.html">hier lesen</a>\r
+open.postingdone.stay_calm=Gedulde Dich einen Moment! Es lohnt sich!\r
+open.postingdone.back=Zur&uuml;ck\r
+\r
+\r
+open.postingdupe.htmltitle=indymedia | envío abierto - envio duplicado\r
+open.postingdupe.title=Mantenga la calma, su envio será procesado en breves instantes.\r
+open.postingdupe.explanation=  Posiblemente haya pulsado el botón de recarga de su navegador, o enviado su articulo por segunda vez\r
+                                       Si está leyendo este texto, significa que su envío ha sido recibido con éxito\r
+                                       y que será incluido en la pagina de artículos en breves instantes.\r
+                               <br>\r
+                                       Como detalle técnico, este imc está conectado a un servidor proxy\r
+                                       que no es actualizado cada minuto.\r
+open.postingdupe.no_panic=No pierda los estribos!\r
+open.postingdupe.back=Atrás\r
diff --git a/bundles/producer_en.properties b/bundles/producer_en.properties
new file mode 100755 (executable)
index 0000000..e074c6f
--- /dev/null
@@ -0,0 +1,24 @@
+general.dateformat = dd/MM/yyyy hh:mm
+general.city.Amsterdam.title = emsterdem
+general.city.London.title = London
+general.city.Berlin.title = Berlijn
+general.topic.Repression.title = repressiun
+general.topic.Feminism.title = feminisme
+general.read.text = Read
+
+article.title.prefix = bolivia.indymedia.org |
+article.email.prefix = e-mail:
+article.homepage.prefix = Homepage:
+article.makecomment.text = Make a quick comment on this article
+
+startpage.title = bolivia.indymedia.org | IMC Bolivia
+
+navigation.languages.caption = Languages:
+navigation.cities.caption = Cities:
+navigation.topics.caption = Topics:
+navigation.publish.text = Publish
+
+topicnavigation.page.prefix = pagina
+
+
+
diff --git a/bundles/producer_es.properties b/bundles/producer_es.properties
new file mode 100755 (executable)
index 0000000..a462b8a
--- /dev/null
@@ -0,0 +1,26 @@
+general.dateformat = dd/MM/yyyy hh:mm
+general.city.Amsterdam.title = emsterdem
+general.city.London.title = Londres
+general.city.Berlin.title = Berlin
+general.topic.Repression.title = repressiun
+general.topic.Feminism.title = feminisme
+general.read.text = Read
+
+article.title.prefix = bolivia.indymedia.org |
+article.email.prefix = e-mail:
+article.homepage.prefix = Homepage:
+article.makecomment.text = Make a quick comment on this article
+
+openposting.
+
+startpage.title = bolivia.indymedia.org | IMC Bolivia
+
+navigation.languages.caption = Linguas:
+navigation.cities.caption = Ciudades:
+navigation.topics.caption = Temas:
+navigation.publish.text = Publicar
+
+topicnavigation.page.prefix = pagina
+
+
+
diff --git a/lib/lucene-1.2.jar b/lib/lucene-1.2.jar
new file mode 100755 (executable)
index 0000000..ff9b900
Binary files /dev/null and b/lib/lucene-1.2.jar differ
diff --git a/lib/multex2c.jar b/lib/multex2c.jar
new file mode 100755 (executable)
index 0000000..d83d104
Binary files /dev/null and b/lib/multex2c.jar differ
diff --git a/scripts/createIndex.java b/scripts/createIndex.java
new file mode 100755 (executable)
index 0000000..028865e
--- /dev/null
@@ -0,0 +1,19 @@
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.index.IndexWriter;
+
+
+
+class createIndex{
+    public static void main(String[] args){
+       try{
+
+       IndexWriter indexWriter = new IndexWriter("/tmp/index/", new StandardAnalyzer(), true);
+
+       indexWriter.close();
+       //and make it owned by correct user?
+       }
+       catch (Exception e){
+           System.out.println(e.toString());
+       }
+    }
+}
index 7b94d9f..9db7350 100755 (executable)
@@ -1,4 +1,4 @@
-
+import freemarker.template.SimpleList;
 import freemarker.template.SimpleHash;
 import freemarker.template.SimpleScalar;
 import mir.misc.HTMLParseException;
@@ -6,9 +6,14 @@ import mir.misc.HTMLTemplateProcessor;
 import mir.misc.MirConfig;
 import mir.misc.StringUtil;
 import mir.servlet.*;
+import mir.producer.*;
+
+import mircoders.global.*;
+import mircoders.localizer.*;
 import mircoders.entity.EntityUsers;
 import mircoders.module.ModuleMessage;
 import mircoders.module.ModuleUsers;
+import mircoders.storage.DatabaseArticleType;
 import mircoders.storage.DatabaseMessages;
 import mircoders.storage.DatabaseUsers;
 
@@ -23,14 +28,18 @@ import java.lang.reflect.Method;
 import java.util.GregorianCalendar;
 import java.util.HashMap;
 import java.util.Locale;
+import java.util.*;
 
 /**
  * Mir.java - main servlet, that dispatches to servletmodules
  *
  * @author $Author: mh $
- * @version $Revision: 1.17 $ $Date: 2002/07/21 22:27:39 $
+ * @version $Revision: 1.18 $ $Date: 2002/08/25 19:00:06 $
  *
  * $Log: Mir.java,v $
+ * Revision 1.18  2002/08/25 19:00:06  mh
+ * merge of localization branch into HEAD. mh and zap
+ *
  * Revision 1.17  2002/07/21 22:27:39  mh
  * make the user error msg look nicer
  *
@@ -55,6 +64,7 @@ public class Mir extends AbstractServlet {
 
         long startTime = System.currentTimeMillis();
         long sessionConnectTime = 0;
+        EntityUsers userEntity;
         String http = "";
 
         // get the configration - this could conflict if 2 mirs are in the
@@ -65,6 +75,7 @@ public class Mir extends AbstractServlet {
         MirConfig.setServletName(getServletName());
 
         session = req.getSession(true);
+        userEntity = (EntityUsers) session.getAttribute("login.uid");
 
         if (req.getServerPort() == 443) http = "https"; else http = "http";
         res.setContentType("text/html; charset="
@@ -76,19 +87,23 @@ public class Mir extends AbstractServlet {
         /** @todo for cleanup and readability this should be moved to
          *  method loginIfNecessary() */
 
+        if (moduleName!=null && moduleName.equals("direct")) {
+          //...
+        }
+
         // Authentifizierung
-        if (moduleName != null && moduleName.equals("login")) {
+        if ((moduleName != null && moduleName.equals("login")) || (userEntity==null)) {
             String user = req.getParameter("login");
             String passwd = req.getParameter("password");
             theLog.printDebugInfo("--login: evaluating for user: " + user);
-            EntityUsers userEntity = allowedUser(user, passwd);
+            userEntity = allowedUser(user, passwd);
             if (userEntity == null) {
                 // login failed: redirecting to login
                 theLog.printWarning("--login: failed!");
                 _sendLoginPage(res, req, res.getWriter());
                 return;
             }
-            else {
+            else if (moduleName!=null && moduleName.equals("login")) {
                 // login successful
 
                 theLog.printInfo("--login: successful! setting uid: " + userEntity.getId());
@@ -141,7 +156,6 @@ public class Mir extends AbstractServlet {
         }
 
         // Check if authed!
-        EntityUsers userEntity = (EntityUsers) session.getAttribute("login.uid");
         if (userEntity == null) {
             // redirect to loginpage
             String redirectString = req.getRequestURI();
@@ -300,9 +314,34 @@ public class Mir extends AbstractServlet {
             mergeData.put("login_user", userEntity);
             if (messageModule == null) messageModule = new ModuleMessage(DatabaseMessages.getInstance());
             mergeData.put("messages", messageModule.getByWhereClause(null, "webdb_create desc", 0, 10));
+
+            mergeData.put("articletypes", DatabaseArticleType.getInstance().selectByWhereClause("", "id", 0, 20));
+
+            SimpleList producersData = new SimpleList();
+            Iterator i = MirGlobal.localizer().producers().factories().entrySet().iterator();
+            while (i.hasNext()) {
+              Map.Entry entry = (Map.Entry) i.next();
+
+              SimpleList producerVerbs = new SimpleList();
+              Iterator j = ((ProducerFactory) entry.getValue()).verbs();
+              while (j.hasNext()) {
+                producerVerbs.add((String) j.next());
+              }
+
+              SimpleHash producerData = new SimpleHash();
+              producerData.put("key", (String) entry.getKey());
+              producerData.put("verbs", producerVerbs);
+
+              producersData.add(producerData);
+            }
+            mergeData.put("producers", producersData);
+
+
+
             HTMLTemplateProcessor.process(res, startTemplate, mergeData, out, getLocale(req));
         }
         catch (Exception e) {
+            e.printStackTrace(System.out);
             handleError(req, res, out, "error while trying to send startpage. " + e.toString());
         }
     }
index 8a8bb9a..c553363 100755 (executable)
@@ -25,7 +25,7 @@ import mircoders.storage.*;
 
 
 public class OpenMir extends AbstractServlet {
-  
+
   //private static boolean                confed=false;
   private static String lang;
   public HttpSession session;
@@ -49,9 +49,17 @@ public class OpenMir extends AbstractServlet {
     session = req.getSession();
 
     if(session.getAttribute("Language")==null){
-      setLanguage(session,getAcceptLanguage(req));
+      if (req.getParameter("language")!=null) {
+        setLanguage(session, req.getParameter("language"));
+      }
+      else {
+        setLanguage(session, getAcceptLanguage(req));
+      }
     }
 
+    if (req.getParameter("language")!=null)
+      setLocale(session, new Locale(req.getParameter("language"), "") );
+
     res.setContentType("text/html; charset="
                       +MirConfig.getProp("Mir.DefaultEncoding"));
     try {
@@ -70,14 +78,14 @@ public class OpenMir extends AbstractServlet {
   }
 
   private void handleUserError(HttpServletRequest req, HttpServletResponse res,
-                                                                                                                        PrintWriter out, String errorString) {
+                               PrintWriter out, String errorString) {
     try {
       theLog.printError(errorString);
       SimpleHash modelRoot = new SimpleHash();
       modelRoot.put("errorstring", new SimpleScalar(errorString));
       modelRoot.put("date", new SimpleScalar(StringUtil.date2readableDateTime(new GregorianCalendar())));
       HTMLTemplateProcessor.process(res,MirConfig.getProp("Mir.UserErrorTemplate"),
-                                                                                                                                               modelRoot, out, req.getLocale() );
+                                    modelRoot, out, req.getLocale() );
       out.close();
     }
     catch (Exception e) {
@@ -93,9 +101,9 @@ public class OpenMir extends AbstractServlet {
       SimpleHash modelRoot = new SimpleHash();
       modelRoot.put("errorstring", new SimpleScalar(errorString));
       modelRoot.put("date", new SimpleScalar(StringUtil.date2readableDateTime(
-                                                                                                                                                                                        new GregorianCalendar())));
+                                               new GregorianCalendar())));
       HTMLTemplateProcessor.process(res,MirConfig.getProp("Mir.ErrorTemplate"),
-                                                                                                                                               modelRoot,out, req.getLocale());
+                                    modelRoot,out, req.getLocale());
       out.close();
     }
     catch (Exception e) {
index 6e02e9b..1ea1029 100755 (executable)
 # GENERAL SETUP
 #
 
-Mir.Version=pre-1.0
+Mir.Version=localizer-0
 ClearXslCache=no
 StandardLanguage=de
 DirectOpenposting=yes
 
+Mir.Localizer=mircoders.localizer.basic.MirBasicLocalizer
+Mir.Localizer.Logfile=log/localizer.log
+Mir.Localizer.ProducerConfigFile=templates/producer/producers.xml
+
+
+
 #note that you can't make pdf's without making fo's
 GenerateFO=yes
 GeneratePDF=yes
 
 #on-time-password-protection
-PasswdProtection=yes
+PasswdProtection=no
 
 #use rsync to mirror the website to a remote-host
 Rsync=no
index 70006bf..bc5528d 100755 (executable)
@@ -25,7 +25,7 @@ public class ConfigChecker {
     rootNode = new Node();\r
   }\r
 \r
-  public void check(ConfigNode aNode) throws ConfigException {\r
+  public void check(ConfigNode aNode) throws ConfigFailure {\r
     getRootNode().check(aNode);\r
   }\r
 \r
@@ -63,7 +63,7 @@ public class ConfigChecker {
       addTypeConstraint(aPropertyName, aType);\r
     }\r
 \r
-    public void check(ConfigNode aNode) throws ConfigException {\r
+    public void check(ConfigNode aNode) throws ConfigFailure {\r
       Iterator iterator;\r
 \r
       iterator=constraints.iterator();\r
@@ -86,7 +86,7 @@ public class ConfigChecker {
         propertyName=aPropertyName;\r
       }\r
 \r
-      public void check(ConfigNode aNode) throws ConfigException {\r
+      public void check(ConfigNode aNode) throws ConfigFailure {\r
       };\r
     }\r
 \r
@@ -95,7 +95,7 @@ public class ConfigChecker {
         super(aPropertyName);\r
       }\r
 \r
-      public void check(ConfigNode aNode) throws ConfigException {\r
+      public void check(ConfigNode aNode) throws ConfigFailure {\r
         aNode.getRequiredStringProperty(propertyName);\r
       };\r
     }\r
@@ -109,7 +109,7 @@ public class ConfigChecker {
         type=aType;\r
       }\r
 \r
-      public void check(ConfigNode aNode) throws ConfigException {\r
+      public void check(ConfigNode aNode) throws ConfigFailure {\r
         switch(type) {\r
           case INTEGER:\r
             aNode.getOptionalIntegerProperty(propertyName, new Integer(0));\r
@@ -124,7 +124,7 @@ public class ConfigChecker {
             aNode.getOptionalBooleanProperty(propertyName, Boolean.FALSE);\r
             break;\r
           default:\r
-            throw new ConfigException("Invalid value for type in type constraint: "+new Integer(type).toString());\r
+            throw new ConfigFailure("Invalid value for type in type constraint: "+new Integer(type).toString());\r
         }\r
       }\r
     }\r
index 868bccb..a70aae0 100755 (executable)
@@ -8,12 +8,12 @@ public interface ConfigNode {
   public String getLocationDescription();\r
 \r
   public ConfigNode getSubNode(String aSubNodeName);\r
-  public Boolean getRequiredBooleanProperty(String aPropertyName) throws ConfigException;\r
-  public Integer getRequiredIntegerProperty(String aPropertyName) throws ConfigException;\r
-  public String getRequiredStringProperty(String aPropertyName) throws ConfigException;\r
-  public Double getRequiredDoubleProperty(String aPropertyName) throws ConfigException;\r
-  public Boolean getOptionalBooleanProperty(String aPropertyName, Boolean aDefaultValue) throws ConfigException;\r
-  public Integer getOptionalIntegerProperty(String aPropertyName, Integer aDefaultValue) throws ConfigException;\r
-  public String getOptionalStringProperty(String aPropertyName, String aDefaultValue) throws ConfigException;\r
-  public Double getOptionalDoubleProperty(String aPropertyName, Double aDefaultValue) throws ConfigException;\r
+  public Boolean getRequiredBooleanProperty(String aPropertyName) throws ConfigFailure;\r
+  public Integer getRequiredIntegerProperty(String aPropertyName) throws ConfigFailure;\r
+  public String getRequiredStringProperty(String aPropertyName) throws ConfigFailure;\r
+  public Double getRequiredDoubleProperty(String aPropertyName) throws ConfigFailure;\r
+  public Boolean getOptionalBooleanProperty(String aPropertyName, Boolean aDefaultValue) throws ConfigFailure;\r
+  public Integer getOptionalIntegerProperty(String aPropertyName, Integer aDefaultValue) throws ConfigFailure;\r
+  public String getOptionalStringProperty(String aPropertyName, String aDefaultValue) throws ConfigFailure;\r
+  public Double getOptionalDoubleProperty(String aPropertyName, Double aDefaultValue) throws ConfigFailure;\r
 }\r
index 03ecd53..d0c0355 100755 (executable)
@@ -26,7 +26,7 @@ public class ConfigReader {
     super();\r
   };\r
 \r
-  public void parseFile(String aFileName, ConfigNodeBuilder aRootNode) throws ConfigException {\r
+  public void parseFile(String aFileName, ConfigNodeBuilder aRootNode) throws ConfigFailure {\r
 \r
     try {\r
       SAXParserFactory parserFactory = SAXParserFactory.newInstance();\r
@@ -40,12 +40,12 @@ public class ConfigReader {
       handler.includeFile(aFileName);\r
     }\r
     catch (Throwable e) {\r
-      if (e instanceof SAXParseException && ((SAXParseException) e).getException() instanceof ConfigException) {\r
-        throw (ConfigException) ((SAXParseException) e).getException();\r
+      if (e instanceof SAXParseException && ((SAXParseException) e).getException() instanceof ConfigFailure) {\r
+        throw (ConfigFailure) ((SAXParseException) e).getException();\r
       }\r
       else {\r
         e.printStackTrace();\r
-        throw new ConfigException( e.getMessage() );\r
+        throw new ConfigFailure( e.getMessage() );\r
       }\r
     }\r
   }\r
@@ -78,7 +78,7 @@ public class ConfigReader {
       locator=aLocator;\r
     }\r
 \r
-    private void includeFile(String aFileName) throws ConfigException, SAXParseException, SAXException {\r
+    private void includeFile(String aFileName) throws ConfigFailure, SAXParseException, SAXException {\r
       File file;\r
       SAXParser parser;\r
       InputSource inputSource;\r
@@ -93,7 +93,7 @@ public class ConfigReader {
         System.err.println("about to include "+file.getCanonicalPath());\r
 \r
         if (includeFileStack.contains(file.getCanonicalPath())) {\r
-          throw new ConfigException("recursive inclusion of file "+file.getCanonicalPath(), getLocatorDescription(locator));\r
+          throw new ConfigFailure("recursive inclusion of file "+file.getCanonicalPath(), getLocatorDescription(locator));\r
         }\r
 \r
         parser=parserFactory.newSAXParser();\r
@@ -110,19 +110,19 @@ public class ConfigReader {
         }\r
       }\r
       catch (ParserConfigurationException e) {\r
-        throw new ConfigException("Internal exception while including \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));\r
+        throw new ConfigFailure("Internal exception while including \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));\r
       }\r
       catch (SAXParseException e) {\r
         throw e;\r
       }\r
-      catch (ConfigException e) {\r
+      catch (ConfigFailure e) {\r
         throw e;\r
       }\r
       catch (FileNotFoundException e) {\r
-        throw new ConfigException("Include file \""+aFileName+"\" not found: "+e.getMessage(), e, getLocatorDescription(locator));\r
+        throw new ConfigFailure("Include file \""+aFileName+"\" not found: "+e.getMessage(), e, getLocatorDescription(locator));\r
       }\r
       catch (IOException e) {\r
-        throw new ConfigException("unable to open include file \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));\r
+        throw new ConfigFailure("unable to open include file \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));\r
       }\r
 \r
     }\r
@@ -132,18 +132,18 @@ public class ConfigReader {
       level++;\r
       try {\r
         if (builder==null) {\r
-          throw new ConfigException("define, include and property tags cannot have content", getLocatorDescription(locator));\r
+          throw new ConfigFailure("define, include and property tags cannot have content", getLocatorDescription(locator));\r
         }\r
         if (aQualifiedName.equals(propertyTagName)) {\r
           String name=anAttributes.getValue(propertyNameAttribute);\r
           String value=anAttributes.getValue(propertyValueAttribute);\r
 \r
           if (name==null) {\r
-            throw new ConfigException("property has no name attribute", getLocatorDescription(locator));\r
+            throw new ConfigFailure("property has no name attribute", getLocatorDescription(locator));\r
           }\r
           else\r
           if (value==null) {\r
-            throw new ConfigException("property \""+name+"\" has no value attribute", getLocatorDescription(locator));\r
+            throw new ConfigFailure("property \""+name+"\" has no value attribute", getLocatorDescription(locator));\r
           }\r
 \r
           builder.addProperty(name, definesManager.resolve(value, getLocatorDescription(locator)), value, getLocatorDescription(locator));\r
@@ -155,11 +155,11 @@ public class ConfigReader {
           String value=anAttributes.getValue(defineValueAttribute);\r
 \r
           if (name==null) {\r
-            throw new ConfigException("define has no name attribute", getLocatorDescription(locator));\r
+            throw new ConfigFailure("define has no name attribute", getLocatorDescription(locator));\r
           }\r
           else\r
           if (value==null) {\r
-            throw new ConfigException("define \""+name+"\" has no value attribute", getLocatorDescription(locator));\r
+            throw new ConfigFailure("define \""+name+"\" has no value attribute", getLocatorDescription(locator));\r
           }\r
 \r
           definesManager.addDefine(name, definesManager.resolve(value, getLocatorDescription(locator)));\r
@@ -169,7 +169,7 @@ public class ConfigReader {
           String fileName=anAttributes.getValue(includeFileAttribute);\r
 \r
           if (fileName==null) {\r
-            throw new ConfigException("include has no file attribute", getLocatorDescription(locator));\r
+            throw new ConfigFailure("include has no file attribute", getLocatorDescription(locator));\r
           }\r
 \r
           includeFile(definesManager.resolve(fileName, getLocatorDescription(locator)));\r
@@ -180,7 +180,7 @@ public class ConfigReader {
           builder=builder.makeSubNode(aQualifiedName, getLocatorDescription(locator));\r
         }\r
       }\r
-      catch (ConfigException e) {\r
+      catch (ConfigFailure e) {\r
         throw new SAXParseException(e.getMessage(), locator, e);\r
       }\r
     }\r
@@ -193,7 +193,7 @@ public class ConfigReader {
     public void characters(char[] aBuffer, int aStart, int anEnd) throws SAXParseException {\r
       String text = new String(aBuffer, aStart, anEnd).trim();\r
       if ( text.length() > 0) {\r
-        throw new SAXParseException("Text not allowed", locator, new ConfigException("text not allowed", getLocatorDescription(locator)));\r
+        throw new SAXParseException("Text not allowed", locator, new ConfigFailure("text not allowed", getLocatorDescription(locator)));\r
       }\r
     }\r
   }\r
@@ -209,7 +209,7 @@ public class ConfigReader {
       defines.put(aName, anExpression);\r
     }\r
 \r
-    public String resolve(String anExpression, String aLocation) throws ConfigException {\r
+    public String resolve(String anExpression, String aLocation) throws ConfigFailure {\r
       int previousPosition = 0;\r
       int position;\r
       int endOfNamePosition;\r
@@ -239,7 +239,7 @@ public class ConfigReader {
               }\r
             }\r
             else {\r
-                throw new ConfigException("Missing }", aLocation);\r
+                throw new ConfigFailure("Missing }", aLocation);\r
             }\r
 \r
           }\r
index 9885f02..53fa7f1 100755 (executable)
@@ -15,7 +15,7 @@ public class MirConfiguration {
     rootNode = aRootNode;\r
   }\r
 \r
-  public MirConfiguration(String aFileName) throws ConfigException {\r
+  public MirConfiguration(String aFileName) throws ConfigFailure {\r
     super();\r
     rootNode = new ConfigSimpleNode();\r
 \r
index 21fce9c..cc94380 100755 (executable)
@@ -1,6 +1,6 @@
 package mir.config.exceptions;\r
 \r
-public class ConfigDefineNotKnownException extends ConfigException {\r
+public class ConfigDefineNotKnownException extends ConfigFailure {\r
   public ConfigDefineNotKnownException(String aMessage, String aLocation) {\r
     super (aMessage, aLocation);\r
   }\r
diff --git a/source/mir/config/exceptions/ConfigException.java b/source/mir/config/exceptions/ConfigException.java
deleted file mode 100755 (executable)
index f02c79f..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-package mir.config.exceptions;\r
-\r
-import java.io.*;\r
-\r
-public class ConfigException extends Exception {\r
-  private String locationDescription;\r
-  private Throwable cause;\r
-\r
-  public ConfigException (String aMessage, Throwable aCause, String aLocationDescription) {\r
-    super ("Configuration error at "+aLocationDescription+": "+aMessage);\r
-\r
-    locationDescription = aLocationDescription;\r
-    cause = aCause;\r
-  }\r
-\r
-  public ConfigException (String aMessage, String aLocationDescription) {\r
-    this (aMessage, (Throwable) null, aLocationDescription);\r
-  }\r
-\r
-  public ConfigException (String aMessage) {\r
-    this (aMessage, (Throwable) null, "?");\r
-  }\r
-}\r
diff --git a/source/mir/config/exceptions/ConfigFailure.java b/source/mir/config/exceptions/ConfigFailure.java
new file mode 100755 (executable)
index 0000000..be73355
--- /dev/null
@@ -0,0 +1,25 @@
+package mir.config.exceptions;
+
+import multex.Failure;
+
+import java.io.*;
+
+public class ConfigFailure extends Failure {
+  private String locationDescription;
+  private Throwable cause;
+
+  public ConfigFailure (String aMessage, Throwable aCause, String aLocationDescription) {
+    super ("Configuration error at "+aLocationDescription+": "+aMessage, aCause);
+
+    locationDescription = aLocationDescription;
+    cause = aCause;
+  }
+
+  public ConfigFailure (String aMessage, String aLocationDescription) {
+    this (aMessage, (Throwable) null, aLocationDescription);
+  }
+
+  public ConfigFailure (String aMessage) {
+    this (aMessage, (Throwable) null, "?");
+  }
+}
index 494227f..b0c6869 100755 (executable)
@@ -1,6 +1,6 @@
 package mir.config.exceptions;\r
 \r
-public class ConfigInvalidPropertyTypeException extends ConfigException {\r
+public class ConfigInvalidPropertyTypeException extends ConfigFailure {\r
   public ConfigInvalidPropertyTypeException(String aMessage, String aLocation) {\r
     super (aMessage, aLocation);\r
   }\r
index df19705..f80e233 100755 (executable)
@@ -1,6 +1,6 @@
 package mir.config.exceptions;\r
 \r
-public class ConfigMissingPropertyException extends ConfigException {\r
+public class ConfigMissingPropertyException extends ConfigFailure {\r
   public ConfigMissingPropertyException(String aMessage, String aLocation) {\r
     super (aMessage, aLocation);\r
   }\r
diff --git a/source/mir/entity/EntityBrowser.java b/source/mir/entity/EntityBrowser.java
new file mode 100755 (executable)
index 0000000..a320dde
--- /dev/null
@@ -0,0 +1,93 @@
+package mir.entity;\r
+\r
+import java.util.*;\r
+import mir.util.*;\r
+import mir.storage.*;\r
+import mir.entity.*;\r
+\r
+public class EntityBrowser implements RewindableIterator {\r
+\r
+  private StorageObject storage;\r
+  private String whereClause;\r
+  private String orderByClause;\r
+  private int batchSize;\r
+  private int toFetch;\r
+  private EntityList currentBatch;\r
+\r
+  private int skip;\r
+  private int limit;\r
+\r
+  private int batchPosition;\r
+  private int positionInBatch;\r
+\r
+  public EntityBrowser(StorageObject aStorage, String aWhereClause, String anOrderByClause,\r
+                       int aBatchSize, int aLimit, int aSkip) throws StorageObjectException {\r
+\r
+    storage=aStorage;\r
+    whereClause=aWhereClause;\r
+    orderByClause=anOrderByClause;\r
+    batchSize=aBatchSize;\r
+    skip=aSkip;\r
+    limit=aLimit;\r
+\r
+    rewind();\r
+  }\r
+\r
+  public EntityBrowser(StorageObject aStorage,\r
+          String aWhereClause, String anOrderByClause,\r
+          int aBatchSize) throws StorageObjectException {\r
+    this(aStorage, aWhereClause, anOrderByClause, aBatchSize, -1, 0);\r
+  }\r
+\r
+  public void readCurrentBatch(int aSkip) throws StorageObjectException {\r
+    currentBatch = storage.selectByWhereClause(whereClause, orderByClause, aSkip, batchSize);\r
+    batchPosition = aSkip;\r
+    positionInBatch = 0;\r
+  }\r
+\r
+  public void rewind() {\r
+    try {\r
+      readCurrentBatch(skip);\r
+    }\r
+    catch (Throwable t) {\r
+      throw new RuntimeException(t.getMessage());\r
+    }\r
+  }\r
+\r
+  public boolean hasNext() {\r
+    try {\r
+      if (limit>-1 && batchPosition+positionInBatch>=skip+limit)\r
+        return false;\r
+\r
+      if (positionInBatch>=currentBatch.size() && currentBatch.hasNextBatch()) {\r
+        readCurrentBatch(batchPosition+positionInBatch);\r
+      }\r
+\r
+      return (positionInBatch<currentBatch.size());\r
+    }\r
+    catch (Throwable t) {\r
+      throw new RuntimeException(t.getMessage());\r
+    }\r
+  }\r
+\r
+  public Object next() {\r
+    try {\r
+      if (hasNext()) {\r
+        Entity result = currentBatch.elementAt(positionInBatch);\r
+        positionInBatch=positionInBatch+1;\r
+\r
+        return result;\r
+      }\r
+      else {\r
+        return null;\r
+      }\r
+    }\r
+    catch (Throwable t) {\r
+      throw new RuntimeException(t.getMessage());\r
+    }\r
+  }\r
+\r
+  public void remove() {\r
+    throw new UnsupportedOperationException();\r
+  }\r
+}
\ No newline at end of file
diff --git a/source/mir/entity/QueryBuilder.java b/source/mir/entity/QueryBuilder.java
new file mode 100755 (executable)
index 0000000..2e18511
--- /dev/null
@@ -0,0 +1,56 @@
+package mir.entity;\r
+\r
+public class QueryBuilder {\r
+\r
+  private String whereClause;\r
+  private String orderByClause;\r
+\r
+  public QueryBuilder(){\r
+    whereClause = new String();\r
+    orderByClause = new String();\r
+  }\r
+\r
+  public void appendDescendingOrder(String anOrder) {\r
+    if (orderByClause.length()==0) {\r
+      orderByClause=anOrder+" desc";\r
+    }\r
+    else {\r
+      orderByClause=orderByClause+","+anOrder+" desc";\r
+    }\r
+  }\r
+\r
+  public void appendAscendingOrder(String anOrder) {\r
+    if (orderByClause.length()==0) {\r
+      orderByClause=anOrder+" asc";\r
+    }\r
+    else {\r
+      orderByClause=orderByClause+","+anOrder+" asc";\r
+    }\r
+  }\r
+\r
+  public void appendAndCondition(String aQualifier) {\r
+    if (whereClause.length()==0) {\r
+      whereClause = aQualifier;\r
+    }\r
+    else {\r
+      whereClause="("+whereClause+") and ("+aQualifier+")";\r
+    }\r
+  }\r
+\r
+  public void appendOrCondition(String aQualifier) {\r
+    if (whereClause.length()==0) {\r
+      whereClause = aQualifier;\r
+    }\r
+    else {\r
+      whereClause="("+whereClause+") or ("+aQualifier+")";\r
+    }\r
+  }\r
+\r
+  public String getWhereClause() {\r
+    return whereClause;\r
+  }\r
+\r
+  public String getOrderByClause() {\r
+    return orderByClause;\r
+  }\r
+}
\ No newline at end of file
diff --git a/source/mir/entity/adapter/EntityAdapter.java b/source/mir/entity/adapter/EntityAdapter.java
new file mode 100755 (executable)
index 0000000..4abc774
--- /dev/null
@@ -0,0 +1,122 @@
+package mir.entity.adapter;
+
+import java.util.*;
+import mir.entity.*;
+import mir.util.*;
+
+public class EntityAdapter implements Map {
+  private Entity entity;
+  private EntityAdapterDefinition definition;
+  private Map calculatedFieldsCache;
+  private EntityAdapterModel model;
+
+  public EntityAdapter(Entity anEntity, EntityAdapterDefinition aDefinition, EntityAdapterModel aModel) {
+    entity = anEntity;
+    definition = aDefinition;
+    calculatedFieldsCache = new HashMap();
+    model = aModel;
+  }
+
+  public boolean containsKey(Object aKey) {
+    try {
+      if (aKey instanceof String)
+        return     entity.hasValueForField((String) aKey)
+                || definition.hasCalculatedField((String) aKey)
+                || entity.getFields().contains(aKey);
+    }
+    catch (Throwable t) {
+    }
+
+    return false;
+  }
+
+  public boolean equals(Object anObject) {
+    return        anObject instanceof EntityAdapter
+           && ((EntityAdapter) anObject).entity.equals(entity);
+  }
+
+  public int hashCode() {
+    return entity.hashCode();
+  }
+
+  public Entity getEntity() {
+    return entity;
+  }
+
+  public EntityAdapterModel getModel() {
+    return model;
+  }
+
+  public Object get(Object aKey) {
+    Object result;
+
+    if (calculatedFieldsCache.containsKey(aKey)) {
+      return calculatedFieldsCache.get(aKey);
+    }
+    else if (aKey instanceof String && definition.hasCalculatedField((String) aKey)) {
+      result = definition.getCalculatedField((String) aKey).getValue(this);
+      calculatedFieldsCache.put(aKey, result);
+
+      return result;
+    }
+    else if (aKey instanceof String) {
+      return entity.getValue((String) aKey);
+    }
+    else {
+      return null;
+    }
+  }
+
+  public boolean isEmpty() {
+    throw new UnsupportedOperationException("EntityAdapter.isEmpty()");
+  }
+
+  public Set keySet() {
+    throw new UnsupportedOperationException("EntityAdapter.keySet()");
+  }
+
+  public Object put(Object aKey, Object value) {
+    throw new UnsupportedOperationException("EntityAdapter.put()");
+  }
+
+  public void putAll(Map t) {
+    throw new UnsupportedOperationException("EntityAdapter.putAll()");
+  }
+
+  public Object remove(Object aKey) {
+    throw new UnsupportedOperationException("EntityAdapter.remove()");
+  }
+
+  public int size() {
+    throw new UnsupportedOperationException("EntityAdapter.size()");
+  }
+
+  public Collection values() {
+    throw new UnsupportedOperationException("EntityAdapter.values()");
+  }
+
+  public void clear() {
+    throw new UnsupportedOperationException("EntityAdapter.clear()");
+  }
+
+  public boolean containsValue(Object value) {
+    throw new UnsupportedOperationException("EntityAdapter.containsValue()");
+  }
+
+  public Set entrySet() {
+    throw new UnsupportedOperationException("EntityAdapter.entrySet()");
+  }
+
+  public Object getRelation(String aWhereClause, String anOrderByClause, String aDefinition) {
+    try {
+      return
+          new CachingRewindableIterator(
+            new EntityIteratorAdapter(
+                aWhereClause, anOrderByClause, -1, getModel(), aDefinition));
+    }
+    catch (Throwable t) {
+      throw new RuntimeException(t.getMessage());
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/source/mir/entity/adapter/EntityAdapterDefinition.java b/source/mir/entity/adapter/EntityAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..0405a40
--- /dev/null
@@ -0,0 +1,125 @@
+package mir.entity.adapter;
+
+import java.util.*;
+import mir.entity.*;
+import mir.storage.*;
+import mir.util.*;
+
+public class EntityAdapterDefinition {
+  Map calculatedFields;
+
+  public EntityAdapterDefinition() {
+    calculatedFields = new HashMap();
+  }
+
+  public EntityAdapter makeEntityAdapter(Entity anEntity, EntityAdapterModel aModel) {
+    return new EntityAdapter(anEntity, this, aModel);
+  }
+
+  public CalculatedField getCalculatedField(String aFieldName) {
+    return (CalculatedField) calculatedFields.get(aFieldName);
+  }
+
+  public boolean hasCalculatedField(String aFieldName) {
+    return calculatedFields.containsKey(aFieldName);
+  }
+
+  public void addCalculatedField(String aFieldName, CalculatedField aField) {
+    calculatedFields.put(aFieldName, aField);
+  }
+
+  public void addMirDateField(String aDestinationFieldName, String aSourceFieldName) {
+    addCalculatedField(aDestinationFieldName, new MirDateField(aSourceFieldName));
+  }
+
+  public void addDBDateField(String aDestinationFieldName, String aSourceFieldName) {
+    addCalculatedField(aDestinationFieldName, new DBDateField(aSourceFieldName));
+  }
+
+  public interface CalculatedField {
+    public Object getValue(EntityAdapter anEntityAdapter);
+  }
+
+  private class MirDateField implements CalculatedField {
+    private String fieldName;
+
+    public MirDateField(String aFieldName) {
+      fieldName = aFieldName;
+    }
+
+    public Object getValue(EntityAdapter anEntityAdapter) {
+
+      Map result = new HashMap();
+      String textValue = anEntityAdapter.getEntity().getValue(fieldName);
+      Calendar calendar = GregorianCalendar.getInstance();
+      int year;
+      int month;
+      int day;
+      Date date;
+
+      if (textValue!=null) {
+        try {
+          year = Integer.parseInt(textValue.substring(0,4));
+          month = Integer.parseInt(textValue.substring(4,6));
+          day = Integer.parseInt(textValue.substring(6,8));
+
+          calendar.set(year, month-1, day);
+          date = calendar.getTime();
+          ;
+
+          result.put("date", date);
+          result.put("formatted", new DateToMapAdapter(date));
+
+        }
+        catch (Throwable t) {
+          result=null;
+        }
+      }
+      return result;
+    }
+  }
+
+  private class DBDateField implements CalculatedField {
+    private String fieldName;
+
+    public DBDateField(String aFieldName) {
+      fieldName = aFieldName;
+    }
+
+    public Object getValue(EntityAdapter anEntityAdapter) {
+
+      Map result = new HashMap();
+      String textValue = anEntityAdapter.getEntity().getValue(fieldName);
+      Calendar calendar = GregorianCalendar.getInstance();
+      int year;
+      int month;
+      int day;
+      int hours;
+      int minutes;
+
+      Date date;
+
+      if (textValue!=null) {
+        try {
+          year = Integer.parseInt(textValue.substring(0,4));
+          month = Integer.parseInt(textValue.substring(5,7));
+          day = Integer.parseInt(textValue.substring(8,10));
+          hours = Integer.parseInt(textValue.substring(11,13));
+          minutes = Integer.parseInt(textValue.substring(14,16));
+
+          calendar.set(year, month-1, day, hours, minutes);
+          date = calendar.getTime();
+
+          result.put("date", date);
+          result.put("formatted", new DateToMapAdapter(date));
+          result.put("raw", textValue);
+        }
+        catch (Throwable t) {
+          result=null;
+        }
+      }
+
+      return result;
+    }
+  }
+}
diff --git a/source/mir/entity/adapter/EntityAdapterModel.java b/source/mir/entity/adapter/EntityAdapterModel.java
new file mode 100755 (executable)
index 0000000..e552799
--- /dev/null
@@ -0,0 +1,52 @@
+package mir.entity.adapter;\r
+\r
+import java.util.*;\r
+import mir.entity.*;\r
+import mir.storage.*;\r
+import mir.util.*;\r
+\r
+public class EntityAdapterModel {\r
+  private Map entityAdapterMappings;\r
+\r
+  public EntityAdapterModel() {\r
+    entityAdapterMappings = new HashMap();\r
+  }\r
+\r
+  public EntityAdapter makeEntityAdapter( String aName, Entity anEntity ) {\r
+    Mapping mapping = getMappingForName( aName );\r
+\r
+    if (mapping == null )\r
+      throw new RuntimeException( "Adapter definition with name '" + aName + "' not present in model" );\r
+\r
+    return mapping.getDefinition().makeEntityAdapter( anEntity, this );\r
+  }\r
+\r
+  public void addMapping( String aName, StorageObject aStorage, EntityAdapterDefinition aDefinition ) {\r
+    entityAdapterMappings.put( aName, new Mapping( aStorage, aDefinition ) );\r
+    }\r
+\r
+  public Mapping getMappingForName( String aName ) {\r
+    return (Mapping) entityAdapterMappings.get( aName );\r
+  }\r
+\r
+  public class Mapping {\r
+    private StorageObject storage;\r
+    private EntityAdapterDefinition definition;\r
+\r
+    public Mapping( StorageObject aStorage, EntityAdapterDefinition aDefinition ) {\r
+      storage = aStorage;\r
+      definition = aDefinition;\r
+    }\r
+\r
+    public StorageObject getStorage() {\r
+      return storage;\r
+    }\r
+\r
+    public EntityAdapterDefinition getDefinition() {\r
+      return definition;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+                                                                                                   
\ No newline at end of file
diff --git a/source/mir/entity/adapter/EntityIteratorAdapter.java b/source/mir/entity/adapter/EntityIteratorAdapter.java
new file mode 100755 (executable)
index 0000000..6fbff1a
--- /dev/null
@@ -0,0 +1,42 @@
+package mir.entity.adapter;
+
+import java.util.*;
+import mir.storage.*;
+import mir.util.*;
+import mir.entity.*;
+
+public class EntityIteratorAdapter implements RewindableIterator {
+  private String definitionName;
+  private RewindableIterator iterator;
+  private EntityAdapterModel model;
+
+  public EntityIteratorAdapter(RewindableIterator anIterator, EntityAdapterModel aModel, String aDefinitionName) {
+    model = aModel;
+    iterator = anIterator;
+    definitionName = aDefinitionName;
+  }
+
+  public EntityIteratorAdapter(String aWhereClause, String anOrderByClause, int aBatchSize, EntityAdapterModel aModel, String aDefinitionName ) throws StorageObjectException {
+    this(new EntityBrowser(aModel.getMappingForName(aDefinitionName).getStorage(), aWhereClause, anOrderByClause, aBatchSize), aModel, aDefinitionName);
+  }
+
+  public EntityIteratorAdapter(String aWhereClause, String anOrderByClause, int aBatchSize, EntityAdapterModel aModel, String aDefinitionName, int aLimit, int aSkip) throws StorageObjectException {
+    this(new EntityBrowser(aModel.getMappingForName(aDefinitionName).getStorage(), aWhereClause, anOrderByClause, aBatchSize, aLimit, aSkip), aModel, aDefinitionName);
+  }
+
+  public boolean hasNext() {
+    return iterator.hasNext();
+  }
+
+  public Object next() {
+    return model.makeEntityAdapter(definitionName, (Entity) iterator.next());
+  }
+
+  public void remove() {
+    iterator.remove();
+  }
+
+  public void rewind() {
+    iterator.rewind();
+  };
+}
diff --git a/source/mir/entity/adapter/EntityListAdapter.java b/source/mir/entity/adapter/EntityListAdapter.java
new file mode 100755 (executable)
index 0000000..ceedf47
--- /dev/null
@@ -0,0 +1,85 @@
+package mir.entity.adapter;
+
+import java.util.*;
+import mir.entity.*;
+
+public class EntityListAdapter extends AbstractList {
+  private int skip;
+  private int maximumLength;
+  private EntityBrowser browser;
+  private boolean exhausted = false;
+  private boolean skipped = false;
+
+  private List cache;
+
+  protected EntityListAdapter(EntityBrowser aBrowser, int aSkip, int aMaximumLength) {
+    browser = aBrowser;
+    skip = aSkip;
+    maximumLength = aMaximumLength;
+    cache = new Vector();
+  }
+
+  protected EntityListAdapter(EntityBrowser aBrowser, int aMaximumLength) {
+    this(aBrowser, 0, aMaximumLength);
+  }
+
+  protected EntityListAdapter(EntityBrowser aBrowser) {
+    this(aBrowser, 0, -1);
+  }
+
+  private void skip() {
+    int i;
+
+    try {
+      if (!skipped) {
+        for(i=0; i<skip; i++)
+          if (browser.hasNext())
+            browser.next();
+      }
+      skipped=true;
+    }
+    catch (Throwable t) {
+      throw new RuntimeException(t.getMessage());
+    }
+  }
+
+  private void fetchNext() {
+    try {
+      if (!exhausted) {
+        if (browser.hasNext())
+          cache.add(browser.next());
+
+        exhausted = !browser.hasNext() || (maximumLength>0 && cache.size()>=maximumLength) ;
+      }
+    }
+    catch (Throwable t) {
+      throw new RuntimeException(t.getMessage());
+    }
+
+  }
+
+  private void exhaust() {
+    skip();
+
+    while (!exhausted)
+      fetchNext();
+  }
+
+  private void fetchUntil(int anIndex) {
+    skip();
+
+    while (!exhausted && anIndex>=cache.size())
+      fetchNext();
+  }
+
+  public int size() {
+    exhaust();
+
+    return cache.size();
+  }
+
+  public Object get(int anIndex) {
+    fetchUntil(anIndex);
+    return cache.get(anIndex);
+  }
+}
\ No newline at end of file
diff --git a/source/mir/generator/CompositeGeneratorLibrary.java b/source/mir/generator/CompositeGeneratorLibrary.java
new file mode 100755 (executable)
index 0000000..2c1a949
--- /dev/null
@@ -0,0 +1,46 @@
+package mir.generator;
+
+import java.util.*;
+
+public class CompositeGeneratorLibrary implements Generator.GeneratorLibrary {
+  private Map generatorLibraries;
+  private Generator.GeneratorLibrary defaultLibrary = null;
+  private static String LIBRARY_QUALIFIER_SEPARATOR = "::";
+
+  public CompositeGeneratorLibrary() {
+    generatorLibraries = new HashMap();
+  }
+
+  public void addLibrary(String aQualifier, Generator.GeneratorLibrary aLibrary, boolean anIsDefault) {
+    if (anIsDefault || defaultLibrary == null) {
+      defaultLibrary = aLibrary;
+    }
+
+    generatorLibraries.put(aQualifier, aLibrary);
+  }
+
+  public Generator makeGenerator(String anIdentifier) throws GeneratorExc, GeneratorFailure {
+    String qualifier;
+    String libraryName;
+    int position;
+    Generator.GeneratorLibrary library;
+
+    position = anIdentifier.indexOf( LIBRARY_QUALIFIER_SEPARATOR );
+    if (position>=0) {
+      libraryName = anIdentifier.substring(0, position);
+      qualifier = anIdentifier.substring(position + LIBRARY_QUALIFIER_SEPARATOR.length());
+
+      library = (Generator.GeneratorLibrary) generatorLibraries.get(libraryName);
+      if (library==null)
+        throw new GeneratorExc("CompositeGeneratorLibrary: library '"+libraryName+"' not found");
+
+      return library.makeGenerator(qualifier);
+    }
+    else {
+      if (defaultLibrary!=null)
+        return defaultLibrary.makeGenerator(anIdentifier);
+      else
+        throw new GeneratorExc("CompositeGeneratorLibrary: no default library speficied");
+    }
+  };
+}
\ No newline at end of file
diff --git a/source/mir/generator/FreemarkerGenerator.java b/source/mir/generator/FreemarkerGenerator.java
new file mode 100755 (executable)
index 0000000..e92bd74
--- /dev/null
@@ -0,0 +1,279 @@
+package mir.generator;
+
+import freemarker.template.*;
+import org.apache.struts.util.MessageResources;
+import java.util.*;
+import java.io.*;
+import mir.entity.*;
+import mir.util.*;
+import mir.misc.*;
+
+public class FreemarkerGenerator implements Generator {
+  private Template template;
+
+  public FreemarkerGenerator(Template aTemplate) {
+    template = aTemplate;
+  }
+
+  public void generate(Object anOutputWriter, Map aValues, PrintWriter aLogger) throws GeneratorExc, GeneratorFailure {
+    if (!(anOutputWriter instanceof PrintWriter))
+      throw new GeneratorExc("Writer for a FreemarkerGenerator must be a PrintWriter");
+
+    try {
+      template.process((TemplateModelRoot) makeMapAdapter(aValues), (PrintWriter) anOutputWriter);
+    }
+    catch (Throwable t) {
+      aLogger.println("Exception occurred: "+t.getMessage());
+      t.printStackTrace(aLogger);
+      throw new GeneratorFailure( t );
+    }
+  }
+
+  private static TemplateScalarModel makeStringAdapter(String aString) {
+    return new SimpleScalar(aString);
+  }
+
+  private static TemplateHashModel makeMapAdapter(Map aMap)  {
+    return new MapAdapter(aMap);
+  }
+
+  private static TemplateListModel makeIteratorAdapter(Iterator anIterator) {
+    return new IteratorAdapter(anIterator);
+  }
+
+  private static TemplateMethodModel makeFunctionAdapter(Generator.GeneratorFunction aFunction) {
+    return new FunctionAdapter(aFunction);
+  }
+
+  private static TemplateModel makeAdapter(Object anObject) throws TemplateModelException {
+    if (anObject == null)
+      return null;
+    if (anObject instanceof TemplateModel)
+      return (TemplateModel) anObject;
+    else if (anObject instanceof Generator.GeneratorFunction)
+      return makeFunctionAdapter((Generator.GeneratorFunction) anObject);
+    else if (anObject instanceof MessageResources)
+      return new MessageMethodModel((MessageResources) anObject);
+    else if (anObject instanceof Integer)
+      return makeStringAdapter(((Integer) anObject).toString());
+    else if (anObject instanceof String)
+      return makeStringAdapter((String) anObject);
+    else if (anObject instanceof Map)
+      return makeMapAdapter((Map) anObject);
+    else if (anObject instanceof Iterator)
+      return makeIteratorAdapter((Iterator) anObject);
+    else if (anObject instanceof List)
+      return makeIteratorAdapter(((List) anObject).iterator());
+    else
+      throw new TemplateModelException("Unadaptable class: " + anObject.getClass().getName());
+  }
+
+  private static class MapAdapter implements TemplateModelRoot {
+    Map map;
+    Map valuesCache;
+
+    private MapAdapter(Map aMap) {
+      map = aMap;
+      valuesCache = new HashMap();
+    }
+
+    public void put(String aKey, TemplateModel aModel) {
+      valuesCache.put(aKey, aModel);
+    }
+
+    public void remove(String aKey) {
+      // ML: kinda tricky...
+    }
+
+    public boolean isEmpty() {
+      return map.isEmpty();
+    }
+
+    public TemplateModel get(String aKey) throws TemplateModelException {
+      try {
+      if (!valuesCache.containsKey(aKey)) {
+        Object value = map.get(aKey);
+
+  if (value == null && !map.containsKey(aKey))
+      throw new TemplateModelException("MapAdapter: no key "+aKey+" available");
+
+        valuesCache.put(aKey, makeAdapter(value));
+      }
+
+      return (TemplateModel) valuesCache.get(aKey);
+    }
+    catch (TemplateModelException e) {
+      throw e;
+    }
+    catch (Throwable t) {
+      throw new TemplateModelException(t.getMessage());
+    }
+    }
+  }
+
+  private static class IteratorAdapter implements TemplateListModel {
+    Iterator iterator;
+    List valuesCache;
+    int position;
+
+    private IteratorAdapter(Iterator anIterator) {
+      iterator = anIterator;
+
+      valuesCache = new Vector();
+      position=0;
+
+
+      if (iterator instanceof RewindableIterator) {
+        ((RewindableIterator) iterator).rewind();
+      }
+    }
+
+    public boolean isEmpty() {
+      return valuesCache.isEmpty() && !iterator.hasNext();
+    }
+
+    private void getUntil(int anIndex) throws TemplateModelException {
+      while (valuesCache.size()<=anIndex && iterator.hasNext())
+      {
+        valuesCache.add(makeAdapter(iterator.next()));
+      }
+    };
+
+    public TemplateModel get(int anIndex) throws TemplateModelException {
+      TemplateModel result;
+
+      getUntil(anIndex);
+
+      if (anIndex<valuesCache.size())
+      {
+        result = (TemplateModel) valuesCache.get(anIndex);
+
+        return result;
+      }
+      else
+        throw new TemplateModelException( "Iterator out of bounds" );
+    }
+
+    public boolean hasNext() {
+      return position<valuesCache.size() || iterator.hasNext();
+    }
+
+    public boolean isRewound() {
+      return position==0;
+    }
+
+    public TemplateModel next() throws TemplateModelException {
+      TemplateModel result;
+
+      if (hasNext()) {
+        result = get(position);
+        position++;
+      }
+      else
+        throw new TemplateModelException( "Iterator out of bounds" );
+
+      return result;
+    }
+
+    public void rewind() {
+      position=0;
+    }
+  }
+
+  private static class ListAdapter implements TemplateListModel {
+    List list;
+    List valuesCache;
+    int position;
+
+    private ListAdapter(List aList) {
+      list = aList;
+      valuesCache = new Vector();
+      position=0;
+    }
+
+    public boolean isEmpty() {
+      return list.isEmpty();
+    }
+
+    public TemplateModel get(int i) throws TemplateModelException {
+
+      if (i>=valuesCache.size() && i<list.size()) {
+        for(int j=valuesCache.size(); j<=i; j++) {
+          valuesCache.add(makeAdapter(list.get(j)));
+        }
+      }
+
+      if (i<valuesCache.size())
+        return (TemplateModel) valuesCache.get(i);
+      else
+        throw new TemplateModelException( "Iterator out of bounds" );
+    }
+
+    public boolean hasNext() {
+      return position<list.size();
+    }
+
+    public boolean isRewound() {
+      return position==0;
+    }
+
+    public TemplateModel next() throws TemplateModelException {
+      TemplateModel result;
+
+      if (hasNext()) {
+        result = get(position);
+        position++;
+      }
+      else {
+        throw new TemplateModelException( "Iterator out of bounds" );
+      }
+
+      return result;
+    }
+
+    public void rewind() {
+      position = 0;
+    }
+  }
+
+  private static class FunctionAdapter implements TemplateMethodModel {
+    Generator.GeneratorFunction function;
+
+    public FunctionAdapter(Generator.GeneratorFunction aFunction) {
+      function = aFunction;
+    }
+
+    public TemplateModel exec(List anArguments) throws TemplateModelException {
+      try {
+        return makeAdapter(function.perform(anArguments));
+      }
+      catch (Throwable t) {
+        throw new TemplateModelException(t.getMessage());
+      }
+    }
+
+    public boolean isEmpty() {
+      return false;
+    }
+
+  }
+
+  public static class FreemarkerGeneratorLibrary implements GeneratorLibrary {
+    private FileTemplateCache  templateCache;
+
+    public FreemarkerGeneratorLibrary(String aTemplateRoot) {
+      templateCache = new FileTemplateCache( aTemplateRoot + "/" );
+      templateCache.setLoadingPolicy(templateCache.LOAD_ON_DEMAND);
+    }
+
+    public Generator makeGenerator(String anIdentifier) throws GeneratorExc, GeneratorFailure {
+      Template template = (Template) templateCache.getItem(anIdentifier, "template");
+
+      if (template==null) {
+        throw new GeneratorExc("FreemarkerGeneratorLibrary: Can't find template "+templateCache.getDirectory()+anIdentifier);
+      }
+
+      return new FreemarkerGenerator(template);
+    }
+  }
+}
diff --git a/source/mir/generator/Generator.java b/source/mir/generator/Generator.java
new file mode 100755 (executable)
index 0000000..64abdef
--- /dev/null
@@ -0,0 +1,16 @@
+package mir.generator;
+
+import java.util.*;
+import java.io.*;
+
+public interface Generator {
+  public void generate(Object anOutputWriter, Map aValues, PrintWriter aLogger) throws GeneratorExc, GeneratorFailure;
+
+  public static interface GeneratorLibrary {
+    public Generator makeGenerator(String anIdentifier) throws GeneratorExc, GeneratorFailure;
+  }
+
+  public static interface GeneratorFunction {
+    public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure;
+  }
+}
diff --git a/source/mir/generator/GeneratorExc.java b/source/mir/generator/GeneratorExc.java
new file mode 100755 (executable)
index 0000000..94cdcf9
--- /dev/null
@@ -0,0 +1,9 @@
+package mir.generator;
+
+import multex.Exc;
+
+public class GeneratorExc extends Exc {
+  public GeneratorExc(String aMessage) {
+    super(aMessage);
+  }
+}
diff --git a/source/mir/generator/GeneratorFailure.java b/source/mir/generator/GeneratorFailure.java
new file mode 100755 (executable)
index 0000000..a729cd5
--- /dev/null
@@ -0,0 +1,14 @@
+package mir.generator;
+
+import multex.Failure;
+
+public class GeneratorFailure extends Failure {
+
+    public GeneratorFailure(String aMessage, Throwable aCause) {
+      super(aMessage, aCause);
+    }
+
+    public GeneratorFailure(Throwable aCause) {
+      this (aCause.getMessage(), aCause);
+    }
+}
\ No newline at end of file
diff --git a/source/mir/generator/WriterEngine.java b/source/mir/generator/WriterEngine.java
new file mode 100755 (executable)
index 0000000..728b2d2
--- /dev/null
@@ -0,0 +1,15 @@
+package mir.generator;
+
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2002</p>
+ * <p>Company: </p>
+ * @author unascribed
+ * @version 1.0
+ */
+
+public interface WriterEngine {
+  public Object openWriter(String anIdentifier, String aParameter) throws GeneratorExc, GeneratorFailure;
+  public void closeWriter(Object aWriter) throws GeneratorExc, GeneratorFailure;
+}
\ No newline at end of file
index 544e161..d9e4e8e 100755 (executable)
@@ -43,7 +43,7 @@ public final class HTMLTemplateProcessor {
   //
   // init
 
-  static {
+    static {
     /** @todo either in the above block or here :) //rk */
     templateDir = MirConfig.getPropWithHome("HTMLTemplateProcessor.Dir");
     templateCache = new FileTemplateCache(templateDir);
@@ -66,8 +66,8 @@ public final class HTMLTemplateProcessor {
     defEncoding = MirConfig.getProp("Mir.DefaultEncoding");
     openAction = MirConfig.getProp("Producer.OpenAction");
     productionHost = MirConfig.getProp("Producer.ProductionHost");
-    videoHost = MirConfig.getProp("Producer.VideoHost");
-    audioHost = MirConfig.getProp("Producer.AudioHost");
+    videoHost = MirConfig.getProp("Producer.Video.Host");
+    audioHost = MirConfig.getProp("Producer.Audio.Host");
     imageHost = MirConfig.getProp("Producer.Image.Host");
     imagePath = MirConfig.getProp("Producer.Image.Path");
     producerDocRoot = MirConfig.getProp("Producer.DocRoot");
@@ -251,7 +251,7 @@ public final class HTMLTemplateProcessor {
                configHash.put("imageHost", new SimpleScalar(imageHost));
                configHash.put("imagePath", new SimpleScalar(imagePath));
                configHash.put("mirVersion", new SimpleScalar(MirConfig.getProp("Mir.Version")));
-               // this conform to updated freemarker syntax
+                // this conform to updated freemarker syntax
                configHash.put("compressWhitespace", new freemarker.template.utility.CompressWhitespace() );
                configHash.put("generateFO", new SimpleScalar(generateFO));
                configHash.put("generatePDF", new SimpleScalar(generatePDF));
index a64f4cf..a3e9199 100755 (executable)
@@ -73,7 +73,14 @@ public class MirConfig extends Configuration {
    * @return a String containing the prop. value
    */
   public static String getProp(String propName) {
-    return (String)configHash.get(propName);
+    String result = (String)configHash.get(propName);
+
+    if (result==null)
+      throw new ConfigException("config property '"+propName+"' not available!");
+
+
+
+    return result;
   }
 
   /**
@@ -83,12 +90,11 @@ public class MirConfig extends Configuration {
    * @return a String containing the prop.value
    */
   public static String getPropWithHome(String propName) {
-    return (String)configHash.get("Home") +
-           (String)configHash.get(propName);
+    return getProp("Home") + getProp(propName);
   }
 
   /**
-   * Returns the property asked for iin raw Object form by 
+   * Returns the property asked for iin raw Object form by
    * pulling it out a HashMap
    * @param a String containing the property name (key)
    * @return an Object containing the prop.value
diff --git a/source/mir/misc/PDFUtil.java b/source/mir/misc/PDFUtil.java
new file mode 100755 (executable)
index 0000000..4e72f19
--- /dev/null
@@ -0,0 +1,70 @@
+package mir.misc;
+
+import java.io.*;
+import javax.servlet.http.*;
+
+import mircoders.global.*;
+
+import org.apache.fop.apps.* ;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+import org.apache.log.*;
+
+public class PDFUtil {
+    
+  public static void makePDF(String foFilePath,Object pdfDestination) throws Exception
+  {
+    try{
+      Driver driver = new Driver();
+      
+      //stupid logging that fop wants to use, needs to be changed
+      Hierarchy hierarchy = Hierarchy.getDefaultHierarchy();
+      Logger fopLog=null;
+      fopLog = hierarchy.getLoggerFor("fop");
+      fopLog.setPriority(Priority.WARN);
+      driver.setLogger(fopLog);
+      
+      driver.setRenderer(Driver.RENDER_PDF);
+  
+      File foFile=new File(foFilePath);
+      
+      String html2foStyleSheetPath=MirGlobal.getConfigProperty("Home") 
+         + MirGlobal.getConfigProperty("HTMLTemplateProcessor.Dir")
+          + "/" 
+          + MirGlobal.getConfigProperty("Producer.PrintableContent.html2foStyleSheetName"); 
+      File html2foStyleSheet=new File(html2foStyleSheetPath);
+      InputHandler inputHandler =
+         new XSLTInputHandler(foFile, html2foStyleSheet);
+      XMLReader parser = inputHandler.getParser();
+      
+      if (pdfDestination instanceof String) {
+       String filePath = (String) pdfDestination;
+       driver.setOutputStream(new FileOutputStream(filePath));
+       driver.render(parser, inputHandler.getInputSource());
+      }
+      else if (pdfDestination instanceof HttpServletResponse){
+       HttpServletResponse res = (HttpServletResponse) pdfDestination; 
+       ByteArrayOutputStream out = new ByteArrayOutputStream();
+       driver.setOutputStream(out);
+       res.setContentType("application/pdf");
+       
+       driver.render(parser, inputHandler.getInputSource());
+       
+       byte[] content = out.toByteArray();
+       res.setContentLength(content.length);
+       res.getOutputStream().write(content);
+       res.getOutputStream().flush();
+      }
+      else {
+       throw new Exception("I'm sorry but I don't know how to output a pdf to an object of type" + pdfDestination.getClass().getName());
+      }
+    }
+  
+    catch (Exception ex){
+       throw(ex);
+    }
+  }
+}
+
+
+
diff --git a/source/mir/producer/AssignmentProducerNode.java b/source/mir/producer/AssignmentProducerNode.java
new file mode 100755 (executable)
index 0000000..1c13cac
--- /dev/null
@@ -0,0 +1,31 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import org.apache.struts.util.MessageResources;
+import mir.util.*;
+
+public class AssignmentProducerNode extends ProducerNodeDecorator {
+  private String key;
+  private String bundleIdentifier;
+  private Object value;
+
+  public AssignmentProducerNode(String aKey, Object aValue, ProducerNode aSubNode) {
+    super(aSubNode);
+
+    key = aKey;
+    value = aValue;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    try {
+      ParameterExpander.setValueForKey(aValueMap, key, value);
+
+      super.produce(aValueMap, aVerb, aLogger);
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  };
+
+}
\ No newline at end of file
diff --git a/source/mir/producer/CompositeProducerNode.java b/source/mir/producer/CompositeProducerNode.java
new file mode 100755 (executable)
index 0000000..503a87d
--- /dev/null
@@ -0,0 +1,58 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+
+public class CompositeProducerNode implements ProducerNode {
+  private List subNodes;
+
+  public CompositeProducerNode() {
+    subNodes = new Vector();
+  }
+
+  public CompositeProducerNode(ProducerNode[] aSubNodes) {
+    this();
+
+    int i;
+
+    for (i=0; i<aSubNodes.length; i++) {
+      addSubNode(aSubNodes[i]);
+    }
+  }
+
+  public int getNrSubNodes() {
+    return subNodes.size();
+  }
+
+  public ProducerNode getSubNode(int anIndex) {
+    return (ProducerNode) subNodes.get(anIndex);
+  }
+
+  public void addSubNode(ProducerNode aSubNode) {
+    if (aSubNode!=null)
+      subNodes.add(aSubNode);
+  }
+
+  public void clear() {
+    subNodes.clear();
+  }
+
+  public void produce(Map aValueSet, String aVerb, PrintWriter aLogger) throws ProducerFailure, ProducerExc {
+    Iterator i = subNodes.iterator();
+
+    while (i.hasNext()) {
+      ProducerNode node = (ProducerNode) i.next();
+      node.produce(aValueSet, aVerb, aLogger);
+    }
+  }
+
+  public Set buildVerbSet() {
+    Iterator i = subNodes.iterator();
+    Set result = new HashSet();
+
+    while (i.hasNext())
+      result.addAll(((ProducerNode) i.next()).buildVerbSet());
+
+    return result;
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/ConditionalProducerNode.java b/source/mir/producer/ConditionalProducerNode.java
new file mode 100755 (executable)
index 0000000..8642b2b
--- /dev/null
@@ -0,0 +1,37 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.util.*;
+
+public class ConditionalProducerNode implements ProducerNode {
+  private String condition;
+  private ProducerNode trueNode;
+  private ProducerNode falseNode;
+
+  public ConditionalProducerNode(String aCondition, ProducerNode aTrueNode, ProducerNode aFalseNode) {
+    condition = aCondition;
+    trueNode = aTrueNode;
+    falseNode = aFalseNode;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    try {
+      if (ParameterExpander.evaluateBooleanExpression(aValueMap, condition)) {
+        if (trueNode!=null)
+          trueNode.produce(aValueMap, aVerb, aLogger);
+      }
+      else {
+        if (falseNode!=null)
+          falseNode.produce(aValueMap, aVerb, aLogger);
+      }
+    }
+    catch (Exception e) {
+      throw new ProducerFailure(e);
+    }
+  }
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/EntityBatchingProducerNode.java b/source/mir/producer/EntityBatchingProducerNode.java
new file mode 100755 (executable)
index 0000000..e12bd79
--- /dev/null
@@ -0,0 +1,235 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.entity.adapter.*;
+import mir.entity.*;
+import mir.storage.*;
+import mir.util.*;
+
+public class EntityBatchingProducerNode implements ProducerNode {
+  private Map verbs;
+
+  private String batchInfoKey;
+  private String batchDataKey;
+  private EntityAdapterModel model;
+  private String definition;
+  private String whereClause;
+  private String orderByClause;
+  private String nrEntitiesToSkipExpression;
+  private String nrEntitiesPerBatchExpression;
+  private String minNrEntitiesInFirstBatchExpression;
+  private String defaultNrBatchesToProcessExpression;
+  private ProducerNode batchSubNode;
+  private ProducerNode batchListSubNode;
+
+  public EntityBatchingProducerNode(
+        String aBatchDataKey,
+        String aBatchInfoKey,
+        EntityAdapterModel aModel,
+        String aDefinition,
+        String aWhereClause,
+        String anOrderByClause,
+        int anrEntitiesPerBatchExpression,
+        int aminNrEntitiesInFirstBatchExpression,
+        int anrEntitiesToSkipExpression,
+        ProducerNode aBatchSubNode) {
+    this(aBatchDataKey, aBatchInfoKey, aModel, aDefinition, aWhereClause,
+        anOrderByClause, anrEntitiesPerBatchExpression, aminNrEntitiesInFirstBatchExpression, anrEntitiesToSkipExpression,
+        aBatchSubNode, null);
+  }
+
+  public EntityBatchingProducerNode(
+        String aBatchDataKey,
+        String aBatchInfoKey,
+        EntityAdapterModel aModel,
+        String aDefinition,
+        String aWhereClause,
+        String anOrderByClause,
+        int aNrEntitiesPerBatch,
+        int aMinNrEntitiesInFirstBatch,
+        int aNrEntitiesToSkip,
+        ProducerNode aBatchSubNode,
+        ProducerNode aBatchListSubNode) {
+
+    this(aBatchDataKey, aBatchInfoKey, aModel, aDefinition,
+         aWhereClause, anOrderByClause,
+        Integer.toString(aNrEntitiesPerBatch),
+        Integer.toString(aMinNrEntitiesInFirstBatch),
+        Integer.toString(aNrEntitiesToSkip),
+        "1",
+        aBatchSubNode, aBatchListSubNode);
+
+  }
+
+  public EntityBatchingProducerNode(
+        String aBatchDataKey,
+        String aBatchInfoKey,
+        EntityAdapterModel aModel,
+        String aDefinition,
+        String aWhereClause,
+        String anOrderByClause,
+        String anrEntitiesPerBatchExpression,
+        String aminNrEntitiesInFirstBatchExpression,
+        String anrEntitiesToSkipExpression,
+        String aDefaultNrBatchesToProcessExpression,
+        ProducerNode aBatchSubNode,
+        ProducerNode aBatchListSubNode) {
+
+    batchSubNode = aBatchSubNode;
+    batchListSubNode = aBatchListSubNode;
+
+    verbs = new HashMap();
+
+    batchDataKey = aBatchDataKey;
+    batchInfoKey = aBatchInfoKey;
+    model = aModel;
+    definition = aDefinition;
+    whereClause = aWhereClause;
+    orderByClause = anOrderByClause;
+    nrEntitiesToSkipExpression = anrEntitiesToSkipExpression;
+    nrEntitiesPerBatchExpression = anrEntitiesPerBatchExpression;
+    minNrEntitiesInFirstBatchExpression = aminNrEntitiesInFirstBatchExpression;
+    defaultNrBatchesToProcessExpression = aDefaultNrBatchesToProcessExpression;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    Iterator browser;
+    int nrEntities;
+    int nrBatchesAfterFirst;
+    int nrEntitiesInFirstBatch;
+    int nrBatchesToProcess;
+    List batchesData;
+    int i;
+    int position;
+    Map batchData;
+    String expandedWhereClause;
+    String expandedOrderByClause;
+    EntityBatchingProducerNodeVerb verb = (EntityBatchingProducerNodeVerb) verbs.get(aVerb);
+
+    List batchLocations;
+    BatchLocation location;
+
+    int nrEntitiesToSkip;
+    int nrEntitiesPerBatch;
+    int minNrEntitiesInFirstBatch;
+
+//  ML: The order by clause should lead to a result set in _reverse order_: the first row will be
+//      the last entity presented on the last page
+
+
+    try {
+      if (verb==null) {
+        nrBatchesToProcess = ParameterExpander.evaluateIntegerExpressionWithDefault( aValueMap, defaultNrBatchesToProcessExpression, -1 );
+      }
+      else {
+        nrBatchesToProcess=verb.nrBatchesToProcess;
+      }
+
+      expandedWhereClause = ParameterExpander.expandExpression( aValueMap, whereClause );
+      expandedOrderByClause = ParameterExpander.expandExpression( aValueMap, orderByClause );
+
+      nrEntitiesToSkip = ParameterExpander.evaluateIntegerExpression( aValueMap, nrEntitiesToSkipExpression);
+      nrEntitiesPerBatch = ParameterExpander.evaluateIntegerExpression( aValueMap, nrEntitiesPerBatchExpression);
+      minNrEntitiesInFirstBatch = ParameterExpander.evaluateIntegerExpression( aValueMap, minNrEntitiesInFirstBatchExpression);
+
+      batchesData = new Vector();
+      batchLocations = new Vector();
+
+      nrEntities = model.getMappingForName(definition).getStorage().getSize(expandedWhereClause)-nrEntitiesToSkip;
+      nrEntitiesInFirstBatch = nrEntities % nrEntitiesPerBatch;
+      while (nrEntitiesInFirstBatch<minNrEntitiesInFirstBatch && nrEntities-nrEntitiesInFirstBatch>=nrEntitiesPerBatch)
+        nrEntitiesInFirstBatch = nrEntitiesInFirstBatch + nrEntitiesPerBatch;
+      nrBatchesAfterFirst = (nrEntities-nrEntitiesInFirstBatch)/nrEntitiesPerBatch;
+
+      batchLocations.add(new BatchLocation(nrBatchesAfterFirst*nrEntitiesPerBatch, nrEntitiesInFirstBatch));
+      batchData = new HashMap();
+      batchData.put("identifier", "");
+      batchData.put("index", new Integer(nrBatchesAfterFirst+1));
+      batchData.put("size", new Integer(nrEntitiesInFirstBatch));
+      batchesData.add(batchData);
+
+      for (i=0; i<nrBatchesAfterFirst; i++) {
+        batchLocations.add(1, new BatchLocation(i*nrEntitiesPerBatch, nrEntitiesPerBatch));
+        batchData = new HashMap();
+        batchData.put("identifier", new Integer(i));
+        batchData.put("index", new Integer(i+1));
+        batchData.put("size", new Integer(nrEntitiesPerBatch));
+        batchesData.add(1, batchData);
+      }
+
+      batchData = new HashMap();
+      ParameterExpander.setValueForKey(aValueMap, batchInfoKey, batchData);
+      batchData.put("all", batchesData);
+      batchData.put("first", batchesData.get(0));
+      batchData.put("last", batchesData.get(batchesData.size()-1));
+      batchData.put("count", new Integer(batchesData.size()));
+
+      if (batchListSubNode!=null) {
+        batchListSubNode.produce(aValueMap, aVerb, aLogger);
+      }
+
+      if (nrBatchesToProcess<0 || nrBatchesToProcess>nrBatchesAfterFirst+1) {
+        nrBatchesToProcess = nrBatchesAfterFirst+1;
+      }
+
+      if (batchSubNode!=null) {
+        for (i=0; i<nrBatchesToProcess; i++) {
+          location = (BatchLocation) batchLocations.get(i);
+
+          batchData.put("current", batchesData.get(i));
+          if (i>0)
+            batchData.put("previous", batchesData.get(i-1));
+          else
+            batchData.put("previous", null);
+
+          if (i<batchesData.size()-1)
+            batchData.put("next", batchesData.get(i+1));
+          else
+            batchData.put("next", null);
+
+          Iterator j = new EntityIteratorAdapter(expandedWhereClause, expandedOrderByClause,
+                    location.nrEntities, model, definition, location.nrEntities, location.firstEntity);
+          List entities = new Vector();
+
+          while (j.hasNext())
+            entities.add(0, j.next());
+
+          ParameterExpander.setValueForKey(aValueMap, batchDataKey, entities );
+
+          batchSubNode.produce(aValueMap, aVerb, aLogger);
+        }
+      }
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  };
+
+  private class BatchLocation {
+    int nrEntities;
+    int firstEntity;
+
+    public BatchLocation(int aFirstEntity, int aNrEntities) {
+      firstEntity = aFirstEntity;
+      nrEntities = aNrEntities;
+    }
+  }
+
+  public Set buildVerbSet() {
+    return verbs.keySet();
+  };
+
+  public void addVerb(String aVerb, int aNrPagesToGenerate) {
+    verbs.put(aVerb, new EntityBatchingProducerNodeVerb(aNrPagesToGenerate));
+  }
+
+  private class EntityBatchingProducerNodeVerb {
+    int nrBatchesToProcess;
+
+    EntityBatchingProducerNodeVerb(int aNrBatchesToProcess) {
+      nrBatchesToProcess = aNrBatchesToProcess;
+    }
+  }
+}
+
diff --git a/source/mir/producer/EntityEnumeratingProducerNode.java b/source/mir/producer/EntityEnumeratingProducerNode.java
new file mode 100755 (executable)
index 0000000..1d352ef
--- /dev/null
@@ -0,0 +1,105 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.entity.adapter.*;
+import mir.entity.*;
+import mir.storage.*;
+import mir.util.*;
+
+public class EntityEnumeratingProducerNode extends ProducerNodeDecorator {
+  private Map verbs;
+  private EntityEnumeratingProducerNodeVerb defaultVerb;
+  private String key;
+  private EntityAdapterModel model;
+  private String definition;
+  private String skip;
+  private String limit;
+
+  public EntityEnumeratingProducerNode(
+                String aKey,
+                EntityAdapterModel aModel, String aDefinition,
+                ProducerNode aSubNode) {
+    super(aSubNode);
+
+    defaultVerb = null;
+    verbs = new HashMap();
+    model = aModel;
+    definition = aDefinition;
+    key = aKey;
+  }
+
+  public EntityEnumeratingProducerNode(
+              String aKey,
+              EntityAdapterModel aModel, String aDefinition,
+              String aDefaultWhereClause, String aDefaultOrderByClause,
+              ProducerNode aSubNode) {
+    this(aKey, aModel, aDefinition, aDefaultWhereClause, aDefaultOrderByClause, "", "", aSubNode);
+  }
+
+  public EntityEnumeratingProducerNode(
+              String aKey,
+              EntityAdapterModel aModel, String aDefinition,
+              String aDefaultWhereClause, String aDefaultOrderByClause,
+              String aLimit, String aSkip,
+              ProducerNode aSubNode) {
+    this(aKey, aModel, aDefinition, aSubNode);
+
+    limit= aLimit;
+    skip = aSkip;
+    defaultVerb = new EntityEnumeratingProducerNodeVerb(aDefaultWhereClause, aDefaultOrderByClause);
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    EntityEnumeratingProducerNodeVerb verb = (EntityEnumeratingProducerNodeVerb) verbs.get(aVerb);
+    Iterator browser;
+
+    if (verb==null)
+      verb = defaultVerb;
+
+    if (verb==null)
+      throw new ProducerFailure("EntityEnumeratingProducerNode: unknown verb '"+aVerb+"'", null);
+
+    try {
+      browser = new EntityIteratorAdapter(
+          ParameterExpander.expandExpression( aValueMap, verb.whereClause ),
+          ParameterExpander.expandExpression( aValueMap, verb.orderByClause ),
+          100,
+          model,
+          definition,
+          ParameterExpander.evaluateIntegerExpressionWithDefault( aValueMap, limit, -1),
+          ParameterExpander.evaluateIntegerExpressionWithDefault( aValueMap, skip, 0));
+
+      while (browser.hasNext()) {
+        ParameterExpander.setValueForKey( aValueMap, key, browser.next());
+        super.produce(aValueMap, aVerb, aLogger);
+      }
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  };
+
+  public Set buildVerbSet() {
+    Set set;
+
+    set = super.buildVerbSet();
+    set.addAll(verbs.keySet());
+
+    return set;
+  };
+
+  public void addVerb(String aVerb, String aWhereClause, String anOrderByClause) {
+    verbs.put(aVerb, new EntityEnumeratingProducerNodeVerb(aWhereClause, anOrderByClause));
+  }
+
+  private class EntityEnumeratingProducerNodeVerb {
+    String whereClause;
+    String orderByClause;
+
+    EntityEnumeratingProducerNodeVerb(String aWhereClause, String anOrderByClause) {
+      whereClause = aWhereClause;
+      orderByClause = anOrderByClause;
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/EntityListProducerNode.java b/source/mir/producer/EntityListProducerNode.java
new file mode 100755 (executable)
index 0000000..e036230
--- /dev/null
@@ -0,0 +1,72 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.entity.adapter.*;
+import mir.entity.*;
+import mir.storage.*;
+import mir.util.*;
+
+public class EntityListProducerNode extends ProducerNodeDecorator {
+  private String key;
+  private String whereClause;
+  private String orderByClause;
+  private int batchSize;
+  private EntityAdapterModel model;
+  private String definition;
+  private String limitExpression;
+  private String skipExpression;
+
+  public EntityListProducerNode(String aKey,
+      EntityAdapterModel aModel, String aDefinition,
+      String aWhereClause, String anOrderByClause,
+      String aLimitExpression, String aSkipExpression, ProducerNode aSubNode) {
+    super(aSubNode);
+
+    model = aModel;
+    definition = aDefinition;
+    key = aKey;
+    whereClause = aWhereClause;
+    orderByClause = anOrderByClause;
+    limitExpression = aLimitExpression;
+    skipExpression = aSkipExpression;
+  }
+
+  public EntityListProducerNode(String aKey,
+      EntityAdapterModel aModel, String aDefinition,
+      String aWhereClause, String anOrderByClause,
+      int aLimit, int aSkip, ProducerNode aSubNode) {
+    this(aKey,  aModel, aDefinition, aWhereClause, anOrderByClause,
+         Integer.toString(aLimit), Integer.toString(aSkip), aSubNode);
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    try {
+      int limit = ParameterExpander.evaluateIntegerExpressionWithDefault(aValueMap, limitExpression, -1);
+      int skip = ParameterExpander.evaluateIntegerExpressionWithDefault(aValueMap, skipExpression, 0);
+
+      if (skipExpression != null && !skipExpression.trim().equals(""))
+        skip = ParameterExpander.evaluateIntegerExpression(aValueMap, skipExpression);
+
+      ParameterExpander.setValueForKey(
+        aValueMap,
+        key,
+        new CachingRewindableIterator(
+          new EntityIteratorAdapter(
+            ParameterExpander.expandExpression( aValueMap, whereClause ),
+            ParameterExpander.expandExpression( aValueMap, orderByClause ),
+            20,
+            model,
+            definition,
+            limit,
+            skip )
+        )
+      );
+      super.produce(aValueMap, aVerb, aLogger);
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  };
+
+}
\ No newline at end of file
diff --git a/source/mir/producer/EntityModifyingProducerNode.java b/source/mir/producer/EntityModifyingProducerNode.java
new file mode 100755 (executable)
index 0000000..22e054b
--- /dev/null
@@ -0,0 +1,44 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mir.util.*;
+
+
+public abstract class EntityModifyingProducerNode implements ProducerNode {
+  String entityExpression;
+  String entityField;
+  String valueExpression;
+
+  public EntityModifyingProducerNode(String anEntityExpression, String anEntityField, String aValueExpression) {
+    entityExpression = anEntityExpression;
+    entityField = anEntityField;
+    valueExpression = aValueExpression;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    Object entity;
+
+    try {
+      entity = ParameterExpander.findValueForKey( aValueMap, entityExpression );
+
+      if (entity instanceof EntityAdapter) {
+        ((EntityAdapter) entity).getEntity().setValueForProperty(entityField, valueExpression);
+        ((EntityAdapter) entity).getEntity().update();
+      }
+      else
+        throw new Exception( entityExpression + " does not evaluate to an entity");
+    }
+    catch (Throwable t) {
+      aLogger.println("Error while performing entity modifying operation: " + t.getMessage());
+
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  }
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/EvaluatedAssignmentProducerNode.java b/source/mir/producer/EvaluatedAssignmentProducerNode.java
new file mode 100755 (executable)
index 0000000..0a7d071
--- /dev/null
@@ -0,0 +1,33 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.util.*;
+
+public class EvaluatedAssignmentProducerNode implements ProducerNode {
+  private String key;
+  private String bundleIdentifier;
+  private String value;
+
+  public EvaluatedAssignmentProducerNode(String aKey, String aValue) {
+    key = aKey;
+    value = aValue;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    try {
+      ParameterExpander.setValueForKey(
+         aValueMap,
+         key,
+         ParameterExpander.evaluateExpression( aValueMap, value ));
+
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  };
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/ExpandedAssignmentProducerNode.java b/source/mir/producer/ExpandedAssignmentProducerNode.java
new file mode 100755 (executable)
index 0000000..86d1012
--- /dev/null
@@ -0,0 +1,33 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.util.*;
+
+public class ExpandedAssignmentProducerNode implements ProducerNode {
+  private String key;
+  private String bundleIdentifier;
+  private String value;
+
+  public ExpandedAssignmentProducerNode(String aKey, String aValue) {
+    key = aKey;
+    value = aValue;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    try {
+      ParameterExpander.setValueForKey(
+         aValueMap,
+         key,
+         ParameterExpander.expandExpression( aValueMap, value ));
+
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  };
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/FileDateSettingProducerNode.java b/source/mir/producer/FileDateSettingProducerNode.java
new file mode 100755 (executable)
index 0000000..4a12062
--- /dev/null
@@ -0,0 +1,35 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.util.*;
+import mir.producer.*;
+import mir.generator.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
+
+public class FileDateSettingProducerNode extends FileOperationProducerNode {
+  String dateExpression;
+
+  public FileDateSettingProducerNode(String aFileIdentifier, String aDateExpression) {
+    super(aFileIdentifier);
+
+    dateExpression = aDateExpression;
+  }
+
+  protected void perform(File aFile, Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    try {
+      Object date = ParameterExpander.findValueForKey( aValueMap, dateExpression );
+
+      if (!(date instanceof Date))
+        throw new ProducerFailure("FileDateSettingProducerNode: expression " + dateExpression + " does not evaluate to a Date!", null );
+
+      if (!aFile.setLastModified(((Date) date).getTime())) {
+        aLogger.println("Can't set date for " + aFile.getName());
+      }
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/FileDeletingProducerNode.java b/source/mir/producer/FileDeletingProducerNode.java
new file mode 100755 (executable)
index 0000000..cc6bd6a
--- /dev/null
@@ -0,0 +1,22 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.util.*;
+import mir.producer.*;
+import mir.generator.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
+
+public class FileDeletingProducerNode extends FileOperationProducerNode {
+
+  public FileDeletingProducerNode(String aFileIdentifier) {
+    super(aFileIdentifier);
+  }
+
+  protected void perform(File aFile, Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    if (!aFile.delete()) {
+      aLogger.print("Can't delete " + aFile.getName());
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/FileOperationProducerNode.java b/source/mir/producer/FileOperationProducerNode.java
new file mode 100755 (executable)
index 0000000..df8e674
--- /dev/null
@@ -0,0 +1,39 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.util.*;
+import mir.producer.*;
+import mir.generator.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
+
+public abstract class FileOperationProducerNode implements ProducerNode {
+  String fileName;
+
+  public FileOperationProducerNode(String aFileName) {
+    fileName = aFileName;
+  }
+
+  protected abstract void perform(File aFile, Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure;
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    String fileIdentifier;
+
+    try {
+      fileIdentifier = ParameterExpander.expandExpression( aValueMap, fileName );
+      File file = new File(fileIdentifier);
+
+      perform(file, aValueMap, aVerb, aLogger);
+    }
+    catch (Throwable t) {
+      aLogger.println("Error while performing file operation: " + t.getMessage());
+
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  }
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/GeneratingProducerNode.java b/source/mir/producer/GeneratingProducerNode.java
new file mode 100755 (executable)
index 0000000..e37abe0
--- /dev/null
@@ -0,0 +1,66 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.util.*;
+import mir.producer.*;
+import mir.generator.*;
+
+public class GeneratingProducerNode implements ProducerNode {
+  private String generatorExpression;
+  private String destinationExpression;
+  private String parametersExpression;
+  private Generator.GeneratorLibrary generatorLibrary;
+  private WriterEngine writerEngine;
+
+  public GeneratingProducerNode(Generator.GeneratorLibrary aGeneratorLibrary, WriterEngine aWriterEngine, String aGenerator, String aDestination, String aParameters) {
+    generatorExpression=aGenerator;
+    destinationExpression=aDestination;
+    parametersExpression=aParameters;
+    generatorLibrary = aGeneratorLibrary;
+    writerEngine = aWriterEngine;
+  }
+
+  public GeneratingProducerNode(Generator.GeneratorLibrary aGeneratorLibrary, WriterEngine aWriterEngine, String aGenerator, String aDestination) {
+    this(aGeneratorLibrary, aWriterEngine, aGenerator, aDestination, "");
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    Generator generator;
+    Object writer;
+    String generatorIdentifier;
+    String destinationIdentifier;
+    String parameters;
+
+    long startTime;
+    long endTime;
+
+    startTime = System.currentTimeMillis();
+    try {
+      destinationIdentifier = ParameterExpander.expandExpression( aValueMap, destinationExpression );
+      generatorIdentifier = ParameterExpander.expandExpression( aValueMap, generatorExpression );
+      parameters = ParameterExpander.expandExpression( aValueMap, parametersExpression );
+
+      aLogger.println("Generating " + generatorIdentifier + " into " + destinationIdentifier + " using parameters " + parameters);
+      aLogger.flush();
+
+      writer = writerEngine.openWriter( destinationIdentifier, parameters );
+      generator = generatorLibrary.makeGenerator( generatorIdentifier );
+      generator.generate(writer, aValueMap, aLogger);
+      writerEngine.closeWriter( writer );
+    }
+    catch (Throwable t) {
+      aLogger.println("  error while generating: " + t.getClass().getName() + ": " + t.getMessage());
+      t.printStackTrace(aLogger);
+      aLogger.flush();
+    }
+    endTime = System.currentTimeMillis();
+
+    aLogger.println("  Time: " + (endTime-startTime) + " ms");
+    aLogger.flush();
+  }
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/LoggingProducerNode.java b/source/mir/producer/LoggingProducerNode.java
new file mode 100755 (executable)
index 0000000..e1d0451
--- /dev/null
@@ -0,0 +1,30 @@
+package mir.producer;
+
+import java.io.*;
+import java.util.*;
+import mir.util.*;
+import mir.producer.*;
+
+public class LoggingProducerNode implements ProducerNode {
+  private String expression;
+
+  public LoggingProducerNode(String anExpression) {
+    expression = anExpression;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    String text;
+
+    try {
+      text = ParameterExpander.expandExpression( aValueMap, expression );
+      aLogger.println(text);
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  }
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/NodedProducer.java b/source/mir/producer/NodedProducer.java
new file mode 100755 (executable)
index 0000000..d3434d5
--- /dev/null
@@ -0,0 +1,25 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+
+public class NodedProducer implements Producer {
+  ProducerNode rootNode;
+  String verb;
+  Map baseValues;
+
+  public NodedProducer( ProducerNode aRootNode, String aVerb, Map aBaseValues) {
+    rootNode = aRootNode;
+    verb = aVerb;
+    baseValues = aBaseValues;
+  }
+
+  public void produce( PrintWriter aLogger ) throws ProducerFailure, ProducerExc {
+    Map valueMap;
+
+    valueMap = new HashMap();
+    valueMap.putAll(baseValues);
+
+    rootNode.produce(valueMap, verb, aLogger);
+  };
+}
diff --git a/source/mir/producer/NodedProducerFactory.java b/source/mir/producer/NodedProducerFactory.java
new file mode 100755 (executable)
index 0000000..b17be99
--- /dev/null
@@ -0,0 +1,39 @@
+package mir.producer;
+
+import java.util.*;
+import mir.producer.*;
+
+public class NodedProducerFactory implements ProducerFactory {
+  private ProducerNode rootNode;
+
+  public NodedProducerFactory(ProducerNode aRootNode) {
+    rootNode = aRootNode;
+  }
+
+  public mir.producer.Producer makeProducer(String aVerb, Map aBasicValueSet) throws ProducerFailure {
+    Map baseValues;
+
+    try {
+      baseValues = new HashMap();
+      baseValues.putAll(aBasicValueSet);
+
+      return new NodedProducer(rootNode, aVerb, baseValues);
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  };
+
+  public Iterator verbs() {
+    Set verbSet = rootNode.buildVerbSet();
+
+    if (verbSet.isEmpty()) {
+      verbSet = new HashSet();
+
+      verbSet.add("(default)");
+    }
+
+    return verbSet.iterator();
+  };
+}
+
diff --git a/source/mir/producer/Producer.java b/source/mir/producer/Producer.java
new file mode 100755 (executable)
index 0000000..47b894f
--- /dev/null
@@ -0,0 +1,7 @@
+package mir.producer;
+
+import java.io.*;
+
+public interface Producer {
+  public void produce( PrintWriter aLogger ) throws ProducerFailure, ProducerExc;
+}
diff --git a/source/mir/producer/ProducerExc.java b/source/mir/producer/ProducerExc.java
new file mode 100755 (executable)
index 0000000..35065ec
--- /dev/null
@@ -0,0 +1,9 @@
+package mir.producer;
+
+import multex.Exc;
+
+public class ProducerExc extends Exc {
+  public ProducerExc(String aMessage) {
+    super(aMessage);
+  }
+}
diff --git a/source/mir/producer/ProducerFactory.java b/source/mir/producer/ProducerFactory.java
new file mode 100755 (executable)
index 0000000..7136d8c
--- /dev/null
@@ -0,0 +1,9 @@
+package mir.producer;
+
+import java.util.*;
+
+public interface ProducerFactory {
+  public Producer makeProducer(String aVerb, Map aStartingValues) throws ProducerFailure, ProducerExc;
+  public Iterator verbs();
+}
+
diff --git a/source/mir/producer/ProducerFailure.java b/source/mir/producer/ProducerFailure.java
new file mode 100755 (executable)
index 0000000..0016c6a
--- /dev/null
@@ -0,0 +1,14 @@
+package mir.producer;
+
+import multex.Failure;
+
+public class ProducerFailure extends Failure {
+
+  public ProducerFailure(String msg,Throwable cause) {
+    super(msg,cause);
+  }
+
+  public ProducerFailure(Throwable aCause) {
+    this (aCause.getMessage(), aCause);
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/ProducerNode.java b/source/mir/producer/ProducerNode.java
new file mode 100755 (executable)
index 0000000..4f7b70a
--- /dev/null
@@ -0,0 +1,9 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+
+public interface ProducerNode {
+  public void produce(Map aValueSet, String aVerb, PrintWriter aLogger) throws ProducerExc, ProducerFailure;
+  public Set buildVerbSet();
+}
\ No newline at end of file
diff --git a/source/mir/producer/ProducerNodeDecorator.java b/source/mir/producer/ProducerNodeDecorator.java
new file mode 100755 (executable)
index 0000000..9709499
--- /dev/null
@@ -0,0 +1,24 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+
+public class ProducerNodeDecorator implements ProducerNode {
+  private ProducerNode slave;
+
+  protected ProducerNodeDecorator(ProducerNode aSlave) {
+    slave = aSlave;
+  }
+
+  public void produce(Map aValueSet, String aVerb, PrintWriter aLogger) throws ProducerFailure, ProducerExc {
+    if (slave!=null)
+      slave.produce(aValueSet, aVerb, aLogger);
+  }
+
+  public Set buildVerbSet() {
+    if (slave!=null)
+      return slave.buildVerbSet();
+    else
+      return new HashSet();
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/ResourceBundleProducerNode.java b/source/mir/producer/ResourceBundleProducerNode.java
new file mode 100755 (executable)
index 0000000..e172d11
--- /dev/null
@@ -0,0 +1,52 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import org.apache.struts.util.MessageResources;
+import mir.util.*;
+import mir.misc.*;
+
+public class ResourceBundleProducerNode extends ProducerNodeDecorator {
+  private String key;
+  private String bundleIdentifier;
+  private String languageIdentifier;
+
+  public ResourceBundleProducerNode(String aKey, String aBundleIdentifier, ProducerNode aSubNode) {
+    this (aKey, aBundleIdentifier, null, aSubNode);
+  }
+
+  public ResourceBundleProducerNode(String aKey, String aBundleIdentifier, String aLanguageIdentifier, ProducerNode aSubNode) {
+    super(aSubNode);
+
+    bundleIdentifier = aBundleIdentifier;
+    languageIdentifier = aLanguageIdentifier;
+    key = aKey;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    Object messages;
+
+
+    try {
+      if (languageIdentifier!=null) {
+        messages =
+            new ResourceBundleGeneratorFunction(
+                new Locale(ParameterExpander.expandExpression( aValueMap, languageIdentifier ), "" ),
+                MessageResources.getMessageResources( ParameterExpander.expandExpression( aValueMap, bundleIdentifier ))
+            );
+      }
+      else {
+        messages =
+          MessageResources.getMessageResources(
+              ParameterExpander.expandExpression( aValueMap, bundleIdentifier ));
+      }
+      ParameterExpander.setValueForKey( aValueMap, key, messages );
+
+      super.produce(aValueMap, aVerb, aLogger);
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  };
+
+}
\ No newline at end of file
diff --git a/source/mir/producer/ScriptCallingProducerNode.java b/source/mir/producer/ScriptCallingProducerNode.java
new file mode 100755 (executable)
index 0000000..61a1fb1
--- /dev/null
@@ -0,0 +1,37 @@
+package mir.producer;
+
+import java.io.*;
+import java.util.*;
+import mir.util.*;
+
+// ML: needs to be tested!
+
+public class ScriptCallingProducerNode implements ProducerNode  {
+  String scriptExpression;
+
+  public ScriptCallingProducerNode(String aScriptExpression) {
+    scriptExpression = aScriptExpression;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    String script;
+    Process process;
+    int returnValue;
+
+    try {
+      script = ParameterExpander.expandExpression( aValueMap, scriptExpression );
+      aLogger.println("Executing " + script + ":");
+
+      process = Runtime.getRuntime().exec(script);
+      returnValue = process.waitFor();
+      aLogger.println("Terminated successfully, return value = " + returnValue + ".");
+    }
+    catch (Throwable e) {
+      throw new ProducerFailure("Executing script failed: " + e.getMessage(), e);
+    }
+  }
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
diff --git a/source/mir/producer/ValuesMapProducerNode.java b/source/mir/producer/ValuesMapProducerNode.java
new file mode 100755 (executable)
index 0000000..45d4790
--- /dev/null
@@ -0,0 +1,28 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import org.apache.struts.util.MessageResources;
+import mir.util.*;
+
+public class ValuesMapProducerNode extends ProducerNodeDecorator {
+  private String key;
+  private String bundleIdentifier;
+  private Map map;
+
+  public ValuesMapProducerNode(Map aMap, ProducerNode aSubNode) {
+    super(aSubNode);
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    try {
+      aValueMap.putAll(map);
+
+      super.produce(aValueMap, aVerb, aLogger);
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  };
+
+}
\ No newline at end of file
diff --git a/source/mir/producer/reader/DefaultProducerNodeBuilders.java b/source/mir/producer/reader/DefaultProducerNodeBuilders.java
new file mode 100755 (executable)
index 0000000..97feb4f
--- /dev/null
@@ -0,0 +1,614 @@
+package mir.producer.reader;
+
+import java.util.*;
+import mir.generator.*;
+import mir.producer.*;
+import mir.entity.adapter.*;
+import mir.util.*;
+
+public class DefaultProducerNodeBuilders {
+
+  public static void registerBuilders(ProducerNodeBuilderLibrary aBuilderLibrary,
+       EntityAdapterModel aModel, Generator.GeneratorLibrary aGeneratorLibrary,
+       WriterEngine aWriterEngine) {
+
+    aBuilderLibrary.registerBuilder("Set", EvaluatedAssignmentProducerNodeBuilder.class);
+    aBuilderLibrary.registerBuilder("Define", ExpandedAssignmentProducerNodeBuilder.class);
+    aBuilderLibrary.registerBuilder("Log", LoggingProducerNodeBuilder.class);
+    aBuilderLibrary.registerBuilder("Execute", ScriptCallingProducerNodeBuilder.class);
+    aBuilderLibrary.registerBuilder("Resource", ResourceBundleProducerNodeBuilder.class);
+
+    aBuilderLibrary.registerBuilder("DeleteFile", FileDeletingProducerNodeBuilder.class);
+    aBuilderLibrary.registerBuilder("SetFileDate", FileDateSettingProducerNodeBuilder.class);
+    aBuilderLibrary.registerBuilder("If", ConditionalProducerNodeBuilder.class);
+
+
+    aBuilderLibrary.registerFactory("Enumerate", new EnumeratingProducerNodeBuilder.factory(aModel));
+    aBuilderLibrary.registerFactory("List", new ListProducerNodeBuilder.factory(aModel));
+    aBuilderLibrary.registerFactory("Batch", new BatchingProducerNodeBuilder.factory(aModel));
+
+    aBuilderLibrary.registerFactory("Generate",
+        new GeneratingProducerNodeBuilder.factory(aGeneratorLibrary, aWriterEngine));
+  }
+
+  public static abstract class AbstractProducerNodeBuilder implements ProducerNodeBuilder {
+    private Map attributes;
+    private Map subNodes;
+    private Set availableSubnodes;
+
+    public AbstractProducerNodeBuilder(String anAvailableSubNodes[]) {
+      attributes = new HashMap();
+      subNodes = new HashMap();
+      availableSubnodes = new HashSet(Arrays.asList(anAvailableSubNodes));
+    }
+
+    protected ProducerNode getSubNode(String aName) {
+      return (ProducerNode) subNodes.get(aName);
+    }
+
+    public void setSubNode(String aName, ProducerNode aNode) {
+      subNodes.put(aName, aNode);
+    };
+
+    public Set getAvailableSubNodes() {
+      return availableSubnodes;
+    };
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  // general attribute names, specifc builders reference these, to keep attribute
+  //    names consistent
+
+  public final static String   SELECTION_ATTRIBUTE = "selection";
+  public final static String   ORDER_ATTRIBUTE = "order";
+  public final static String   DEFINITION_ATTRIBUTE = "table";
+  public final static String   SKIP_ATTRIBUTE = "skip";
+  public final static String   KEY_ATTRIBUTE = "key";
+  public final static String   LIMIT_ATTRIBUTE = "limit";
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class ExpandedAssignmentProducerNodeBuilder extends AbstractProducerNodeBuilder {
+    private final static String   ASSIGNMENT_KEY_ATTRIBUTE = KEY_ATTRIBUTE;
+    private final static String   ASSIGNMENT_VALUE_ATTRIBUTE = "value";
+    private final static String[] ASSIGNMENT_REQUIRED_ATTRIBUTES = { ASSIGNMENT_KEY_ATTRIBUTE, ASSIGNMENT_VALUE_ATTRIBUTE };
+    private final static String[] ASSIGNMENT_OPTIONAL_ATTRIBUTES = {};
+    private final static String[] ASSIGNMENT_SUBNODES = {};
+
+    private String key;
+    private String value;
+
+    public ExpandedAssignmentProducerNodeBuilder() {
+      super(ASSIGNMENT_SUBNODES);
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributes(anAttributes, ASSIGNMENT_REQUIRED_ATTRIBUTES, ASSIGNMENT_OPTIONAL_ATTRIBUTES);
+
+      key = (String) anAttributes.get(ASSIGNMENT_KEY_ATTRIBUTE);
+      value = (String) anAttributes.get(ASSIGNMENT_VALUE_ATTRIBUTE);
+    };
+
+    public ProducerNode constructNode() {
+      return new ExpandedAssignmentProducerNode(key, value);
+    };
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class EvaluatedAssignmentProducerNodeBuilder extends AbstractProducerNodeBuilder {
+    private final static String   ASSIGNMENT_KEY_ATTRIBUTE = KEY_ATTRIBUTE;
+    private final static String   ASSIGNMENT_VALUE_ATTRIBUTE = "value";
+    private final static String[] ASSIGNMENT_REQUIRED_ATTRIBUTES = { ASSIGNMENT_KEY_ATTRIBUTE, ASSIGNMENT_VALUE_ATTRIBUTE };
+    private final static String[] ASSIGNMENT_OPTIONAL_ATTRIBUTES = {};
+    private final static String[] ASSIGNMENT_SUBNODES = {};
+
+    private String key;
+    private String value;
+
+    public EvaluatedAssignmentProducerNodeBuilder() {
+      super(ASSIGNMENT_SUBNODES);
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributes(anAttributes, ASSIGNMENT_REQUIRED_ATTRIBUTES, ASSIGNMENT_OPTIONAL_ATTRIBUTES);
+
+      key = (String) anAttributes.get(ASSIGNMENT_KEY_ATTRIBUTE);
+      value = (String) anAttributes.get(ASSIGNMENT_VALUE_ATTRIBUTE);
+    };
+
+    public ProducerNode constructNode() {
+      return new EvaluatedAssignmentProducerNode(key, value);
+    };
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class EnumeratingProducerNodeBuilder extends AbstractProducerNodeBuilder {
+    private final static String   ENUMERATION_KEY_ATTRIBUTE = KEY_ATTRIBUTE;
+    private final static String   ENUMERATION_DEFINITION_ATTRIBUTE = DEFINITION_ATTRIBUTE;
+    private final static String   ENUMERATION_SELECTION_ATTRIBUTE = SELECTION_ATTRIBUTE;
+    private final static String   ENUMERATION_ORDER_ATTRIBUTE = ORDER_ATTRIBUTE;
+    private final static String   ENUMERATION_DEFAULT_SUBNODE = "default";
+    private final static String   ENUMERATION_LIMIT_ATTRIBUTE = LIMIT_ATTRIBUTE;
+    private final static String   ENUMERATION_SKIP_ATTRIBUTE = SKIP_ATTRIBUTE;
+    private final static String[] ENUMERATION_REQUIRED_ATTRIBUTES = { ENUMERATION_KEY_ATTRIBUTE, ENUMERATION_DEFINITION_ATTRIBUTE };
+    private final static String[] ENUMERATION_OPTIONAL_ATTRIBUTES = { ENUMERATION_SELECTION_ATTRIBUTE, ENUMERATION_ORDER_ATTRIBUTE, ENUMERATION_LIMIT_ATTRIBUTE, ENUMERATION_SKIP_ATTRIBUTE};
+    private final static String[] ENUMERATION_SUBNODES = {ENUMERATION_DEFAULT_SUBNODE};
+
+    private String key;
+    private String definition;
+    private String selection;
+    private String order;
+    private String limit;
+    private String skip;
+    private EntityAdapterModel model;
+
+    public EnumeratingProducerNodeBuilder(EntityAdapterModel aModel) {
+      super(ENUMERATION_SUBNODES);
+
+      model = aModel;
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc  {
+      ReaderTool.checkAttributes(anAttributes, ENUMERATION_REQUIRED_ATTRIBUTES, ENUMERATION_OPTIONAL_ATTRIBUTES);
+
+      key = (String) anAttributes.get(ENUMERATION_KEY_ATTRIBUTE);
+      definition = (String) anAttributes.get(ENUMERATION_DEFINITION_ATTRIBUTE);
+      selection = (String) ReaderTool.getStringAttributeWithDefault(anAttributes, ENUMERATION_SELECTION_ATTRIBUTE, "");
+      order = (String) ReaderTool.getStringAttributeWithDefault(anAttributes, ENUMERATION_ORDER_ATTRIBUTE, "");
+      limit = (String) anAttributes.get(ENUMERATION_LIMIT_ATTRIBUTE);
+      skip = (String) anAttributes.get(ENUMERATION_SKIP_ATTRIBUTE);
+    };
+
+    public ProducerNode constructNode() {
+      return new EntityEnumeratingProducerNode(key, model, definition, selection, order, limit, skip, getSubNode(ENUMERATION_DEFAULT_SUBNODE ));
+    };
+
+    public static class factory implements ProducerNodeBuilderFactory {
+      private EntityAdapterModel model;
+
+      public factory(EntityAdapterModel aModel) {
+        model = aModel;
+      }
+
+      public ProducerNodeBuilder makeBuilder() {
+        return new EnumeratingProducerNodeBuilder(model);
+      }
+    }
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class ListProducerNodeBuilder extends AbstractProducerNodeBuilder {
+    private final static String   LIST_KEY_ATTRIBUTE = KEY_ATTRIBUTE;
+    private final static String   LIST_DEFINITION_ATTRIBUTE = DEFINITION_ATTRIBUTE;
+    private final static String   LIST_SELECTION_ATTRIBUTE = SELECTION_ATTRIBUTE;
+    private final static String   LIST_ORDER_ATTRIBUTE = ORDER_ATTRIBUTE;
+    private final static String   LIST_DEFAULT_SUBNODE = "default";
+    private final static String   LIST_LIMIT_ATTRIBUTE = LIMIT_ATTRIBUTE;
+    private final static String   LIST_SKIP_ATTRIBUTE = SKIP_ATTRIBUTE;
+    private final static String[] LIST_REQUIRED_ATTRIBUTES = { LIST_KEY_ATTRIBUTE, LIST_DEFINITION_ATTRIBUTE };
+    private final static String[] LIST_OPTIONAL_ATTRIBUTES = { LIST_SELECTION_ATTRIBUTE, LIST_ORDER_ATTRIBUTE, LIST_SKIP_ATTRIBUTE, LIST_LIMIT_ATTRIBUTE};
+    private final static String[] LIST_SUBNODES = {};
+
+    private String key;
+    private String definition;
+    private String selection;
+    private String order;
+    private String limit;
+    private String skip;
+    private EntityAdapterModel model;
+
+    public ListProducerNodeBuilder(EntityAdapterModel aModel) {
+      super(LIST_SUBNODES);
+
+      model = aModel;
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributes(anAttributes, LIST_REQUIRED_ATTRIBUTES, LIST_OPTIONAL_ATTRIBUTES);
+
+      key = (String) anAttributes.get(LIST_KEY_ATTRIBUTE);
+      definition = (String) anAttributes.get(LIST_DEFINITION_ATTRIBUTE);
+      selection = (String) ReaderTool.getStringAttributeWithDefault(anAttributes, LIST_SELECTION_ATTRIBUTE, "");
+      order = (String) ReaderTool.getStringAttributeWithDefault(anAttributes, LIST_ORDER_ATTRIBUTE, "");
+      limit = (String) anAttributes.get(LIST_LIMIT_ATTRIBUTE);
+      skip = (String) anAttributes.get(LIST_SKIP_ATTRIBUTE);
+    };
+
+    public ProducerNode constructNode() {
+      return new EntityListProducerNode(key, model, definition, selection, order, limit, skip, null );
+    };
+
+    public static class factory implements ProducerNodeBuilderFactory {
+      private EntityAdapterModel model;
+
+      public factory(EntityAdapterModel aModel) {
+        model = aModel;
+      }
+
+      public ProducerNodeBuilder makeBuilder() {
+        return new ListProducerNodeBuilder(model);
+      }
+    }
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class LoggingProducerNodeBuilder extends AbstractProducerNodeBuilder {
+    private final static String   LOG_MESSAGE_ATTRIBUTE = "message";
+    private final static String[] LOG_REQUIRED_ATTRIBUTES = { LOG_MESSAGE_ATTRIBUTE };
+    private final static String[] LOG_OPTIONAL_ATTRIBUTES = {};
+    private final static String[] LOG_SUBNODES = {};
+
+    private String message;
+
+    public LoggingProducerNodeBuilder() {
+      super(LOG_SUBNODES);
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributes(anAttributes, LOG_REQUIRED_ATTRIBUTES, LOG_OPTIONAL_ATTRIBUTES);
+
+      message = (String) anAttributes.get(LOG_MESSAGE_ATTRIBUTE);
+    };
+
+    public ProducerNode constructNode() {
+      return new LoggingProducerNode(message);
+    };
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class ResourceBundleProducerNodeBuilder extends AbstractProducerNodeBuilder {
+    private final static String   RESOURCEBUNDLE_KEY_ATTRIBUTE = KEY_ATTRIBUTE;
+    private final static String   RESOURCEBUNDLE_BUNDLE_ATTRIBUTE = "bundle";
+    private final static String   RESOURCEBUNDLE_LANGUAGE_ATTRIBUTE = "language";
+    private final static String   RESOURCEBUNDLE_DEFAULT_SUBNODE = "default";
+    private final static String[] RESOURCEBUNDLE_REQUIRED_ATTRIBUTES = { RESOURCEBUNDLE_KEY_ATTRIBUTE, RESOURCEBUNDLE_BUNDLE_ATTRIBUTE };
+    private final static String[] RESOURCEBUNDLE_OPTIONAL_ATTRIBUTES = { RESOURCEBUNDLE_LANGUAGE_ATTRIBUTE};
+    private final static String[] RESOURCEBUNDLE_SUBNODES = {};
+
+    private String key;
+    private String bundle;
+    private String language;
+
+    public ResourceBundleProducerNodeBuilder() {
+      super(RESOURCEBUNDLE_SUBNODES);
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributes(anAttributes, RESOURCEBUNDLE_REQUIRED_ATTRIBUTES, RESOURCEBUNDLE_OPTIONAL_ATTRIBUTES);
+
+      key = (String) anAttributes.get(RESOURCEBUNDLE_KEY_ATTRIBUTE);
+      bundle = (String) anAttributes.get(RESOURCEBUNDLE_BUNDLE_ATTRIBUTE);
+      language = (String) anAttributes.get(RESOURCEBUNDLE_LANGUAGE_ATTRIBUTE);
+    };
+
+    public ProducerNode constructNode() {
+      return new ResourceBundleProducerNode(key, bundle, language, null );
+    };
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class FileDateSettingProducerNodeBuilder extends AbstractProducerNodeBuilder {
+    private final static String   FILEDATESETTING_FILE_ATTRIBUTE = "filename";
+    private final static String   FILEDATESETTING_DATE_ATTRIBUTE = "date";
+    private final static String[] FILEDATESETTING_REQUIRED_ATTRIBUTES = { FILEDATESETTING_FILE_ATTRIBUTE, FILEDATESETTING_DATE_ATTRIBUTE };
+    private final static String[] FILEDATESETTING_OPTIONAL_ATTRIBUTES = { };
+    private final static String[] FILEDATESETTING_SUBNODES = {};
+
+    private String fileNameKey;
+    private String dateKey;
+
+    public FileDateSettingProducerNodeBuilder() {
+      super(FILEDATESETTING_SUBNODES);
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributes(anAttributes, FILEDATESETTING_REQUIRED_ATTRIBUTES, FILEDATESETTING_OPTIONAL_ATTRIBUTES);
+
+      fileNameKey = (String) anAttributes.get(FILEDATESETTING_FILE_ATTRIBUTE);
+      dateKey = (String) anAttributes.get(FILEDATESETTING_DATE_ATTRIBUTE);
+    };
+
+    public ProducerNode constructNode() {
+      return new FileDateSettingProducerNode(fileNameKey, dateKey);
+    };
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class FileDeletingProducerNodeBuilder extends AbstractProducerNodeBuilder {
+    private final static String   FILEDELETING_FILE_ATTRIBUTE = "filename";
+    private final static String[] FILEDELETING_REQUIRED_ATTRIBUTES = { FILEDELETING_FILE_ATTRIBUTE };
+    private final static String[] FILEDELETING_OPTIONAL_ATTRIBUTES = { };
+    private final static String[] FILEDELETING_SUBNODES = { };
+
+    private String fileNameKey;
+
+    public FileDeletingProducerNodeBuilder() {
+      super(FILEDELETING_SUBNODES);
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributes(anAttributes, FILEDELETING_REQUIRED_ATTRIBUTES, FILEDELETING_OPTIONAL_ATTRIBUTES);
+
+      fileNameKey = (String) anAttributes.get(FILEDELETING_FILE_ATTRIBUTE);
+    };
+
+    public ProducerNode constructNode() {
+      return new FileDeletingProducerNode(fileNameKey);
+    };
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class ScriptCallingProducerNodeBuilder extends AbstractProducerNodeBuilder {
+    private final static String   SCRIPT_COMMAND_ATTRIBUTE = "command";
+    private final static String[] SCRIPT_REQUIRED_ATTRIBUTES = { SCRIPT_COMMAND_ATTRIBUTE };
+    private final static String[] SCRIPT_OPTIONAL_ATTRIBUTES = {};
+    private final static String[] SCRIPT_SUBNODES = {};
+
+    private String command;
+
+    public ScriptCallingProducerNodeBuilder() {
+      super(SCRIPT_SUBNODES);
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributes(anAttributes, SCRIPT_REQUIRED_ATTRIBUTES, SCRIPT_OPTIONAL_ATTRIBUTES);
+
+      command = (String) anAttributes.get(SCRIPT_COMMAND_ATTRIBUTE);
+    };
+
+    public ProducerNode constructNode() {
+      return new ScriptCallingProducerNode(command);
+    };
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class GeneratingProducerNodeBuilder extends AbstractProducerNodeBuilder {
+    private final static String   GENERATION_GENERATOR_ATTRIBUTE = "generator";
+    private final static String   GENERATION_DESTINATION_ATTRIBUTE = "destination";
+    private final static String   GENERATION_PARAMETERS_ATTRIBUTE = "parameters";
+    private final static String[] GENERATION_REQUIRED_ATTRIBUTES = { GENERATION_GENERATOR_ATTRIBUTE, GENERATION_DESTINATION_ATTRIBUTE };
+    private final static String[] GENERATION_OPTIONAL_ATTRIBUTES = { GENERATION_PARAMETERS_ATTRIBUTE};
+    private final static String[] GENERATION_SUBNODES = {};
+
+    private String generator;
+    private String destination;
+    private String parameters;
+    private Generator.GeneratorLibrary generatorLibrary;
+    private WriterEngine writerEngine;
+
+    public GeneratingProducerNodeBuilder(Generator.GeneratorLibrary aGeneratorLibrary, WriterEngine aWriterEngine) {
+      super(GENERATION_SUBNODES);
+
+      writerEngine = aWriterEngine;
+      generatorLibrary = aGeneratorLibrary;
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributes(anAttributes, GENERATION_REQUIRED_ATTRIBUTES, GENERATION_OPTIONAL_ATTRIBUTES);
+
+      generator = (String) anAttributes.get(GENERATION_GENERATOR_ATTRIBUTE);
+      destination = (String) anAttributes.get(GENERATION_DESTINATION_ATTRIBUTE);
+      parameters = ReaderTool.getStringAttributeWithDefault(anAttributes, GENERATION_PARAMETERS_ATTRIBUTE, "" );
+    };
+
+    public ProducerNode constructNode() {
+      return new GeneratingProducerNode(generatorLibrary, writerEngine, generator, destination, parameters);
+    };
+
+    public static class factory implements ProducerNodeBuilderFactory {
+      private Generator.GeneratorLibrary generatorLibrary;
+      private WriterEngine writerEngine;
+
+      public factory(Generator.GeneratorLibrary aGeneratorLibrary, WriterEngine aWriterEngine) {
+        writerEngine = aWriterEngine;
+        generatorLibrary = aGeneratorLibrary;
+      }
+
+      public ProducerNodeBuilder makeBuilder() {
+        return new GeneratingProducerNodeBuilder(generatorLibrary, writerEngine);
+      }
+    }
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class BatchingProducerNodeBuilder extends AbstractProducerNodeBuilder {
+
+    private final static String   BATCHER_DATAKEY_ATTRIBUTE = KEY_ATTRIBUTE;
+    private final static String   BATCHER_INFOKEY_ATTRIBUTE = "infokey";
+    private final static String   BATCHER_DEFINITION_ATTRIBUTE = DEFINITION_ATTRIBUTE;
+    private final static String   BATCHER_SELECTION_ATTRIBUTE = SELECTION_ATTRIBUTE;
+    private final static String   BATCHER_ORDER_ATTRIBUTE = ORDER_ATTRIBUTE;
+
+    private final static String   BATCHER_BATCHSIZE_ATTRIBUTE = "batchsize";
+    private final static String   BATCHER_MINBATCHSIZE_ATTRIBUTE = "minbatchsize";
+    private final static String   BATCHER_SKIP_ATTRIBUTE = SKIP_ATTRIBUTE;
+
+    private final static String   BATCHER_PROCESS_ATTRIBUTE = "process";
+
+    private final static String   BATCHER_BATCH_SUBNODE = "batches";
+    private final static String   BATCHER_BATCHLIST_SUBNODE = "batchlist";
+    private final static String[] BATCHER_REQUIRED_ATTRIBUTES = { BATCHER_DATAKEY_ATTRIBUTE, BATCHER_INFOKEY_ATTRIBUTE, BATCHER_DEFINITION_ATTRIBUTE, BATCHER_BATCHSIZE_ATTRIBUTE };
+    private final static String[] BATCHER_OPTIONAL_ATTRIBUTES = { BATCHER_SELECTION_ATTRIBUTE, BATCHER_ORDER_ATTRIBUTE, BATCHER_MINBATCHSIZE_ATTRIBUTE, BATCHER_SKIP_ATTRIBUTE, BATCHER_PROCESS_ATTRIBUTE };
+    private final static String[] BATCHER_SUBNODES = { BATCHER_BATCH_SUBNODE, BATCHER_BATCHLIST_SUBNODE };
+
+    // ML: batchSize, minBatchSize, skip should be expressions!
+
+    private EntityAdapterModel model;
+    private String batchDataKey;
+    private String batchInfoKey;
+    private String definition;
+    private String selection;
+    private String order;
+    private String batchSize;
+    private String minBatchSize;
+    private String skip;
+    private String process;
+
+    public BatchingProducerNodeBuilder(EntityAdapterModel aModel) {
+      super(BATCHER_SUBNODES);
+
+      model = aModel;
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributes(anAttributes, BATCHER_REQUIRED_ATTRIBUTES, BATCHER_OPTIONAL_ATTRIBUTES);
+
+      batchDataKey = ReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_DATAKEY_ATTRIBUTE, "data" );
+      batchInfoKey = ReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_INFOKEY_ATTRIBUTE, "info" );
+      definition = ReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_DEFINITION_ATTRIBUTE, "" );
+      selection = ReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_SELECTION_ATTRIBUTE, "" );
+      order = ReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_ORDER_ATTRIBUTE, "" );
+
+      batchSize = ReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_BATCHSIZE_ATTRIBUTE, "20" );
+      minBatchSize = ReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_MINBATCHSIZE_ATTRIBUTE, "0" );
+      skip = ReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_SKIP_ATTRIBUTE, "0" );
+      process = ReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_PROCESS_ATTRIBUTE, "-1" );
+    };
+
+    public ProducerNode constructNode() {
+      return new EntityBatchingProducerNode(
+          batchDataKey,
+          batchInfoKey,
+          model,
+          definition,
+          selection,
+          order,
+          batchSize,
+          minBatchSize,
+          skip,
+          process,
+          getSubNode( BATCHER_BATCH_SUBNODE ),
+          getSubNode( BATCHER_BATCHLIST_SUBNODE )
+      );
+    };
+
+    public static class factory implements ProducerNodeBuilderFactory {
+      private EntityAdapterModel model;
+
+      public factory(EntityAdapterModel aModel) {
+        model = aModel;
+      }
+
+      public ProducerNodeBuilder makeBuilder() {
+        return new BatchingProducerNodeBuilder(model);
+      }
+    }
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class ConditionalProducerNodeBuilder extends AbstractProducerNodeBuilder {
+    private final static String   IF_CONDITION_ATTRIBUTE = "condition";
+
+    private final static String   IF_TRUE_SUBNODE = "then";
+    private final static String   IF_FALSE_SUBNODE = "else";
+    private final static String[] IF_REQUIRED_ATTRIBUTES = { IF_CONDITION_ATTRIBUTE };
+    private final static String[] IF_OPTIONAL_ATTRIBUTES = {  };
+    private final static String[] IF_SUBNODES = { IF_TRUE_SUBNODE, IF_FALSE_SUBNODE };
+
+    private String condition;
+
+    public ConditionalProducerNodeBuilder() {
+      super(IF_SUBNODES);
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributes(anAttributes, IF_REQUIRED_ATTRIBUTES, IF_OPTIONAL_ATTRIBUTES);
+
+      condition = (String) anAttributes.get( IF_CONDITION_ATTRIBUTE );
+    };
+
+    public ProducerNode constructNode() {
+      return new ConditionalProducerNode(
+          condition,
+          getSubNode( IF_TRUE_SUBNODE ),
+          getSubNode( IF_FALSE_SUBNODE )
+      );
+    };
+
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class ScriptedProducerParameterNodeBuilder implements ProducerNodeBuilder {
+    private String parameterName;
+    private String scriptedNodeName;
+
+    public ScriptedProducerParameterNodeBuilder(String aScriptedNodeName, String aParameterName) {
+      parameterName = aParameterName;
+      scriptedNodeName = aScriptedNodeName;
+    }
+
+    public void setSubNode(String aName, ProducerNode aNode) {
+    };
+
+    public Set getAvailableSubNodes() {
+      return new HashSet();
+    };
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      if (!anAttributes.isEmpty())
+        throw new ProducerConfigExc("No parameters allowed here");
+    };
+
+    public ProducerNode constructNode() {
+      return new ScriptedProducerNodeDefinition.NodeParameterProducerNode(scriptedNodeName, parameterName);
+    };
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class ScriptedProducerNodeBuilder implements ProducerNodeBuilder {
+    private ScriptedProducerNodeDefinition definition;
+    private Map nodeParameterValues;
+    private Map parameterValues;
+
+    public ScriptedProducerNodeBuilder(ScriptedProducerNodeDefinition aDefinition) {
+      definition = aDefinition;
+
+      parameterValues = new HashMap();
+      parameterValues.putAll(definition.getParameters());
+
+      nodeParameterValues = new HashMap();
+    }
+
+    public void setSubNode(String aName, ProducerNode aNode) {
+      nodeParameterValues.put(aName, aNode);
+    };
+
+    public Set getAvailableSubNodes() {
+      return definition.getNodeParameters();
+    };
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributeSet(anAttributes.keySet(), definition.getRequiredAttributes(), definition.getOptionalAttributes());
+    };
+
+    public ProducerNode constructNode() {
+      return new ScriptedProducerNode(definition, parameterValues, nodeParameterValues);
+    };
+
+    public static class factory implements ProducerNodeBuilderFactory {
+      private ScriptedProducerNodeDefinition definition;
+
+      public factory(ScriptedProducerNodeDefinition aDefinition) {
+        definition = aDefinition;
+      }
+
+      public ProducerNodeBuilder makeBuilder() {
+        return new ScriptedProducerNodeBuilder(definition);
+      }
+    }
+  }
+}
diff --git a/source/mir/producer/reader/ProducerConfigExc.java b/source/mir/producer/reader/ProducerConfigExc.java
new file mode 100755 (executable)
index 0000000..15cb7c9
--- /dev/null
@@ -0,0 +1,9 @@
+package mir.producer.reader;
+
+import multex.Exc;
+
+public class ProducerConfigExc extends Exc {
+  public ProducerConfigExc(String aMessage) {
+    super(aMessage);
+  }
+}
diff --git a/source/mir/producer/reader/ProducerConfigFailure.java b/source/mir/producer/reader/ProducerConfigFailure.java
new file mode 100755 (executable)
index 0000000..23ae14d
--- /dev/null
@@ -0,0 +1,14 @@
+
+package mir.producer.reader;
+
+import multex.Failure;
+
+public class ProducerConfigFailure extends Failure {
+  public ProducerConfigFailure(String aMessage, Throwable aCause) {
+    super(aMessage, aCause);
+  }
+
+  public ProducerConfigFailure(Throwable aCause) {
+    super(aCause.getMessage(), aCause);
+  }
+}
diff --git a/source/mir/producer/reader/ProducerConfigReader.java b/source/mir/producer/reader/ProducerConfigReader.java
new file mode 100755 (executable)
index 0000000..1b78791
--- /dev/null
@@ -0,0 +1,702 @@
+package  mir.producer.reader;
+
+import java.io.*;
+import java.util.*;
+import java.lang.System;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.*;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import mir.util.*;
+import mir.config.exceptions.*;
+import mir.producer.*;
+
+//import mir.producer.exceptions.*;
+import mir.misc.Location;
+
+public class ProducerConfigReader {
+  private ProducerNodeBuilderLibrary builderLibrary;
+  private ProducerNodeBuilderLibrary scriptedNodeBuilderLibrary;
+
+  public ProducerConfigReader() {
+    super();
+  };
+
+  public void parseFile(String aFileName, ProducerNodeBuilderLibrary aBuilderLibrary, Map aProducerFactories) throws ConfigFailure {
+    parseFile(aFileName, aBuilderLibrary, aProducerFactories, new Vector());
+
+  }
+
+  public void parseFile(String aFileName, ProducerNodeBuilderLibrary aBuilderLibrary, Map aProducerFactories, List aUsedFiles) throws ConfigFailure {
+    try {
+      builderLibrary = aBuilderLibrary;
+      scriptedNodeBuilderLibrary = new ProducerNodeBuilderLibrary();
+
+      SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+
+      parserFactory.setNamespaceAware(false);
+      parserFactory.setValidating(true);
+
+      ProducerConfigHandler handler = new ProducerConfigHandler(parserFactory, aProducerFactories, aUsedFiles);
+
+      handler.includeFile(aFileName);
+    }
+    catch (Throwable e) {
+      if (e instanceof SAXParseException && ((SAXParseException) e).getException() instanceof ConfigFailure) {
+        throw (ConfigFailure) ((SAXParseException) e).getException();
+      }
+      else {
+        e.printStackTrace();
+        throw new ConfigFailure( e.getMessage() );
+      }
+    }
+  }
+
+  private class ProducerConfigHandler extends DefaultHandler {
+    private Locator locator;
+    private Stack includeFileStack;
+    private SAXParserFactory parserFactory;
+    private SectionsManager manager;
+    private List usedFiles;
+    private InputSource inputSource;
+
+    public ProducerConfigHandler(SAXParserFactory aParserFactory, Map aProducers, List aUsedFiles) {
+      super();
+
+      includeFileStack=new Stack();
+      parserFactory=aParserFactory;
+      includeFileStack = new Stack();
+      manager = new SectionsManager();
+      usedFiles = aUsedFiles;
+
+      manager.pushHandler(new RootSectionHandler(aProducers));
+   }
+
+    public String getLocatorDescription(Locator aLocator) {
+      return aLocator.getPublicId()+" ("+aLocator.getLineNumber()+")";
+    }
+
+    public void setDocumentLocator(Locator aLocator) {
+      locator=aLocator;
+    }
+
+    private void includeFile(String aFileName) throws ConfigFailure, SAXParseException, SAXException {
+      File file;
+      SAXParser parser;
+
+      try {
+        if (!includeFileStack.empty())
+          file = new File(new File((String) includeFileStack.peek()).getParent(), aFileName);
+        else
+          file = new File(aFileName);
+
+        System.err.println("about to include "+file.getCanonicalPath());
+
+        if (includeFileStack.contains(file.getCanonicalPath())) {
+          throw new ConfigFailure("recursive inclusion of file "+file.getCanonicalPath(), getLocatorDescription(locator));
+        }
+
+        usedFiles.add(file);
+
+        parser=parserFactory.newSAXParser();
+
+        inputSource = new InputSource(new FileInputStream(file));
+        inputSource.setPublicId(file.getCanonicalPath());
+
+        includeFileStack.push(file.getCanonicalPath());
+        try {
+          parser.parse(inputSource, this);
+        }
+        finally {
+          includeFileStack.pop();
+        }
+      }
+      catch (ParserConfigurationException e) {
+        throw new ConfigFailure("Internal exception while including \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));
+      }
+      catch (SAXParseException e) {
+        throw e;
+      }
+      catch (ConfigFailure e) {
+        throw e;
+      }
+      catch (FileNotFoundException e) {
+        throw new ConfigFailure("Include file \""+aFileName+"\" not found: "+e.getMessage(), e, getLocatorDescription(locator));
+      }
+      catch (IOException e) {
+        throw new ConfigFailure("unable to open include file \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));
+      }
+    }
+
+    public void startElement(String aUri, String aTag, String aQualifiedName, Attributes anAttributes) throws SAXException {
+      Map attributesMap;
+      int i;
+
+      try {
+        if (aQualifiedName.equals("include")) {
+          String fileName=anAttributes.getValue("file");
+
+          if (fileName==null) {
+            throw new ConfigFailure("include has no file attribute", getLocatorDescription(locator));
+          }
+
+          includeFile(fileName);
+        }
+        else {
+          attributesMap = new HashMap();
+          for (i=0; i<anAttributes.getLength(); i++)
+            attributesMap.put(anAttributes.getQName(i), anAttributes.getValue(i));
+
+          manager.pushHandler( manager.currentHandler().startElement(aQualifiedName, attributesMap) );
+        }
+      }
+      catch (Exception e) {
+        e.printStackTrace(System.out);
+        throw new SAXException(e);
+      }
+    }
+
+    public void endElement(String aUri, String aTag, String aQualifiedName) throws SAXException {
+      try
+      {
+        if (!aQualifiedName.equals("include")) {
+          SectionHandler handler = manager.popHandler();
+
+          handler.finishSection();
+
+          if (!manager.isEmpty()) {
+            manager.currentHandler().endElement(handler);
+          }
+        }
+      }
+      catch (Exception e) {
+        e.printStackTrace(System.out);
+        throw new SAXException(e);
+      }
+    }
+
+    public void characters(char[] aBuffer, int aStart, int anEnd) throws SAXParseException {
+      String text = new String(aBuffer, aStart, anEnd).trim();
+      if ( text.length() > 0) {
+        throw new SAXParseException("Text not allowed", locator, new ConfigFailure("text not allowed", getLocatorDescription(locator)));
+      }
+    }
+
+  }
+  public class SectionsManager {
+    Stack handlerStack;
+
+    public SectionsManager() {
+      handlerStack = new Stack();
+    }
+
+    public void pushHandler(SectionHandler aSectionHandler) {
+      handlerStack.push(aSectionHandler);
+    }
+
+    public SectionHandler popHandler() {
+      return (SectionHandler) handlerStack.pop();
+    }
+
+    public SectionHandler currentHandler() {
+      return (SectionHandler) handlerStack.peek();
+    }
+
+    public boolean isEmpty() {
+      return handlerStack.isEmpty();
+    }
+  }
+
+  public abstract class SectionHandler {
+    public abstract SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc;
+
+    public abstract void endElement(SectionHandler aHandler) throws ProducerConfigExc;
+//    {
+//    }
+
+    public void finishSection() throws ProducerConfigExc {
+    }
+  }
+
+  public class RootSectionHandler extends SectionHandler {
+    private Map producers;
+
+    public RootSectionHandler(Map aProducers) {
+      producers = aProducers;
+    }
+
+    public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
+      if (aTag.equals("producers")) {
+        return new ProducersSectionHandler(producers);
+      }
+      else
+        throw new ProducerConfigExc ("Tag 'producers' expected, tag '"+aTag+"' found");
+    }
+
+    public void endElement(SectionHandler aHandler) {
+    }
+
+    public void finishSection() throws ProducerConfigExc {
+    }
+  }
+
+
+  private final static String   PRODUCER_NAME_ATTRIBUTE = "name";
+  private final static String[] PRODUCER_REQUIRED_ATTRIBUTES = { PRODUCER_NAME_ATTRIBUTE };
+  private final static String[] PRODUCER_OPTIONAL_ATTRIBUTES = { };
+
+  private final static String   NODE_DEFINITION_NAME_ATTRIBUTE = "name";
+  private final static String[] NODE_DEFINITION_REQUIRED_ATTRIBUTES = { NODE_DEFINITION_NAME_ATTRIBUTE };
+  private final static String[] NODE_DEFINITION_OPTIONAL_ATTRIBUTES = {  };
+
+  public class ProducersSectionHandler extends SectionHandler {
+    private Map producers;
+    private String name;
+
+    public ProducersSectionHandler(Map aProducers) {
+      producers = aProducers;
+    }
+
+    public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
+
+      if (aTag.equals("producer")) {
+        ReaderTool.checkAttributes(anAttributes, PRODUCER_REQUIRED_ATTRIBUTES, PRODUCER_OPTIONAL_ATTRIBUTES);
+
+        name = (String) anAttributes.get(PRODUCER_NAME_ATTRIBUTE);
+        ReaderTool.checkValidIdentifier( name );
+
+        if (producers.containsKey(name))
+          throw new ProducerConfigExc("Duplicate producer name: '" + name + "'");
+
+        name = (String) anAttributes.get(PRODUCER_NAME_ATTRIBUTE);
+
+        return new ProducerSectionHandler();
+      }
+      else if (aTag.equals("nodedefinition")) {
+        ReaderTool.checkAttributes(anAttributes, NODE_DEFINITION_REQUIRED_ATTRIBUTES, NODE_DEFINITION_OPTIONAL_ATTRIBUTES);
+
+        name = (String) anAttributes.get(NODE_DEFINITION_NAME_ATTRIBUTE);
+        ReaderTool.checkValidIdentifier( name );
+
+//        if (producers.containsKey(name))
+//          throw new ProducerConfigExc("Duplicate producer name: '" + name + "'");
+
+        name = (String) anAttributes.get(NODE_DEFINITION_NAME_ATTRIBUTE);
+
+        return new NodeDefinitionSectionHandler(name);
+      }
+
+      throw new ProducerConfigExc("Unexpected tag: "+aTag );
+    }
+
+    public void endElement(SectionHandler aHandler) throws ProducerConfigExc {
+      if (aHandler instanceof ProducerSectionHandler) {
+        producers.put(name, ((ProducerSectionHandler) aHandler).getProducerFactory());
+      }
+      else if (aHandler instanceof NodeDefinitionSectionHandler) {
+        scriptedNodeBuilderLibrary.registerFactory(name,
+            new DefaultProducerNodeBuilders.ScriptedProducerNodeBuilder.factory(
+                ((NodeDefinitionSectionHandler) aHandler).getDefinition()));
+      }
+      else throw new ProducerConfigExc("ProducersSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());
+    }
+
+    public void finishSection() throws ProducerConfigExc {
+    }
+  }
+
+  public class ProducerSectionHandler extends SectionHandler {
+    private ProducerFactory producerFactory;
+
+    private ProducerNode body;
+    private Map verbs;
+    private String defaultVerb;
+
+    public SectionHandler startElement(String aTag, Map anAttributes)  throws ProducerConfigExc {
+      if (aTag.equals("verbs")) {
+        if (verbs!=null)
+          throw new ProducerConfigExc("Verbs already processed");
+        if (body!=null)
+          throw new ProducerConfigExc("Verbs should come before body");
+        else
+          return new ProducerVerbsSectionHandler();
+      }
+      else if (aTag.equals("body")) {
+        if (body==null)
+          return new ProducerNodeSectionHandler();
+        else
+          throw new ProducerConfigExc("Body already processed");
+      }
+      throw new ProducerConfigExc("Unexpected tag: '"+aTag+"'");
+    }
+
+    public void endElement(SectionHandler aHandler) throws ProducerConfigExc {
+      if (aHandler instanceof ProducerNodeSectionHandler) {
+        body = ((ProducerNodeSectionHandler) aHandler).getProducerNode();
+      }
+      else if (aHandler instanceof ProducerVerbsSectionHandler)
+      {
+        verbs = ((ProducerVerbsSectionHandler) aHandler).getVerbs();
+        defaultVerb = ((ProducerVerbsSectionHandler) aHandler).getDefaultVerb();
+      }
+      else throw new ProducerConfigExc("ProducerSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());
+    }
+
+    public void finishSection() throws ProducerConfigExc {
+      if (verbs==null)
+        throw new ProducerConfigExc("No verbs defined");
+
+      if (body==null)
+        throw new ProducerConfigExc("No body defined");
+
+      producerFactory = new ScriptedProducerFactory(verbs, body, defaultVerb);
+    }
+
+    public ProducerFactory getProducerFactory() {
+      return producerFactory;
+    }
+  }
+
+  private final static String   PRODUCER_VERB_NAME_ATTRIBUTE = "name";
+  private final static String   PRODUCER_VERB_DEFAULT_ATTRIBUTE = "default";
+  private final static String[] PRODUCER_VERB_REQUIRED_ATTRIBUTES = { PRODUCER_VERB_NAME_ATTRIBUTE };
+  private final static String[] PRODUCER_VERB_OPTIONAL_ATTRIBUTES = { PRODUCER_VERB_DEFAULT_ATTRIBUTE };
+
+  public class ProducerVerbsSectionHandler extends SectionHandler {
+    private Map verbs;
+    private String defaultVerb;
+    private String currentVerb;
+
+    public ProducerVerbsSectionHandler() {
+      verbs = new HashMap();
+      defaultVerb = null;
+    }
+
+    public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
+      if (aTag.equals("verb")) {
+        ReaderTool.checkAttributes(anAttributes, PRODUCER_VERB_REQUIRED_ATTRIBUTES, PRODUCER_VERB_OPTIONAL_ATTRIBUTES);
+        currentVerb = (String) anAttributes.get( PRODUCER_VERB_NAME_ATTRIBUTE );
+
+        ReaderTool.checkValidIdentifier( currentVerb );
+
+        if (verbs.containsKey(currentVerb))
+          throw new ProducerConfigExc( "Duplicate definition of verb '" + currentVerb + "'" );
+
+        if (anAttributes.containsKey(PRODUCER_VERB_DEFAULT_ATTRIBUTE)) {
+          if (defaultVerb!=null)
+            throw new ProducerConfigExc( "Default verb already declared" );
+
+          defaultVerb = currentVerb;
+        }
+
+        return new ProducerNodeSectionHandler();
+      }
+      else throw new ProducerConfigExc("Only 'verb' tags allowed here, '" + aTag + "' encountered.");
+    }
+
+    public void endElement(SectionHandler aHandler) {
+      verbs.put(currentVerb, ((ProducerNodeSectionHandler) aHandler).getProducerNode());
+    }
+
+    public void finishSection() {
+    }
+
+    public String getDefaultVerb() {
+      return defaultVerb;
+    }
+
+    public Map getVerbs() {
+      return verbs;
+    }
+  }
+
+  public class EmptySectionHandler extends SectionHandler {
+    public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
+      throw new ProducerConfigExc("No tags are allowed here");
+    }
+
+    public void endElement(SectionHandler aHandler) {
+    }
+
+  }
+
+  public class MultiProducerNodeSectionHandler extends SectionHandler {
+    private Map nodeParameters;
+    private Set validNodeParameters;
+    private String currentNodeParameter;
+    private String scriptedNodeName;
+    private Set allowedNodeParameterReferences;
+
+    public MultiProducerNodeSectionHandler(String aScriptedNodeName, Set anAllowedNodeParameterReferences, Set aValidNodeParameters) {
+      allowedNodeParameterReferences = anAllowedNodeParameterReferences;
+      scriptedNodeName = aScriptedNodeName;
+      validNodeParameters = aValidNodeParameters;
+      nodeParameters = new HashMap();
+    }
+    public MultiProducerNodeSectionHandler(Set aValidNodeParameters) {
+      this("", new HashSet(), aValidNodeParameters);
+    }
+
+    public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
+      if (!validNodeParameters.contains(aTag))
+        throw new ProducerConfigExc("Invalid node parameter: '" + aTag + "'");
+      else if (nodeParameters.containsKey(aTag))
+        throw new ProducerConfigExc("Node parameter: '" + aTag + "' already specified");
+      else if (anAttributes.size()>0)
+        throw new ProducerConfigExc("No parameters are allowed here");
+
+      currentNodeParameter = aTag;
+
+      return new ProducerNodeSectionHandler(scriptedNodeName, validNodeParameters);
+    }
+
+    public void endElement(SectionHandler aHandler) throws ProducerConfigExc  {
+      if (aHandler instanceof ProducerNodeSectionHandler) {
+        nodeParameters.put(currentNodeParameter, ((ProducerNodeSectionHandler) aHandler).getProducerNode());
+      }
+      else {
+        throw new ProducerConfigExc("Internal error: unknown section handler '" + aHandler.getClass().getName() + "'" );
+      }
+    }
+
+    public Map getNodeParameters() {
+      return nodeParameters;
+    }
+  }
+
+  public class ProducerNodeSectionHandler extends SectionHandler {
+    private CompositeProducerNode producerNode;
+    private ProducerNodeBuilder currentBuilder;
+    private String scriptedNodeName;
+    private Set allowedNodeParameterReferences;
+
+    public ProducerNodeSectionHandler(String aScriptedNodeName, Set anAllowedNodeParameterReferences) {
+      producerNode = new CompositeProducerNode();
+      scriptedNodeName = aScriptedNodeName;
+      allowedNodeParameterReferences = anAllowedNodeParameterReferences;
+    }
+
+    public ProducerNodeSectionHandler() {
+      this("", new HashSet());
+    }
+
+    public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
+      if (allowedNodeParameterReferences.contains((aTag))) {
+        if (!anAttributes.isEmpty()) {
+          throw new ProducerConfigExc( "No attributes allowed" );
+        }
+
+        currentBuilder = new DefaultProducerNodeBuilders.ScriptedProducerParameterNodeBuilder(scriptedNodeName, aTag);
+//        producerNode.addSubNode(
+//        new ScriptedProducerNodeDefinition.NodeParameterProducerNode(scriptedNodeName, aTag));
+        return new EmptySectionHandler();
+      }
+      else if (scriptedNodeBuilderLibrary.hasBuilderForName(aTag) || builderLibrary.hasBuilderForName((aTag))) {
+
+        if (scriptedNodeBuilderLibrary.hasBuilderForName(aTag))
+          currentBuilder = scriptedNodeBuilderLibrary.constructBuilder(aTag);
+        else
+          currentBuilder = builderLibrary.constructBuilder(aTag);
+
+        currentBuilder.setAttributes(anAttributes);
+        if (currentBuilder.getAvailableSubNodes().isEmpty())  {
+          return new EmptySectionHandler();
+        }
+        if (currentBuilder.getAvailableSubNodes().size()>1)
+          return new MultiProducerNodeSectionHandler(scriptedNodeName, allowedNodeParameterReferences, currentBuilder.getAvailableSubNodes());
+        else if (currentBuilder.getAvailableSubNodes().size()<1)
+          return new EmptySectionHandler();
+        else {
+          return new ProducerNodeSectionHandler(scriptedNodeName, allowedNodeParameterReferences);
+        }
+      }
+      else
+        throw new ProducerConfigExc("Unknown producer node tag: '" + aTag + "'");
+    }
+
+    public void endElement(SectionHandler aHandler) throws ProducerConfigExc  {
+      if (aHandler instanceof ProducerNodeSectionHandler) {
+        currentBuilder.setSubNode((String) (currentBuilder.getAvailableSubNodes().iterator().next()),
+                    ((ProducerNodeSectionHandler) aHandler).getProducerNode());
+      }
+      else if (aHandler instanceof MultiProducerNodeSectionHandler) {
+        Iterator i;
+        Map nodeParameters;
+        Map.Entry entry;
+
+        nodeParameters = ((MultiProducerNodeSectionHandler) aHandler).getNodeParameters();
+        i = nodeParameters.entrySet().iterator();
+        while (i.hasNext()) {
+          entry = (Map.Entry) i.next();
+          currentBuilder.setSubNode((String) entry.getKey(), (ProducerNode) entry.getValue());
+        }
+      }
+      else if (aHandler instanceof EmptySectionHandler) {
+        // deliberately empty: nothing expected, so nothing to process
+      }
+      else {
+        throw new ProducerConfigExc("Internal error: unknown section handler '" + aHandler.getClass().getName() + "'" );
+      }
+
+      producerNode.addSubNode(currentBuilder.constructNode());
+      currentBuilder = null;
+    }
+
+    public ProducerNode getProducerNode() {
+      if (producerNode.getNrSubNodes()==1) {
+        return producerNode.getSubNode(0);
+      }
+      else {
+        return producerNode;
+      }
+    }
+  }
+
+  public class NodeDefinitionSectionHandler extends SectionHandler {
+    private ScriptedProducerNodeDefinition nodeDefinition;
+    private ProducerNode body;
+    private Map stringParameters;
+    private Map nodeParameters;
+    private String name;
+
+    public NodeDefinitionSectionHandler(String aName) {
+      body = null;
+      nodeParameters = null;
+      stringParameters = null;
+      name = aName;
+    }
+
+    public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
+      if (aTag.equals("parameters")) {
+        if (!anAttributes.isEmpty()) {
+          throw new ProducerConfigExc( "No attributes allowed for tag 'parameters'" );
+        }
+        if (nodeParameters!=null) {
+          throw new ProducerConfigExc( "Parameters have already been declared" );
+        }
+        if (body!=null) {
+          throw new ProducerConfigExc( "Parameters should come before definition" );
+        }
+
+        return new NodeDefinitionParametersSectionHandler();
+      }
+      else if (aTag.equals("definition")) {
+        return new ProducerNodeSectionHandler(name, nodeParameters.keySet());
+      }
+      else throw new ProducerConfigExc("Only 'definition' or 'parameters' tags allowed here, '" + aTag + "' encountered.");
+    }
+
+    public void endElement(SectionHandler aHandler) {
+      if (aHandler instanceof NodeDefinitionParametersSectionHandler) {
+        stringParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getStringParameters();
+        nodeParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getNodeParameters();
+      }
+      else if (aHandler instanceof ProducerNodeSectionHandler) {
+        body = ((ProducerNodeSectionHandler) aHandler).getProducerNode();
+      }
+    }
+
+    public void finishSection() throws ProducerConfigExc {
+      Iterator i;
+      if (body == null)
+        throw new ProducerConfigExc( "Definition missing" );
+
+      nodeDefinition = new ScriptedProducerNodeDefinition(name);
+
+      nodeDefinition.setBody(body);
+
+      i = nodeParameters.keySet().iterator();
+      while (i.hasNext()) {
+        nodeDefinition.addNodeParameter((String) i.next());
+      }
+
+      i = stringParameters.entrySet().iterator();
+      while (i.hasNext()) {
+        Map.Entry entry = (Map.Entry) i.next();
+        nodeDefinition.addParameter((String) entry.getKey(), (String) entry.getValue());
+      }
+    }
+
+    public ScriptedProducerNodeDefinition getDefinition() {
+      return nodeDefinition;
+    }
+  }
+
+  private final static String   NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE = "name";
+  private final static String   NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE = "defaultvalue";
+  private final static String[] NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES = { NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE };
+  private final static String[] NODE_DEFINITION_PARAMETER_OPTIONAL_ATTRIBUTES = { NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE };
+  private final static String[] NODE_DEFINITION_NODE_PARAMETER_OPTIONAL_ATTRIBUTES = { };
+
+  public class NodeDefinitionParametersSectionHandler extends SectionHandler {
+    private Map nodeParameters;
+    private Map stringParameters;
+
+    public NodeDefinitionParametersSectionHandler() {
+      nodeParameters = new HashMap();
+      stringParameters = new HashMap();
+    }
+
+    public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
+      String parameterName;
+      String defaultValue;
+
+      if (aTag.equals("node")) {
+        ReaderTool.checkAttributes(anAttributes, NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES, NODE_DEFINITION_NODE_PARAMETER_OPTIONAL_ATTRIBUTES);
+        parameterName = (String) anAttributes.get( NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE );
+
+        if (nodeParameters.containsKey(parameterName))
+          throw new ProducerConfigExc("Duplicate parameter name: '" + parameterName + "'");
+
+        ReaderTool.checkValidIdentifier( parameterName );
+
+        nodeParameters.put(parameterName, parameterName);
+
+        return new EmptySectionHandler();
+      }
+      else if (aTag.equals("string")) {
+        ReaderTool.checkAttributes(anAttributes, NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES, NODE_DEFINITION_PARAMETER_OPTIONAL_ATTRIBUTES);
+        parameterName = (String) anAttributes.get( NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE );
+
+        if (stringParameters.containsKey(parameterName))
+          throw new ProducerConfigExc("Duplicate parameter name: '" + parameterName + "'");
+
+        ReaderTool.checkValidIdentifier( parameterName );
+
+        defaultValue = (String) anAttributes.get( NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE );
+
+        stringParameters.put(parameterName, defaultValue);
+
+        return new EmptySectionHandler();
+      }
+      else throw new ProducerConfigExc("Only 'string' and 'node' tags allowed here, '" + aTag + "' encountered.");
+
+    }
+
+    public void endElement(SectionHandler aHandler) {
+    }
+
+    public void finishSection() {
+    }
+
+    public Map getNodeParameters() {
+      return nodeParameters;
+    }
+
+    public Map getStringParameters() {
+      return stringParameters;
+    }
+  }
+}
+
+
+/*
+ /                 (expecting producers)
+ producers/        (expecting nodedefinition, producer)
+   nodedefinition  (expecting parameters, definition)
+     parameters    (expecting parameter declarations)
+     definition    (expecting nodes, subnodes)
+*/
+
diff --git a/source/mir/producer/reader/ProducerNodeBuilder.java b/source/mir/producer/reader/ProducerNodeBuilder.java
new file mode 100755 (executable)
index 0000000..c298761
--- /dev/null
@@ -0,0 +1,34 @@
+package mir.producer.reader;
+
+import java.util.*;
+import mir.producer.*;
+
+public interface ProducerNodeBuilder  {
+  public void setAttributes(Map anAttributes) throws ProducerConfigExc;
+  public void setSubNode(String aName, ProducerNode aNode) throws ProducerConfigExc;
+  public Set getAvailableSubNodes() throws ProducerConfigExc;
+  public ProducerNode constructNode() throws ProducerConfigExc;
+
+  public interface ProducerNodeBuilderFactory {
+    public ProducerNodeBuilder makeBuilder() throws ProducerConfigExc;
+  }
+
+  public class DefaultProducerNodeBuilderFactory implements ProducerNodeBuilderFactory {
+    private Class producerNodeBuilderClass;
+
+    public DefaultProducerNodeBuilderFactory(Class aProducerNodeBuilderClass) {
+      producerNodeBuilderClass = aProducerNodeBuilderClass;
+    }
+
+    public ProducerNodeBuilder makeBuilder() throws ProducerConfigExc{
+      try {
+        return (ProducerNodeBuilder) producerNodeBuilderClass.newInstance();
+      }
+      catch (Throwable t) {
+        throw new ProducerConfigFailure(t);
+      }
+    }
+  }
+}
+
+
diff --git a/source/mir/producer/reader/ProducerNodeBuilderLibrary.java b/source/mir/producer/reader/ProducerNodeBuilderLibrary.java
new file mode 100755 (executable)
index 0000000..4a7be95
--- /dev/null
@@ -0,0 +1,31 @@
+package mir.producer.reader;
+
+import java.util.*;
+import mir.producer.*;
+
+public class ProducerNodeBuilderLibrary {
+  private Map nodeBuilders;
+
+  public ProducerNodeBuilderLibrary() {
+    nodeBuilders = new HashMap();
+  }
+
+  public void registerBuilder(String aName, Class aProducerNodeBuilderClass) {
+    registerFactory(aName, new ProducerNodeBuilder.DefaultProducerNodeBuilderFactory( aProducerNodeBuilderClass ));
+  }
+
+  public void registerFactory(String aName, ProducerNodeBuilder.ProducerNodeBuilderFactory aFactory) {
+    nodeBuilders.put(aName, aFactory);
+  }
+
+  public boolean hasBuilderForName(String aName) {
+    return nodeBuilders.containsKey(aName);
+  }
+
+  public ProducerNodeBuilder constructBuilder(String aName) throws ProducerConfigExc {
+    if (hasBuilderForName(aName))
+      return ((ProducerNodeBuilder.ProducerNodeBuilderFactory) nodeBuilders.get(aName)).makeBuilder();
+    else
+      throw new ProducerConfigExc("ProducerNodeBuilder: no builder with name '" + aName + "' found.");
+  }
+}
diff --git a/source/mir/producer/reader/ReaderTool.java b/source/mir/producer/reader/ReaderTool.java
new file mode 100755 (executable)
index 0000000..376196f
--- /dev/null
@@ -0,0 +1,63 @@
+package mir.producer.reader;
+
+import java.util.*;
+
+public class ReaderTool {
+
+  public static void checkValidIdentifier(String anIdentifier) throws ProducerConfigExc {
+  }
+
+  public static String getStringAttributeWithDefault(Map anAttributes, String aKey, String aDefault) {
+    if (anAttributes.containsKey(aKey))
+      return (String) anAttributes.get(aKey);
+    else
+      return aDefault;
+  }
+
+  public static void checkIntegerAttribute(Map anAttributes, String aKey) throws ProducerConfigExc {
+    try {
+      Integer.parseInt((String) anAttributes.get(aKey));
+    }
+    catch (Throwable t) {
+      throw new ProducerConfigExc("attribute '"+aKey+"' is not an integer" );
+    }
+  }
+
+  public static int getIntegerAttributeWithDefault(Map anAttributes, String aKey, int aDefault) throws ProducerConfigExc  {
+    String value;
+
+    if (anAttributes.containsKey(aKey)) {
+      checkIntegerAttribute(anAttributes, aKey);
+      return Integer.parseInt((String) anAttributes.get(aKey));
+    }
+    else
+      return aDefault;
+  }
+
+  public static void checkAttributes(Map anAttributes, String[] aRequiredAttributes, String[] anOptionalAttributes)  throws ProducerConfigExc {
+    checkAttributeSet(anAttributes.keySet(),
+       new HashSet(Arrays.asList(aRequiredAttributes)),
+       new HashSet(Arrays.asList(anOptionalAttributes)));
+  }
+
+  public static void checkAttributeSet(Set aSet, Set aRequiredElements, Set anOptionalElements) throws ProducerConfigExc{
+    Iterator i;
+
+    i = aSet.iterator();
+    while (i.hasNext()) {
+      Object item = i.next();
+
+      if (!(aRequiredElements.contains(item) || anOptionalElements.contains(item)))
+        throw new ProducerConfigExc("unknown attribute '" + item + "'" );
+    }
+
+    i = aRequiredElements.iterator();
+    while (i.hasNext()) {
+      Object item = i.next();
+
+      if (!(aSet.contains(item)))
+        throw new ProducerConfigExc("missing required attribute '" + item + "'" );
+    }
+
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/reader/ScriptedProducerFactory.java b/source/mir/producer/reader/ScriptedProducerFactory.java
new file mode 100755 (executable)
index 0000000..985686e
--- /dev/null
@@ -0,0 +1,43 @@
+package mir.producer.reader;
+
+import java.util.*;
+import mir.producer.*;
+
+public class ScriptedProducerFactory implements ProducerFactory {
+  private Map verbs;
+  private ProducerNode body;
+  private String defaultVerb;
+
+  public ScriptedProducerFactory(Map aVerbs, ProducerNode aBody, String aDefaultVerb) {
+    verbs = aVerbs;
+    body = aBody;
+    defaultVerb = aDefaultVerb;
+  }
+
+  public ScriptedProducerFactory(Map aVerbs, ProducerNode aBody) {
+    this(aVerbs, aBody, null);
+  }
+
+  public Producer makeProducer(String aVerb, Map aStartingValues) throws ProducerFailure, ProducerExc {
+    CompositeProducerNode rootNode;
+    ProducerNode verbNode;
+
+    if (verbs.containsKey(aVerb)) {
+      verbNode = (ProducerNode) verbs.get(aVerb);
+    }
+    else if (defaultVerb!=null && verbs.containsKey(defaultVerb)) {
+      verbNode = (ProducerNode) verbs.get(defaultVerb);
+    }
+    else throw new ProducerExc("Undefined verb: " + aVerb);
+
+    rootNode = new CompositeProducerNode();
+    rootNode.addSubNode(verbNode);
+    rootNode.addSubNode(body);
+
+    return new NodedProducer(rootNode, aVerb, aStartingValues);
+  };
+
+  public Iterator verbs() {
+    return verbs.keySet().iterator();
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/reader/ScriptedProducerNode.java b/source/mir/producer/reader/ScriptedProducerNode.java
new file mode 100755 (executable)
index 0000000..08925cb
--- /dev/null
@@ -0,0 +1,56 @@
+package mir.producer.reader;
+
+import java.util.*;
+import java.io.*;
+import mir.producer.*;
+import mir.util.*;
+
+public class ScriptedProducerNode implements ProducerNode {
+  private ScriptedProducerNodeDefinition definition;
+  private Map parameterValues;
+  private Map nodeParameterValues;
+
+  public ScriptedProducerNode(ScriptedProducerNodeDefinition aDefinition, Map aParameterValues, Map aNodeParameterValues) {
+    definition = aDefinition;
+    parameterValues = new HashMap();
+    parameterValues.putAll(aParameterValues);
+    nodeParameterValues = new HashMap();
+    nodeParameterValues.putAll(aNodeParameterValues);
+  }
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+
+  public void produce(Map aValues, String aVerb, PrintWriter aLogger) throws ProducerFailure, ProducerExc {
+    try {
+      Map oldValues = ScriptedProducerNodeTool.saveMapValues(aValues, definition.getParameters().keySet());
+      try {
+        Iterator i = parameterValues.entrySet().iterator();
+
+        while (i.hasNext()) {
+          Map.Entry entry = (Map.Entry) i.next();
+
+          if (entry.getValue() instanceof String) {
+            aValues.put(entry.getKey(), ParameterExpander.expandExpression(aValues, (String) entry.getValue()));
+          }
+        }
+
+        ScriptedProducerNodeTool.pushNodeParameterValues(aValues, definition.getName(), nodeParameterValues);
+        try {
+          definition.getBody().produce(aValues, aVerb, aLogger);
+        }
+        finally {
+          ScriptedProducerNodeTool.popNodeParameterValues(aValues, definition.getName());
+        }
+      }
+      finally {
+        ScriptedProducerNodeTool.restoreMapValues(aValues, definition.getParameters().keySet(), oldValues);
+      }
+    }
+    catch (Exception e) {
+      throw new ProducerFailure(e);
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/source/mir/producer/reader/ScriptedProducerNodeDefinition.java b/source/mir/producer/reader/ScriptedProducerNodeDefinition.java
new file mode 100755 (executable)
index 0000000..e12b8d5
--- /dev/null
@@ -0,0 +1,100 @@
+package mir.producer.reader;
+
+import java.util.*;
+import java.io.*;
+import mir.producer.*;
+
+public class ScriptedProducerNodeDefinition {
+  private Map parameters;               // name -> default value
+  private Set nodeParameters;
+  private ProducerNode body;
+  private String name;
+
+  public static String SCRIPTED_PRODUCERNODE_RUNTIMEDATA_KEY = "$SCRIPTRUNTIMEDATA";
+  public static String SCRIPTED_PRODUCERNODE_RUNTIMESTACK_KEY = "stack";
+
+  public ScriptedProducerNodeDefinition(String aName) {
+    name = aName;
+    parameters = new HashMap();
+    nodeParameters = new HashSet();
+    body = new CompositeProducerNode();
+  }
+
+  public void addParameter(String aName, String aDefaultValue) {
+    parameters.put(aName, aDefaultValue);
+  }
+
+  public void addNodeParameter(String aName) {
+    nodeParameters.add(aName);
+  }
+
+  public void setBody(ProducerNode aBody) {
+    body = aBody;
+  }
+
+  protected Map getParameters() {
+    return parameters;
+  }
+
+  protected Set getNodeParameters() {
+    return nodeParameters;
+  }
+
+  protected ProducerNode getBody() {
+    return body;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public Set getRequiredAttributes() {
+    return getAttributesSelection(true);
+  }
+
+  public Set getOptionalAttributes() {
+    return getAttributesSelection(false);
+  }
+
+  public Set getAttributesSelection(boolean aRequired) {
+    Set result = new HashSet();
+    Iterator i = parameters.entrySet().iterator();
+
+    while (i.hasNext()) {
+      Map.Entry entry = (Map.Entry) i.next();
+
+      if ((entry.getValue() == null) == aRequired ) {
+        result.add(entry.getKey());
+      }
+    }
+
+    return result;
+  }
+
+
+  protected static class NodeParameterProducerNode implements ProducerNode {
+    private String parameterName;
+    private String definitionName;
+
+    public NodeParameterProducerNode(String aDefinitionName, String aParameterName) {
+      definitionName = aDefinitionName;
+      parameterName = aParameterName;
+    }
+
+    public void produce(Map aValues, String aVerb, PrintWriter aLogger) throws ProducerExc, ProducerFailure {
+      ProducerNode producerNode;
+
+      Map runTimeData = (Map) ((Map) aValues.get(SCRIPTED_PRODUCERNODE_RUNTIMEDATA_KEY)).get(definitionName);
+      Map parameters = (Map) ((Stack) runTimeData.get( SCRIPTED_PRODUCERNODE_RUNTIMESTACK_KEY )).peek();
+
+      producerNode = (ProducerNode) parameters.get(parameterName);
+
+      if (producerNode != null)
+        producerNode.produce(aValues, aVerb, aLogger);
+    }
+
+    public Set buildVerbSet() {
+      return new HashSet();
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/reader/ScriptedProducerNodeTool.java b/source/mir/producer/reader/ScriptedProducerNodeTool.java
new file mode 100755 (executable)
index 0000000..76c7fa5
--- /dev/null
@@ -0,0 +1,56 @@
+package mir.producer.reader;
+
+import java.util.*;
+
+public class ScriptedProducerNodeTool {
+
+  public static Object getOrMakeMapValueForKey(Map aMap, Object aKey, Object aDefaultValue) {
+    if (aMap.containsKey(aKey))
+      return aMap.get(aKey);
+    else {
+      aMap.put(aKey, aDefaultValue);
+      return aDefaultValue;
+    }
+  }
+
+  public static Stack getRunTimeStack(Map aProductionMap, String aDefinitionName) {
+    Map runtimeData = (Map) getOrMakeMapValueForKey(aProductionMap, ScriptedProducerNodeDefinition.SCRIPTED_PRODUCERNODE_RUNTIMEDATA_KEY, new HashMap());
+    runtimeData = (Map) getOrMakeMapValueForKey(runtimeData, aDefinitionName, new HashMap());
+    return (Stack) getOrMakeMapValueForKey(runtimeData, ScriptedProducerNodeDefinition.SCRIPTED_PRODUCERNODE_RUNTIMESTACK_KEY, new Stack());
+  }
+
+  public static void pushNodeParameterValues(Map aProductionMap, String aDefinitionName, Map aNodeParameterValues) {
+    Stack runtimeStack = getRunTimeStack(aProductionMap, aDefinitionName);
+    runtimeStack.push(aNodeParameterValues);
+  }
+
+  public static void popNodeParameterValues(Map aProductionMap, String aDefinitionName) {
+    Stack runtimeStack = getRunTimeStack(aProductionMap, aDefinitionName);
+    runtimeStack.pop();
+  }
+
+  public static Map saveMapValues(Map aMap, Set aKeys) {
+    Map result = new HashMap();
+    Iterator i = aKeys.iterator();
+
+    while (i.hasNext()) {
+      Object key = i.next();
+      if (aMap.containsKey(key))
+        result.put(key, aMap.get(key));
+    }
+
+    return result;
+  }
+
+  public static void restoreMapValues(Map aMap, Set aKeys, Map aSavedValues) {
+    Iterator i = aKeys.iterator();
+
+    while (i.hasNext()) {
+      Object key = i.next();
+      if (aSavedValues.containsKey(key))
+        aMap.put(key, aSavedValues.get(key));
+      else
+        aMap.remove(key);
+    }
+  }
+}
\ No newline at end of file
index c3a6e93..d82264c 100755 (executable)
@@ -27,10 +27,13 @@ import  mir.misc.*;
  * Treiber, Host, User und Passwort, ueber den der Zugriff auf die
  * Datenbank erfolgt.
  *
- * @version $Revision: 1.21 $ $Date: 2002/08/04 23:38:22 $
+ * @version $Revision: 1.22 $ $Date: 2002/08/25 19:00:09 $
  * @author $Author: mh $
  *
  * $Log: Database.java,v $
+ * Revision 1.22  2002/08/25 19:00:09  mh
+ * merge of localization branch into HEAD. mh and zap
+ *
  * Revision 1.21  2002/08/04 23:38:22  mh
  * fix up the webdb_create update stuff
  *
@@ -592,6 +595,7 @@ public class Database implements StorageObject {
                        int size = metadataFields.size();
                        for (int i = 0; i < size; i++) {
                                // alle durchlaufen bis nix mehr da
+
                                theType = metadataTypes[i];
                                if (theType == java.sql.Types.LONGVARBINARY) {
                                        InputStreamReader is = (InputStreamReader)rs.getCharacterStream(i + 1);
@@ -1061,7 +1065,9 @@ public class Database implements StorageObject {
                throws SQLException,StorageObjectException
        {
                long  startTime = System.currentTimeMillis();
-               String sql = "SELECT count(*) FROM "+ theTable + " where " + where;
+               String sql = "SELECT Count(*) FROM "+ theTable;
+               if (where != null && !(where.length() == 0))
+                 sql = sql + " where " + where;
                Connection con = null;
                Statement stmt = null;
                int result = 0;
diff --git a/source/mir/util/CachingRewindableIterator.java b/source/mir/util/CachingRewindableIterator.java
new file mode 100755 (executable)
index 0000000..77be4ba
--- /dev/null
@@ -0,0 +1,45 @@
+package mir.util;
+
+import java.util.*;
+
+import java.util.*;
+import mir.storage.*;
+import mir.util.*;
+import mir.entity.*;
+
+public class CachingRewindableIterator implements RewindableIterator {
+  private Iterator master;
+  private List cachedItems;
+  private int iterationPosition;
+
+  public CachingRewindableIterator(Iterator anIterator) {
+    master = anIterator;
+    cachedItems = new Vector();
+    iterationPosition = 0;
+  }
+
+  public boolean hasNext() {
+    return iterationPosition<cachedItems.size() || master.hasNext();
+  }
+
+  public Object next() {
+    Object result;
+
+    if (iterationPosition>=cachedItems.size()) {
+      cachedItems.add(master.next());
+    }
+
+    result = cachedItems.get(iterationPosition);
+    iterationPosition++;
+
+    return result;
+  }
+
+  public void remove() {
+    throw new UnsupportedOperationException();
+  }
+
+  public void rewind() {
+    iterationPosition=0;
+  };
+}
\ No newline at end of file
diff --git a/source/mir/util/DateToMapAdapter.java b/source/mir/util/DateToMapAdapter.java
new file mode 100755 (executable)
index 0000000..cd77de1
--- /dev/null
@@ -0,0 +1,37 @@
+package mir.util;
+
+import java.util.*;
+import java.text.*;
+
+import mir.misc.*;
+
+public class DateToMapAdapter extends AbstractMap {
+  Date date;
+
+  public DateToMapAdapter(Date aDate) {
+    date = aDate;
+  }
+
+  public Object get(Object aKey) {
+    if (aKey instanceof String) {
+      try {
+        // ML: quick fix to allow for the dc encoding now...
+        if (((String) aKey).equals("dc")) {
+          GregorianCalendar calendar = new GregorianCalendar();
+          calendar.setTime(date);
+          return StringUtil.date2w3DateTime(calendar);
+        }
+        else
+          return new SimpleDateFormat((String) aKey).format(date);
+      }
+      catch (Throwable t) {
+        throw new RuntimeException( "Can't format date with format " + (String) aKey + ": " + t.getMessage());
+      }
+    }
+    else return null;
+  }
+
+  public Set entrySet() {
+    return new HashSet();
+  }
+}
\ No newline at end of file
diff --git a/source/mir/util/FileMonitor.java b/source/mir/util/FileMonitor.java
new file mode 100755 (executable)
index 0000000..a35dc67
--- /dev/null
@@ -0,0 +1,35 @@
+package mir.util;
+
+import java.util.*;
+import java.io.*;
+
+public class FileMonitor {
+  private Map files;
+
+  public FileMonitor() {
+    files = new HashMap();
+  }
+
+  public void addFile(File aFile) {
+    files.put(aFile, new Long(aFile.lastModified()));
+  }
+
+  public void clear() {
+    files.clear();
+  }
+
+  public boolean hasChanged() {
+    Iterator i = files.entrySet().iterator();
+
+    while (i.hasNext()) {
+      Map.Entry entry = (Map.Entry) i.next();
+      File file = (File) entry.getKey();
+      Long lastModified = (Long) entry.getValue();
+
+      if (lastModified.longValue()!=file.lastModified())
+        return true;
+    }
+
+    return false;
+  }
+}
\ No newline at end of file
diff --git a/source/mir/util/GeneratorHTMLFunctions.java b/source/mir/util/GeneratorHTMLFunctions.java
new file mode 100755 (executable)
index 0000000..e46db00
--- /dev/null
@@ -0,0 +1,44 @@
+package mir.util;
+
+import java.util.*;
+import java.net.*;
+
+import mir.misc.*;
+import mir.generator.*;
+
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2002</p>
+ * <p>Company: </p>
+ * @author unascribed
+ * @version 1.0
+ */
+
+public class GeneratorHTMLFunctions {
+  private GeneratorHTMLFunctions() {}
+
+  public static class encodeURIGeneratorFunction implements Generator.GeneratorFunction {
+    public Object perform(List aParameters) throws GeneratorExc {
+      if (aParameters.size()!=1)
+        throw new GeneratorExc("encodeHTMLGeneratorFunction: only 1 parameter expected");
+      if (!(aParameters.get(0) instanceof String))
+        throw new GeneratorExc("encodeHTMLGeneratorFunction: parameter must be a string");
+
+      return URLEncoder.encode((String) aParameters.get(0));
+    };
+  }
+
+  public static class encodeHTMLGeneratorFunction implements Generator.GeneratorFunction {
+    public Object perform(List aParameters) throws GeneratorExc {
+      if (aParameters.size()!=1)
+        throw new GeneratorExc("encodeHTMLGeneratorFunction: only 1 parameter expected");
+      if (!(aParameters.get(0) instanceof String))
+        throw new GeneratorExc("encodeHTMLGeneratorFunction: parameter must be a string");
+
+      // YUCK! -mh
+      //return StringUtil.encodeHtml((String) aParameters.get(0));
+      return (String) aParameters.get(0);
+    };
+  }
+}
diff --git a/source/mir/util/NullWriter.java b/source/mir/util/NullWriter.java
new file mode 100755 (executable)
index 0000000..8bb9027
--- /dev/null
@@ -0,0 +1,18 @@
+package mir.util;
+
+import java.io.*;
+
+public class NullWriter extends Writer {
+
+  public NullWriter() {
+  }
+
+  public void close() {
+  }
+
+  public void flush() {
+  }
+
+  public void write(char[] cbuf, int off, int len) {
+  }
+}
\ No newline at end of file
diff --git a/source/mir/util/ParameterExpander.java b/source/mir/util/ParameterExpander.java
new file mode 100755 (executable)
index 0000000..8db5736
--- /dev/null
@@ -0,0 +1,831 @@
+package  mir.util;
+
+import multex.Failure;
+import multex.Exc;
+
+import java.util.*;
+
+public class ParameterExpander {
+  final static String NODE_SEPARATOR = ".";
+  final static char STRING_ESCAPE_CHARACTER = '\\';
+
+  public static List splitString(String aString, String aSeparator) {
+    List result= new Vector();
+    int previousPosition = 0;
+    int position;
+    int endOfNamePosition;
+
+    while ((position = aString.indexOf(aSeparator, previousPosition))>=0) {
+      result.add(aString.substring(previousPosition, position));
+      previousPosition = position + aSeparator.length();
+    }
+
+    result.add(aString.substring(previousPosition, aString.length()));
+
+    return result;
+  }
+
+  private static Object findNode(String aKey, Map aMap, List aParts, boolean aMakeIfNotPresent) throws Exception {
+    Iterator i;
+    String location = "";
+    Object node = aMap;
+    Object newNode;
+
+    i = aParts.iterator();
+
+    while (i.hasNext()) {
+      String part = (String) i.next();
+
+      if (!(node instanceof Map)) {
+        throw new Exception( "Can't expand key " + aKey + ": " + location + " is not a map" );
+      }
+
+      if (location.length()>0) {
+        location=location + NODE_SEPARATOR;
+      }
+      location = location + part;
+
+      newNode = ((Map) node).get(part);
+
+      if (newNode == null)
+        if (aMakeIfNotPresent) {
+          newNode = new HashMap();
+          ((Map) node).put(part, newNode);
+        }
+        else
+          throw new ParameterExpanderExc( "Can't expand key {1}: {2} does not exist", new Object[]{aKey,location} );
+
+      node = newNode;
+    }
+
+    return node;
+  }
+
+  public static Object findValueForKey(Map aMap, String aKey) throws Exception {
+    Object node;
+    List parts = splitString(aKey, NODE_SEPARATOR);
+
+    node = findNode(aKey, aMap, parts, false);
+
+    return node;
+  }
+
+  public static String findStringForKey(Map aMap, String aKey) throws Exception {
+    Object expandedValue = findValueForKey(aMap, aKey);
+
+    if (!(expandedValue instanceof String))
+      throw new ParameterExpanderExc( "Value of key is not a string but a {1}", new Object[]{expandedValue.getClass().getName()} );
+
+    return (String) expandedValue;
+  }
+
+  public static void setValueForKey(Map aMap, String aKey, Object aValue) throws Exception {
+    List parts = splitString(aKey, NODE_SEPARATOR);
+
+    String key = (String) parts.get(parts.size()-1);
+    parts.remove(parts.size()-1);
+
+    Object node=findNode(aKey, aMap, parts, true);
+
+    if (node instanceof Map) {
+      ((Map) node).put(key, aValue);
+    }
+    else
+      throw new ParameterExpanderExc( "Can't set key {1}: not inside a Map", new Object[]{aKey} );
+  }
+
+  public static String expandExpression(Map aMap, String anExpression) throws Exception {
+    int previousPosition = 0;
+    int position;
+    int endOfExpressionPosition;
+    StringBuffer result = new StringBuffer();
+
+    while ((position=anExpression.indexOf("$", previousPosition))>=0) {
+      result.append(anExpression.substring(previousPosition, position));
+
+      if (position>=anExpression.length()-1) {
+        result.append(anExpression.substring(position, anExpression.length()));
+        previousPosition=anExpression.length();
+      }
+      else
+      {
+        if (anExpression.charAt(position+1) == '{') {
+          endOfExpressionPosition=position+2;
+          while (endOfExpressionPosition<anExpression.length() && anExpression.charAt(endOfExpressionPosition) != '}') {
+            if (anExpression.charAt(endOfExpressionPosition)=='\'' || anExpression.charAt(endOfExpressionPosition)=='"') {
+              char boundary = anExpression.charAt(endOfExpressionPosition);
+
+              endOfExpressionPosition++;
+              while (endOfExpressionPosition<anExpression.length() && anExpression.charAt(endOfExpressionPosition) != boundary) {
+                if (anExpression.charAt(endOfExpressionPosition) == STRING_ESCAPE_CHARACTER)
+                  endOfExpressionPosition++;
+                endOfExpressionPosition++;
+              }
+              if (endOfExpressionPosition<anExpression.length()) {
+                throw new ParameterExpanderExc("Unterminated string in {1}",new Object[]{anExpression});
+              }
+            }
+            endOfExpressionPosition++;
+          }
+          if (endOfExpressionPosition<anExpression.length()) {
+            result.append(evaluateStringExpression(aMap, anExpression.substring(position+2, endOfExpressionPosition)));
+            previousPosition=endOfExpressionPosition+1;
+          }
+          else {
+            throw new ParameterExpanderExc("Missing } in {1}",new Object[]{anExpression});
+          }
+        }
+        else
+        {
+          previousPosition=position+2;
+          result.append(anExpression.charAt(position+1));
+        }
+      }
+    }
+    result.append(anExpression.substring(previousPosition, anExpression.length()));
+
+    return result.toString();
+  }
+
+  public static boolean evaluateBooleanExpression(Map aMap, String anExpression) throws Exception {
+    Parser parser = new Parser(anExpression, aMap);
+
+    return parser.parseBoolean();
+  }
+
+  public static String evaluateStringExpression(Map aMap, String anExpression) throws Exception {
+    Parser parser = new Parser(anExpression, aMap);
+
+    return parser.parseString();
+  }
+
+  public static int evaluateIntegerExpressionWithDefault(Map aMap, String anExpression, int aDefault) throws Exception {
+    if (anExpression == null || anExpression.trim().equals(""))
+      return aDefault;
+    else
+      return evaluateIntegerExpression(aMap, anExpression);
+  }
+
+  public static int evaluateIntegerExpression(Map aMap, String anExpression) throws Exception {
+    Parser parser = new Parser(anExpression, aMap);
+
+    return parser.parseInteger();
+  }
+
+  public static Object evaluateExpression(Map aMap, String anExpression) throws Exception {
+    Parser parser = new Parser(anExpression, aMap);
+
+    return parser.parseWhole();
+  }
+
+  private static class Reader {
+    private String data;
+    private int position;
+
+    public Reader(String aData) {
+      data = aData;
+      position=0;
+    }
+
+    public Character peek() {
+      if (position<data.length()) {
+        return (new Character(data.charAt(position)));
+      }
+
+      return null;
+    }
+
+    public boolean hasNext() {
+      return peek()!=null;
+    }
+
+    public Character getNext() {
+      Character result = peek();
+
+      if (result!=null)
+        position++;
+
+      return result;
+    }
+
+    public String getPositionString() {
+      return data.substring(0, position) + "<__>" + data.substring(position) ;
+    }
+  }
+
+  private static abstract class Token {
+  }
+
+  public static abstract class PunctuationToken extends Token { public PunctuationToken() { }; }
+    private static class LeftSquareBraceToken extends PunctuationToken {};
+    private static class RightSquareBraceToken extends PunctuationToken {};
+    private static class EqualsToken extends PunctuationToken {};
+    private static class EqualsNotToken extends PunctuationToken {};
+    private static class NOTToken extends PunctuationToken {};
+    private static class LeftParenthesisToken extends PunctuationToken {};
+    private static class RightParenthesisToken extends PunctuationToken {};
+    private static class CommaToken extends PunctuationToken {};
+    private static class PeriodToken extends PunctuationToken {};
+    private static class PlusToken extends PunctuationToken {};
+    private static class TimesToken extends PunctuationToken {};
+    private static class DivideToken extends PunctuationToken {};
+    private static class MinusToken extends PunctuationToken {};
+    private static class ConcatenateToken extends PunctuationToken {};
+    private static class LessThanOrEqualsToken extends PunctuationToken {};
+    private static class GreaterThanOrEqualsToken extends PunctuationToken {};
+    private static class LessThanToken extends PunctuationToken {};
+    private static class GreaterThanToken extends PunctuationToken {};
+
+
+  private static class IdentifierToken extends Token {
+    private String name;
+
+    public IdentifierToken(String aName) {
+      name = aName;
+    }
+
+    public String getName() {
+      return name;
+    }
+
+  }
+
+  private static class LiteralToken extends Token {
+    private Object value;
+
+    public LiteralToken(Object aValue) {
+      value = aValue;
+    }
+
+    public Object getValue() {
+      return value;
+    }
+  }
+
+  private static class Scanner {
+    private Reader reader;
+    private Token nextToken;
+    private String positionString;
+
+    public Scanner(Reader aReader) {
+      reader = aReader;
+      skipWhitespace();
+      positionString = reader.getPositionString();
+    }
+
+    public Token scanStringLiteral() {
+      StringBuffer result = new StringBuffer();
+      Character delimiter;
+
+      delimiter = reader.getNext();
+
+      while (reader.hasNext() && !reader.peek().equals(delimiter)) {
+        if (reader.peek().charValue()==STRING_ESCAPE_CHARACTER) {
+          reader.getNext();
+          if (reader.hasNext())
+            result.append(reader.getNext());
+        }
+        else {
+          result.append(reader.getNext());
+        }
+      }
+
+      if (!reader.hasNext())
+        throw new RuntimeException("unterminated string");
+      else
+        reader.getNext();
+
+      return new LiteralToken(result.toString());
+    }
+
+    public String getPositionString() {
+      return positionString;
+    }
+
+    private Token scanNumber() {
+      StringBuffer result = new StringBuffer();
+      result.append(reader.getNext());
+
+      while (reader.hasNext() && isNumberRest(reader.peek().charValue())) {
+        result.append(reader.getNext());
+      }
+
+      try {
+        return new LiteralToken(new Integer(Integer.parseInt(result.toString())));
+      }
+      catch (NumberFormatException e) {
+        throw new RuntimeException("Invalid number: " + e.getMessage());
+      }
+    }
+
+    private Token scanIdentifierKeyword() {
+      StringBuffer result = new StringBuffer();
+      result.append(reader.getNext());
+
+      while (reader.hasNext() && isIdentifierRest(reader.peek().charValue())) {
+        result.append(reader.getNext());
+      }
+
+      return new IdentifierToken(result.toString());
+    }
+
+    private Token scanPunctuation() {
+      Character c;
+
+      c = reader.getNext();
+
+      switch(c.charValue()) {
+        case '[': return new LeftSquareBraceToken();
+        case ']': return new RightSquareBraceToken();
+        case '=':
+          if (reader.hasNext() && reader.peek().charValue() == '=') {
+            reader.getNext();
+            return new EqualsToken();
+          }
+          else {
+            throw new RuntimeException("Unknown character: '='");
+          }
+
+        case '!':
+          if (reader.hasNext() && reader.peek().charValue() == '=') {
+            reader.getNext();
+            return new EqualsNotToken();
+          }
+          else {
+            return new NOTToken();
+          }
+
+        case '(': return new LeftParenthesisToken ();
+
+        case ')': return new RightParenthesisToken ();
+        case ',': return new CommaToken ();
+        case '.': return new PeriodToken ();
+        case '+':
+          if (reader.hasNext() && reader.peek().charValue() == '+') {
+            reader.getNext();
+            return new ConcatenateToken();
+          }
+          else {
+            return new PlusToken ();
+          }
+        case '*': return new TimesToken ();
+        case '/': return new DivideToken ();
+        case '-': return new MinusToken ();
+        case '<':
+          if (reader.hasNext() && reader.peek().charValue() == '=') {
+            reader.getNext();
+            return new LessThanOrEqualsToken();
+          }
+          else {
+            return new LessThanToken();
+          }
+
+        case '>':
+          if (reader.hasNext() && reader.peek().charValue() == '=') {
+            reader.getNext();
+            return new GreaterThanOrEqualsToken();
+          }
+          else {
+            return new GreaterThanToken();
+          }
+        default:
+          throw new RuntimeException("Unexpected character: "+c);
+      }
+    }
+
+    public void skipWhitespace() {
+      while (reader.hasNext() && Character.isWhitespace(reader.peek().charValue()))
+        reader.getNext();
+    };
+
+    private boolean isIdentifierStart(char c) {
+      return Character.isLetter(c) || (c == '_');
+    }
+
+    private boolean isIdentifierRest(char c) {
+      return Character.isLetterOrDigit(c) || (c == '_');
+    }
+
+    private boolean isNumberStart(char c) {
+      return Character.isDigit(c);
+    }
+
+    private boolean isNumberRest(char c) {
+      return Character.isDigit(c);
+    }
+
+    public Token scanNext() {
+      Token result = null;
+
+      skipWhitespace();
+
+      if (reader.hasNext()) {
+        Character c = reader.peek();
+
+        switch(c.charValue()) {
+          case '\'':
+          case '"':
+            result = scanStringLiteral();
+            break;
+
+          default: {
+            if (isIdentifierStart(c.charValue())) {
+              result = scanIdentifierKeyword();
+            }
+            else if (isNumberStart(c.charValue())) {
+              result = scanNumber();
+            }
+            else
+              result = scanPunctuation();
+          }
+        }
+      }
+
+      skipWhitespace();
+
+      return result;
+    }
+
+    public Token scan() {
+      Token result = peek();
+      nextToken = null;
+      positionString = reader.getPositionString();
+
+      return result;
+    }
+
+    public Token peek() {
+      if (nextToken==null) {
+        nextToken = scanNext();
+      }
+
+      return nextToken;
+    }
+
+    public boolean hasToken() {
+      return peek()!=null;
+    }
+  }
+
+  private static class Parser {
+    private Scanner scanner;
+    private Map valueMap;
+
+    public Parser(String anExpression, Map aValueMap) {
+      scanner = new Scanner(new Reader(anExpression));
+      valueMap = aValueMap;
+    }
+
+    public boolean parseBoolean() {
+      try {
+        return interpretAsBoolean(parseWhole());
+      }
+      catch (Throwable t) {
+        throw new RuntimeException("Parser error at '" + getLocation()+ "': "+t.getMessage());
+      }
+    }
+
+    public int parseInteger() {
+      try {
+        return interpretAsInteger(parseWhole());
+      }
+      catch (Throwable t) {
+        throw new RuntimeException("Parser error at '" + getLocation()+ "': "+t.getMessage());
+      }
+    }
+
+    public String parseString() {
+      try {
+        return interpretAsString(parseWhole());
+      }
+      catch (Throwable t) {
+        throw new RuntimeException("Parser error at '" + getLocation()+ "': "+t.getMessage());
+      }
+    }
+
+    private String getLocation() {
+      return scanner.getPositionString();
+    }
+
+    private Object parseWhole() {
+      Object result = parse();
+
+      if (scanner.hasToken()) {
+        throw new RuntimeException("Operator expected");
+      }
+
+      return result;
+    }
+
+    private Object parse() {
+      return parseUntil(MAX_OPERATOR_LEVEL);
+    }
+
+    private Object parseSet() {
+      Token token;
+      Object expression;
+      Set result = new HashSet();
+
+      token = scanner.scan();
+      if (!(token instanceof LeftParenthesisToken)) {
+        throw new RuntimeException("( expected after in keyword");
+      }
+
+      if (scanner.peek() instanceof RightParenthesisToken) {
+        scanner.scan();
+        return result;
+      }
+
+      do {
+        expression = parse();
+
+        if (expression==null) {
+          throw new RuntimeException("expression expected");
+        }
+
+        result.add(expression);
+
+        token = scanner.scan();
+      }
+      while (token instanceof CommaToken);
+
+      if (!(token instanceof RightParenthesisToken)) {
+        throw new RuntimeException(") or , expected");
+      }
+
+      return result;
+    }
+
+    private Object parseVariable() {
+      boolean done;
+      Token token;
+      Object currentValue = valueMap;
+      Object qualifier;
+
+      do {
+        token = scanner.scan();
+        if (token instanceof LeftSquareBraceToken) {
+          qualifier = parseUntil(MAX_OPERATOR_LEVEL);
+          token = scanner.scan();
+          if (!(token instanceof RightSquareBraceToken))
+            throw new RuntimeException("] expected");
+        }
+        else if (token instanceof IdentifierToken) {
+          qualifier = ((IdentifierToken) token).getName();
+        }
+        else
+          throw new RuntimeException("fieldname or [ expected");
+
+        if (currentValue!=null) {
+          if (currentValue instanceof Map) {
+            currentValue = ((Map) currentValue).get(qualifier);
+          }
+          else {
+            throw new RuntimeException("cannot reference into anything other than a map");
+          }
+        }
+        else {
+          // throw? or allow null.null?
+        }
+
+        if (scanner.peek() instanceof PeriodToken)
+        {
+          scanner.scan();
+          done = false;
+        }
+        else
+          done = true;
+      } while (!done);
+
+      return currentValue;
+    }
+
+
+    private Object parseUntil(int aMaxOperatorLevel) {
+      Token token = scanner.peek();
+      Object value;
+
+      if (token instanceof LeftParenthesisToken) {
+        scanner.scan();
+        value = parse();
+        token = scanner.peek();
+        if (!(token instanceof RightParenthesisToken))
+          throw new RuntimeException(") expected");
+        scanner.scan();
+      }
+      else if (isUnaryOperator(token)) {
+        scanner.scan();
+        value = parseUntil(unaryOperatorLevel(token));
+        value = expandOperatorExpression(token, value);
+      }
+      else if (token instanceof IdentifierToken) {
+        value = parseVariable();
+      }
+      else if (token instanceof LiteralToken) {
+        scanner.scan();
+        value = ((LiteralToken) token).getValue();
+      }
+      else
+        throw new RuntimeException("Expression expected");
+
+      token = scanner.peek();
+
+      while (isBinaryOperator(token) && binaryOperatorLevel(token)<aMaxOperatorLevel) {
+        Object value2;
+        scanner.scan();
+
+        if (isINOperator(token)) {
+          value2 = parseSet();
+        }
+        else {
+          value2 = parseUntil(binaryOperatorLevel(token));
+        }
+
+        value = expandOperatorExpression(token, value, value2);
+
+        token = scanner.peek();
+      }
+
+      return value;
+    }
+
+    private static final int MAX_OPERATOR_LEVEL = 1000;               // && || !
+    private static final int LOGICAL_OPERATOR_LEVEL = 5;               // && || !
+    private static final int COMPARISON_OPERATOR_LEVEL = 4;            // == <= >= in < >
+    private static final int ADDITION_OPERATOR_LEVEL = 3;              // + - &
+    private static final int MULTIPLICATION_OPERATOR_LEVEL = 2;        // * /
+
+    private int unaryOperatorLevel(Token aToken) {
+      if (aToken instanceof NOTToken)
+        return LOGICAL_OPERATOR_LEVEL;
+      else if (aToken instanceof MinusToken)
+        return ADDITION_OPERATOR_LEVEL;
+
+      throw new RuntimeException("Internal error: unknown unary operator: " + aToken.getClass().getName());
+    }
+
+    private boolean isUnaryOperator(Token aToken) {
+      return
+          ((aToken instanceof NOTToken) ||
+           (aToken instanceof MinusToken));
+    }
+
+    private int binaryOperatorLevel(Token aToken) {
+      if (isANDOperator(aToken) ||
+          isOROperator(aToken))
+        return LOGICAL_OPERATOR_LEVEL;
+
+      if ((aToken instanceof EqualsToken) ||
+          (aToken instanceof EqualsNotToken) ||
+          (aToken instanceof LessThanOrEqualsToken) ||
+          (aToken instanceof LessThanToken) ||
+          (aToken instanceof GreaterThanOrEqualsToken) ||
+          (aToken instanceof GreaterThanToken) ||
+          isINOperator(aToken))
+        return COMPARISON_OPERATOR_LEVEL;
+
+      if ((aToken instanceof PlusToken) ||
+          (aToken instanceof ConcatenateToken) ||
+          (aToken instanceof MinusToken))
+        return ADDITION_OPERATOR_LEVEL;
+
+      if ((aToken instanceof TimesToken) ||
+          (aToken instanceof DivideToken))
+        return MULTIPLICATION_OPERATOR_LEVEL;
+
+      throw new RuntimeException("Internal error: unknown binary operator: " + aToken.getClass().getName());
+    }
+
+    private boolean isINOperator(Token aToken) {
+      return (aToken instanceof IdentifierToken && ((IdentifierToken) aToken).getName().equals("in"));
+    }
+
+    private boolean isANDOperator(Token aToken) {
+      return (aToken instanceof IdentifierToken && ((IdentifierToken) aToken).getName().equals("and"));
+    }
+
+    private boolean isOROperator(Token aToken) {
+      return (aToken instanceof IdentifierToken && ((IdentifierToken) aToken).getName().equals("or"));
+    }
+
+    private boolean isBinaryOperator(Token aToken) {
+      return
+           (aToken instanceof EqualsToken) ||
+           (aToken instanceof EqualsNotToken) ||
+           (aToken instanceof PlusToken) ||
+           (aToken instanceof TimesToken) ||
+           (aToken instanceof DivideToken) ||
+           (aToken instanceof MinusToken) ||
+           (aToken instanceof ConcatenateToken) ||
+           (aToken instanceof LessThanOrEqualsToken) ||
+           (aToken instanceof LessThanToken) ||
+           (aToken instanceof GreaterThanOrEqualsToken) ||
+           (aToken instanceof GreaterThanToken) ||
+           isINOperator(aToken) ||
+           isOROperator(aToken) ||
+           isANDOperator(aToken);
+    }
+
+    private boolean interpretAsBoolean(Object aValue) {
+      if (aValue instanceof Boolean)
+        return ((Boolean) aValue).booleanValue();
+
+      return aValue!=null;
+    }
+
+    private int interpretAsInteger(Object aValue) {
+      if (aValue instanceof Integer)
+        return ((Integer) aValue).intValue();
+
+      if (aValue instanceof String) {
+        try {
+          return Integer.parseInt((String) aValue);
+        }
+        catch (Throwable t) {
+        }
+      }
+
+      throw new RuntimeException("Not an integer");
+    }
+
+    private String interpretAsString(Object aValue) {
+      if (aValue instanceof String)
+        return (String) aValue;
+      if (aValue instanceof Integer)
+        return ((Integer) aValue).toString();
+
+      throw new RuntimeException("Not a string");
+    }
+
+    private Object expandOperatorExpression(Token aToken, Object aValue) {
+      if (aToken instanceof NOTToken)
+        return new Boolean(!interpretAsBoolean(aValue));
+      else if (aToken instanceof MinusToken)
+        return new Integer(-interpretAsInteger(aValue));
+
+      throw new RuntimeException("Internal error: unknown unary operator: " + aToken.getClass().getName());
+    }
+
+    private boolean areEqual(Object aValue1, Object aValue2) {
+      if (aValue1==null || aValue2==null)
+        return (aValue1==null) && (aValue2==null);
+      else
+        return aValue1.equals(aValue2);
+    }
+
+    private Object expandOperatorExpression(Token aToken, Object aValue1, Object aValue2) {
+      if (isINOperator(aToken)) {
+        if (!(aValue2 instanceof Set)) {
+          throw new RuntimeException("Internal error: set expected");
+        }
+
+        Iterator i = ((Set) aValue2).iterator();
+
+        while (i.hasNext()) {
+          if (areEqual(aValue1, i.next()))
+            return Boolean.TRUE;
+        }
+
+        return Boolean.FALSE;
+      }
+
+      if (isANDOperator(aToken))
+        return new Boolean(interpretAsBoolean(aValue1) && interpretAsBoolean(aValue2));
+      if (isOROperator(aToken))
+        return new Boolean(interpretAsBoolean(aValue1) || interpretAsBoolean(aValue2));
+      if (aToken instanceof EqualsToken) {
+        return new Boolean(areEqual(aValue1, aValue2));
+      }
+      if (aToken instanceof EqualsNotToken)
+        return new Boolean(!areEqual(aValue1, aValue2));
+      if (aToken instanceof PlusToken)
+        return new Integer(interpretAsInteger(aValue1) + interpretAsInteger(aValue2));
+      if (aToken instanceof TimesToken)
+        return new Integer(interpretAsInteger(aValue1) * interpretAsInteger(aValue2));
+      if (aToken instanceof DivideToken)
+        return new Integer(interpretAsInteger(aValue1) / interpretAsInteger(aValue2));
+      if (aToken instanceof MinusToken)
+        return new Integer(interpretAsInteger(aValue1) - interpretAsInteger(aValue2));
+
+      if (aToken instanceof ConcatenateToken)
+        return interpretAsString(aValue1) + interpretAsString(aValue2);
+
+      if (aToken instanceof LessThanOrEqualsToken)
+        return new Boolean(interpretAsInteger(aValue1) <= interpretAsInteger(aValue2));
+      if (aToken instanceof LessThanToken)
+        return new Boolean(interpretAsInteger(aValue1) < interpretAsInteger(aValue2));
+      if (aToken instanceof GreaterThanOrEqualsToken)
+        return new Boolean(interpretAsInteger(aValue1) >= interpretAsInteger(aValue2));
+      if (aToken instanceof GreaterThanToken)
+        return new Boolean(interpretAsInteger(aValue1) > interpretAsInteger(aValue2));
+
+      throw new RuntimeException("Internal error: unknown binary operator: " + aToken.getClass().getName());
+    }
+  }
+
+  public static class ParameterExpanderExc extends Exc {
+    public ParameterExpanderExc(String msg, Object[] objects) {
+      super(msg, objects);
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mir/util/ResourceBundleGeneratorFunction.java b/source/mir/util/ResourceBundleGeneratorFunction.java
new file mode 100755 (executable)
index 0000000..fc0152e
--- /dev/null
@@ -0,0 +1,37 @@
+package mir.util;
+
+import java.util.*;
+import org.apache.struts.util.MessageResources;
+
+import mir.generator.*;
+
+public class ResourceBundleGeneratorFunction implements Generator.GeneratorFunction {
+  private MessageResources messages;
+  private Locale locale;
+
+  public ResourceBundleGeneratorFunction(Locale aLocale, MessageResources aMessages) {
+    this.locale = aLocale;
+    this.messages = aMessages;
+  }
+
+  public Object perform(List aParameters) throws GeneratorExc {
+    List extraParameters = new Vector(aParameters);
+
+    if (aParameters.size()<1)
+      throw new GeneratorExc("ResourceBundleGeneratorFunction: at least 1 parameter expected");
+
+    if (!(aParameters.get(0) instanceof String))
+      throw new GeneratorExc("encodeHTMLGeneratorFunction: parameters must be strings");
+
+    String key = (String) aParameters.get(0);
+    extraParameters.remove(0);
+    String message = messages.getMessage(locale, key, extraParameters.toArray());
+
+    if (message == null) {
+      return new String("??" + key + "??");
+    }
+    else {
+      return message;
+    }
+  };
+}
\ No newline at end of file
diff --git a/source/mir/util/RewindableIterator.java b/source/mir/util/RewindableIterator.java
new file mode 100755 (executable)
index 0000000..23f8e55
--- /dev/null
@@ -0,0 +1,7 @@
+package mir.util;
+
+import java.util.*;
+
+public interface RewindableIterator extends Iterator {
+  public void rewind();
+}
\ No newline at end of file
diff --git a/source/mircoders/global/JobQueue.java b/source/mircoders/global/JobQueue.java
new file mode 100755 (executable)
index 0000000..f60116f
--- /dev/null
@@ -0,0 +1,136 @@
+package mircoders.global;
+
+import java.util.*;
+
+// important: objects passed as data must not be altered once put into a job
+
+public class JobQueue {
+  private Vector jobs;
+  private Map dataToJob;
+
+  public static final int STATUS_PENDING = 0;
+  public static final int STATUS_PROCESSING = 1;
+  public static final int STATUS_PROCESSED = 2;
+
+  public JobQueue() {
+    jobs = new Vector();
+    dataToJob = new HashMap();
+  }
+
+  public void appendJob(Object aData) {
+    synchronized (jobs) {
+      Job job = new Job(aData);
+      jobs.add(job);
+      dataToJob.put(aData, job);
+    }
+  }
+
+  public Object acquirePendingJob() {
+    synchronized (jobs) {
+      Iterator i = jobs.iterator();
+
+      while (i.hasNext()) {
+        Job job = (Job) i.next();
+
+        if (job.setProcessing()) {
+          return job.getData();
+        }
+      }
+    }
+
+    return null;
+  }
+
+  public void flagOffJob(Object aData) {
+    synchronized (jobs) {
+      Job job = (Job) dataToJob.get(aData);
+
+      if (job!=null) {
+        job.setProcessed();
+      }
+    }
+  }
+
+  public void cleanupJobs() {
+    synchronized (jobs) {
+      Iterator i = jobs.iterator();
+
+      while (i.hasNext()) {
+        Job job = (Job) i.next();
+
+        if (job.hasBeenProcessed()) {
+          i.remove();
+        }
+      }
+    }
+  }
+
+  public List makeJobListSnapshot() {
+    synchronized (jobs) {
+      return (List) jobs.clone();
+    }
+  }
+
+  public class Job implements Cloneable {
+    private Object data;
+    private int status;
+
+    public Job(Object aData, int aStatus) {
+      data = aData;
+      status = aStatus;
+    }
+
+    public Job(Object aData) {
+      this(aData, STATUS_PENDING);
+    }
+
+    public Object getData() {
+      return data;
+    }
+
+    public int getStatus() {
+      synchronized(this) {
+        return status;
+      }
+    }
+
+    protected boolean setProcessing() {
+      return setStatus(STATUS_PENDING, STATUS_PROCESSING);
+    }
+
+    protected void setProcessed() {
+      setStatus(STATUS_PROCESSING, STATUS_PROCESSED);
+    }
+
+    public boolean hasBeenProcessed() {
+      return getStatus() == STATUS_PROCESSED;
+    }
+
+    public boolean isProcessing() {
+      return getStatus() == STATUS_PROCESSING;
+    }
+
+    public boolean isPending() {
+      return getStatus() == STATUS_PENDING;
+    }
+
+    private boolean setStatus(int anOldStatus, int aNewStatus) {
+      synchronized(this) {
+        if (status == anOldStatus) {
+          status = aNewStatus;
+          return true;
+        }
+        else {
+          return false;
+        }
+      }
+    }
+
+    protected Object clone() {
+      synchronized(this) {
+        return new Job(data, status);
+      }
+    }
+  }
+}
+
diff --git a/source/mircoders/global/MirGlobal.java b/source/mircoders/global/MirGlobal.java
new file mode 100755 (executable)
index 0000000..28a4a3b
--- /dev/null
@@ -0,0 +1,99 @@
+package mircoders.global;
+
+import mir.misc.*;
+import mircoders.localizer.*;
+
+public class MirGlobal {
+  static private MirConfig configuration;
+  static private MirLocalizer localizer;
+  static private ProducerEngine producerEngine;
+
+  public static MirLocalizer localizer() {
+    String localizerClassName;
+    Class localizerClass;
+
+    if (localizer == null ) {
+      synchronized(MirGlobal.class) {
+        if (localizer == null ) {
+          localizerClassName = getConfigPropertyWithDefault("Mir.Localizer", "mirlocal.loaclizer.basic.MirBasicLocalizer");
+
+          try {
+            localizerClass = Class.forName(localizerClassName);
+          }
+          catch (Throwable t) {
+            throw new ConfigException("localizer class '" + localizerClassName + "' not found: " + t.toString());
+          }
+
+          if (!(MirLocalizer.class.isAssignableFrom(localizerClass)))
+            throw new ConfigException("localizer class '" + localizerClassName + "' is not assignable from MirLocalizer");
+
+          try {
+            localizer = new MirCachingLocalizerDecorator((MirLocalizer) localizerClass.newInstance());
+          }
+          catch (Throwable t) {
+            throw new ConfigException("localizer class '" + localizerClassName + "' cannot be instantiated: " + t.toString());
+          }
+        }
+      }
+    }
+
+    return localizer;
+  }
+
+  public static MirConfig config() {
+    if (configuration == null) {
+      configuration = new MirConfig();
+    }
+
+    return configuration;
+  }
+
+  public static ProducerEngine producerEngine() {
+    if (producerEngine == null) {
+      producerEngine = new ProducerEngine();
+    }
+
+    return producerEngine;
+  }
+
+  public static String getConfigPropertyWithDefault(String aPropertyName, String aDefault) {
+    String result;
+
+    result = config().getProp(aPropertyName);
+
+    if (result==null)
+      result = aDefault;
+
+    return result;
+  }
+
+  public static String getConfigProperty(String aPropertyName) {
+    String result;
+
+    result = config().getProp(aPropertyName);
+
+    if (result==null)
+      throw new ConfigException("Property '" + aPropertyName + "' not present");
+
+    return result;
+  }
+
+  public static int getConfigIntegerProperty(String aPropertyName) {
+    String result;
+
+    result = config().getProp(aPropertyName);
+
+    return Integer.parseInt(result);
+  }
+
+  public static boolean getConfigBooleanProperty(String aPropertyName) {
+    String result;
+
+    result = config().getProp(aPropertyName);
+
+    if (result==null)
+      throw new ConfigException("Boolean property '" + aPropertyName + "' not present");
+
+    return (result.equals("yes") || result.equals("1"));
+  }
+}
diff --git a/source/mircoders/global/ProducerEngine.java b/source/mircoders/global/ProducerEngine.java
new file mode 100755 (executable)
index 0000000..1fb9e60
--- /dev/null
@@ -0,0 +1,172 @@
+package mircoders.global;
+
+import java.util.*;
+import java.io.*;
+import mir.producer.*;
+import mir.util.*;
+import multex.Exc;
+import multex.Failure;
+
+public class ProducerEngine {
+//  private Map producers;
+  private JobQueue producerJobQueue;
+  private Thread queueThread;
+  private PrintWriter log;
+
+  protected ProducerEngine() {
+//    producers = MirGlobal.localizer().producers().factories();
+    producerJobQueue = new JobQueue();
+    try {
+      RandomAccessFile raFile = (new RandomAccessFile(MirGlobal.getConfigProperty("Home") + "/" + MirGlobal.getConfigProperty("Producer.Logfile"), "rw"));
+                        raFile.seek(raFile.length());
+                log = new PrintWriter(new FileWriter( raFile.getFD()));
+    }
+    catch (Exception e) {
+//      throw new ProducerEngineRuntimeExc("Creating PrintWriter log failed",e);
+      log = new PrintWriter(new NullWriter());
+    }
+    queueThread = new Thread(new ProducerJobQueueThread());
+    queueThread.start();
+  }
+
+  public void addJob(String aProducerFactory, String aVerb) {
+// ML: TODO: should check if a similar job is already pending
+    producerJobQueue.appendJob(new ProducerJob(aProducerFactory, aVerb));
+    log.println(aProducerFactory+"."+aVerb+" added to queue");
+    log.flush();
+  }
+
+  public void printQueueStatus(PrintWriter aWriter) {
+    Iterator iterator = producerJobQueue.makeJobListSnapshot().iterator();
+    producerJobQueue.cleanupJobs();
+    JobQueue.Job job;
+
+    while (iterator.hasNext()) {
+      job = (JobQueue.Job) iterator.next();
+      ProducerJob producerJob = (ProducerJob) job.getData();
+
+      aWriter.print(producerJob.factoryName + "." + producerJob.verb);
+      if (job.hasBeenProcessed())
+        aWriter.print(" processed");
+      else if (job.isProcessing())
+        aWriter.print(" processing");
+      else if (job.isPending())
+        aWriter.print(" pending");
+      else
+        aWriter.print(" unknown status");
+
+      aWriter.println("<br/>");
+    }
+  }
+
+  private void produceNow(String aProducerFactory, String aVerb, PrintWriter aLogger) {
+    try {
+      long startTime;
+      long endTime;
+      Map startingMap = new HashMap();
+
+      startTime = System.currentTimeMillis();
+
+      aLogger.println("Producing (" + aProducerFactory + "," + aVerb + ")");
+
+      ProducerFactory factory = (ProducerFactory) MirGlobal.localizer().producers().factories().get(aProducerFactory);
+
+      if (factory == null )
+        throw new Exception("No producer factory '"+aProducerFactory+"' present.");
+
+      MirGlobal.localizer().producerAssistant().initializeGenerationValueSet(startingMap);
+      Producer producer = factory.makeProducer(aVerb, startingMap);
+
+      producer.produce(aLogger);
+
+      endTime = System.currentTimeMillis();
+
+      aLogger.println("Time: " + (endTime-startTime) + " ms<br>");
+    }
+    catch (Throwable e) {
+      try {
+        aLogger.println("exception occurred:<br>");
+        aLogger.println(e.getMessage());
+        e.printStackTrace(aLogger);
+      }
+      catch (Throwable f) {
+      }
+    }
+  }
+
+  private class ProducerJob {
+    private String factoryName;
+    private String verb;
+
+    public ProducerJob(String aFactory, String aVerb) {
+      factoryName = aFactory;
+      verb = aVerb;
+    }
+
+    public void execute() {
+      ProducerFactory factory;
+      Producer producer;
+      long startTime;
+      long endTime;
+      Map startingMap = new HashMap();
+
+      startTime = System.currentTimeMillis();
+      log.println("Producing job: "+factoryName+"."+verb);
+
+      try {
+        factory = (ProducerFactory) MirGlobal.localizer().producers().factories().get( factoryName );
+
+        if (factory!=null) {
+          MirGlobal.localizer().producerAssistant().initializeGenerationValueSet(startingMap);
+
+          synchronized(factory) {
+            producer = factory.makeProducer(verb, startingMap);
+          }
+          if (producer!=null) {
+            producer.produce(log);
+          }
+        }
+      }
+      catch (Throwable t) {
+        log.println("  exception "+t.getMessage());
+        t.printStackTrace(log);
+      }
+      log.println("Done producing job: "+factoryName+"."+verb);
+                  endTime = System.currentTimeMillis();
+
+                  log.println("Time: " + (endTime-startTime) + " ms");
+                  log.flush();
+    }
+  }
+
+  private class ProducerJobQueueThread implements Runnable {
+    public void run() {
+      log.println("starting ProducerJobQueueThread");
+      log.flush();
+
+      while (true) {
+        ProducerJob job = (ProducerJob) producerJobQueue.acquirePendingJob();
+        if (job!=null) {
+          job.execute();
+          producerJobQueue.flagOffJob(job);
+        }
+        else
+        {
+          try {
+            Thread.sleep(1500);
+          }
+          catch (InterruptedException e) {
+          }
+        }
+      }
+    }
+  }
+
+
+  public static class ProducerEngineRuntimeExc extends Failure {
+    public ProducerEngineRuntimeExc(String msg, Exception cause){
+      super(msg,cause);
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/source/mircoders/localizer/MirAdminInterfaceLocalizer.java b/source/mircoders/localizer/MirAdminInterfaceLocalizer.java
new file mode 100755 (executable)
index 0000000..8a5c9a6
--- /dev/null
@@ -0,0 +1,18 @@
+package mircoders.localizer;
+
+import java.util.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+
+public interface MirAdminInterfaceLocalizer {
+  public Map simpleCommentOperations();
+  public Map simpleArticleOperations();
+
+  public interface MirSimpleEntityOperation {
+    public boolean isAvailable(EntityAdapter anEntity);
+    public void perform(EntityAdapter anEntity);
+  }
+}
\ No newline at end of file
diff --git a/source/mircoders/localizer/MirCachingLocalizerDecorator.java b/source/mircoders/localizer/MirCachingLocalizerDecorator.java
new file mode 100755 (executable)
index 0000000..bf26533
--- /dev/null
@@ -0,0 +1,65 @@
+package mircoders.localizer;
+
+public class MirCachingLocalizerDecorator implements MirLocalizer {
+  private MirLocalizer localizer;
+  private MirProducerLocalizer producerLocalizer;
+  private MirGeneratorLocalizer generatorLocalizer;
+  private MirOpenPostingLocalizer openPostingsLocalizer;
+  private MirProducerAssistantLocalizer producerAssistantLocalizer;
+  private MirDataModelLocalizer dataModelLocalizer;
+  private MirAdminInterfaceLocalizer adminInterfaceLocalizer;
+
+  public MirCachingLocalizerDecorator(MirLocalizer aLocalizer) {
+    localizer = aLocalizer;
+  }
+
+  public MirProducerLocalizer producers() throws MirLocalizerFailure, MirLocalizerException {
+    if (producerLocalizer==null) {
+      producerLocalizer = localizer.producers();
+    }
+
+    return producerLocalizer;
+  }
+
+  public MirGeneratorLocalizer generators() throws MirLocalizerFailure, MirLocalizerException {
+    if (generatorLocalizer==null) {
+      generatorLocalizer = localizer.generators();
+    }
+
+    return generatorLocalizer;
+  }
+
+  public MirOpenPostingLocalizer openPostings() throws MirLocalizerFailure, MirLocalizerException {
+    if (openPostingsLocalizer==null) {
+      openPostingsLocalizer = localizer.openPostings();
+    }
+
+    return openPostingsLocalizer;
+  }
+
+  public MirProducerAssistantLocalizer producerAssistant() throws MirLocalizerFailure, MirLocalizerException {
+    if (producerAssistantLocalizer==null) {
+      producerAssistantLocalizer = localizer.producerAssistant();
+    }
+
+    return producerAssistantLocalizer;
+  }
+
+  public MirDataModelLocalizer dataModel() throws MirLocalizerFailure, MirLocalizerException {
+    if (dataModelLocalizer==null) {
+      dataModelLocalizer = localizer.dataModel();
+    }
+
+    return dataModelLocalizer;
+  }
+
+  public MirAdminInterfaceLocalizer adminInterface() throws MirLocalizerFailure, MirLocalizerException {
+    if (adminInterfaceLocalizer==null) {
+      adminInterfaceLocalizer = localizer.adminInterface();
+    }
+
+    return adminInterfaceLocalizer;
+  };
+
+
+}
\ No newline at end of file
diff --git a/source/mircoders/localizer/MirDataModelLocalizer.java b/source/mircoders/localizer/MirDataModelLocalizer.java
new file mode 100755 (executable)
index 0000000..4b8c8a1
--- /dev/null
@@ -0,0 +1,7 @@
+package mircoders.localizer;\r
+\r
+import mir.entity.adapter.*;\r
+\r
+public interface MirDataModelLocalizer {\r
+  public EntityAdapterModel adapterModel() throws MirLocalizerException, MirLocalizerFailure;\r
+}
\ No newline at end of file
diff --git a/source/mircoders/localizer/MirGeneratorLocalizer.java b/source/mircoders/localizer/MirGeneratorLocalizer.java
new file mode 100755 (executable)
index 0000000..a966b42
--- /dev/null
@@ -0,0 +1,8 @@
+package mircoders.localizer;
+
+import mir.generator.*;
+
+public interface MirGeneratorLocalizer {
+  public Generator.GeneratorLibrary makeGeneratorLibrary() throws MirLocalizerException, MirLocalizerFailure;
+  public WriterEngine makeWriterEngine() throws MirLocalizerException, MirLocalizerFailure;
+}
\ No newline at end of file
diff --git a/source/mircoders/localizer/MirLocalizer.java b/source/mircoders/localizer/MirLocalizer.java
new file mode 100755 (executable)
index 0000000..aeb0400
--- /dev/null
@@ -0,0 +1,11 @@
+package mircoders.localizer;
+
+public interface MirLocalizer {
+  public MirProducerLocalizer producers() throws MirLocalizerFailure, MirLocalizerException;
+  public MirAdminInterfaceLocalizer adminInterface() throws MirLocalizerFailure, MirLocalizerException;
+  public MirOpenPostingLocalizer openPostings() throws MirLocalizerFailure, MirLocalizerException;
+  public MirProducerAssistantLocalizer producerAssistant() throws MirLocalizerFailure, MirLocalizerException;
+  public MirGeneratorLocalizer generators() throws MirLocalizerFailure, MirLocalizerException;
+  public MirDataModelLocalizer dataModel() throws MirLocalizerFailure, MirLocalizerException;
+
+}
\ No newline at end of file
diff --git a/source/mircoders/localizer/MirLocalizerException.java b/source/mircoders/localizer/MirLocalizerException.java
new file mode 100755 (executable)
index 0000000..1bb8215
--- /dev/null
@@ -0,0 +1,10 @@
+package mircoders.localizer;
+
+import multex.Exc;
+
+public class MirLocalizerException extends Exc {
+
+  public MirLocalizerException(String aMessage) {
+    super(aMessage);
+  }
+}
\ No newline at end of file
diff --git a/source/mircoders/localizer/MirLocalizerFailure.java b/source/mircoders/localizer/MirLocalizerFailure.java
new file mode 100755 (executable)
index 0000000..c5a99e4
--- /dev/null
@@ -0,0 +1,12 @@
+package mircoders.localizer;
+
+import multex.Failure;
+
+public class MirLocalizerFailure extends Failure {
+  public MirLocalizerFailure(String msg, Throwable throwable) {
+    super(msg, throwable);
+  }
+  public MirLocalizerFailure(Throwable aThrowable) {
+    this(aThrowable.getMessage(), aThrowable);
+  }
+}
diff --git a/source/mircoders/localizer/MirOpenPostingLocalizer.java b/source/mircoders/localizer/MirOpenPostingLocalizer.java
new file mode 100755 (executable)
index 0000000..d9add8c
--- /dev/null
@@ -0,0 +1,13 @@
+package mircoders.localizer;
+
+import java.util.*;
+import javax.servlet.http.*;
+
+import mircoders.entity.*;
+
+public interface MirOpenPostingLocalizer {
+  public void afterContentPosting(EntityContent aContent);
+  public void afterCommentPosting(EntityComment aComment);
+
+  public String chooseOpenPostingLanguage(HttpServletRequest req);
+}
diff --git a/source/mircoders/localizer/MirProducerAssistantLocalizer.java b/source/mircoders/localizer/MirProducerAssistantLocalizer.java
new file mode 100755 (executable)
index 0000000..4319fae
--- /dev/null
@@ -0,0 +1,9 @@
+package mircoders.localizer;
+
+import java.util.*;
+import java.io.*;
+
+public interface MirProducerAssistantLocalizer {
+  public void initializeGenerationValueSet(Map aValueSet) throws MirLocalizerException, MirLocalizerFailure;
+  public String filterText(String aText) throws MirLocalizerException, MirLocalizerFailure;
+}
diff --git a/source/mircoders/localizer/MirProducerLocalizer.java b/source/mircoders/localizer/MirProducerLocalizer.java
new file mode 100755 (executable)
index 0000000..44abd88
--- /dev/null
@@ -0,0 +1,7 @@
+package mircoders.localizer;
+
+import java.util.*;
+
+public interface MirProducerLocalizer {
+  public Map factories() throws MirLocalizerException, MirLocalizerFailure;
+}
diff --git a/source/mircoders/localizer/basic/MirBasicAdminInterfaceLocalizer.java b/source/mircoders/localizer/basic/MirBasicAdminInterfaceLocalizer.java
new file mode 100755 (executable)
index 0000000..044789c
--- /dev/null
@@ -0,0 +1,131 @@
+package mircoders.localizer.basic;
+
+import java.util.*;
+import mir.entity.adapter.*;
+import mir.storage.*;
+import mir.entity.*;
+import mircoders.localizer.*;
+import mircoders.entity.*;
+import mircoders.storage.*;
+
+
+public class MirBasicAdminInterfaceLocalizer implements MirAdminInterfaceLocalizer {
+  private Map simpleCommentOperations;
+  private Map simpleArticleOperations;
+
+  public MirBasicAdminInterfaceLocalizer() throws MirLocalizerFailure, MirLocalizerException {
+    simpleCommentOperations = new HashMap();
+    simpleArticleOperations = new HashMap();
+
+    buildSimpleCommentOperations(simpleCommentOperations);
+    buildSimpleArticleOperations(simpleArticleOperations);
+  }
+
+  public Map simpleCommentOperations() {
+    return simpleCommentOperations;
+  };
+
+  public Map simpleArticleOperations() {
+    return simpleArticleOperations;
+  };
+
+  public void buildSimpleCommentOperations(Map anOperations) throws MirLocalizerFailure, MirLocalizerException {
+    anOperations.put("hide", new HideCommentOperation());
+    anOperations.put("unhide", new UnhideCommentOperation());
+  };
+
+  public void buildSimpleArticleOperations(Map anOperations)  throws MirLocalizerFailure, MirLocalizerException {
+    anOperations.put("hide", new HideArticleOperation());
+    anOperations.put("unhide", new UnhideArticleOperation());
+  };
+
+  protected abstract static class EntityModifyingOperation implements MirSimpleEntityOperation {
+    public boolean isAvailable(EntityAdapter anEntity) {
+      try {
+
+        Entity entity = anEntity.getEntity();
+        return (entity instanceof EntityComment) && isAvailable((EntityComment) entity);
+      }
+      catch (Throwable t) {
+        return false;
+      }
+    };
+
+    public void perform(EntityAdapter anEntity) {
+      Entity entity = anEntity.getEntity();
+      try {
+        performModification(entity);
+        entity.update();
+      }
+      catch (Throwable t) {
+      }
+    };
+
+    protected abstract boolean isAvailable(Entity anEntity) throws StorageObjectException ;
+    protected abstract void performModification(Entity anEntity) throws StorageObjectException ;
+  }
+
+  public static abstract class CommentModifyingOperation extends EntityModifyingOperation {
+    protected boolean isAvailable(Entity anEntity) throws StorageObjectException {
+      return anEntity instanceof EntityComment && isAvailable((EntityComment) anEntity);
+    }
+
+    protected void performModification(Entity anEntity) throws StorageObjectException {
+      performModification((EntityComment) anEntity);
+      DatabaseContent.getInstance().setUnproduced("id="+anEntity.getValue("to_media"));
+    };
+
+    protected abstract boolean isAvailable(EntityComment aComment) throws StorageObjectException ;
+    protected abstract void performModification(EntityComment aComment) throws StorageObjectException ;
+  }
+
+  public static abstract class ArticleModifyingOperation extends EntityModifyingOperation {
+    protected boolean isAvailable(Entity anEntity) throws StorageObjectException {
+      return anEntity instanceof EntityContent && isAvailable((EntityComment) anEntity);
+    }
+
+    protected void performModification(Entity anEntity) throws StorageObjectException {
+      performModification((EntityContent) anEntity);
+      anEntity.setValueForProperty("is_produced", "0");
+    };
+
+    protected abstract boolean isAvailable(EntityContent anArticle) throws StorageObjectException ;
+    protected abstract void performModification(EntityContent anArticle) throws StorageObjectException ;
+  }
+
+  private static class HideCommentOperation extends CommentModifyingOperation {
+    protected boolean isAvailable(EntityComment aComment) {
+      return aComment.getValue("is_published").equals("1");
+    }
+    protected void performModification(EntityComment aComment) throws StorageObjectException {
+      aComment.setValueForProperty("is_published", "0");
+    }
+  }
+
+  private static class UnhideCommentOperation extends CommentModifyingOperation {
+    protected boolean isAvailable(EntityComment aComment) {
+      return aComment.getValue("is_published").equals("0");
+    }
+    protected void performModification(EntityComment aComment) throws StorageObjectException {
+      aComment.setValueForProperty("is_published", "1");
+    }
+  }
+
+  private static class HideArticleOperation extends ArticleModifyingOperation {
+    protected boolean isAvailable(EntityContent anArticle) {
+      return anArticle.getValue("is_published").equals("1");
+    }
+    protected void performModification(EntityContent anArticle) throws StorageObjectException {
+      anArticle.setValueForProperty("is_published", "0");
+    }
+  }
+
+  private static class UnhideArticleOperation extends ArticleModifyingOperation {
+    protected boolean isAvailable(EntityContent anArticle) {
+      return anArticle.getValue("is_published").equals("0");
+    }
+    protected void performModification(EntityContent anArticle) throws StorageObjectException {
+      anArticle.setValueForProperty("is_published", "1");
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mircoders/localizer/basic/MirBasicDataModelLocalizer.java b/source/mircoders/localizer/basic/MirBasicDataModelLocalizer.java
new file mode 100755 (executable)
index 0000000..4edec5b
--- /dev/null
@@ -0,0 +1,266 @@
+package mircoders.localizer.basic;\r
+\r
+import java.util.*;\r
+import mir.entity.*;\r
+import mir.entity.adapter.*;\r
+import mir.media.*;\r
+import mir.misc.*;\r
+import mir.util.*;\r
+import mircoders.storage.*;\r
+import mircoders.global.*;\r
+import mircoders.entity.*;\r
+import mircoders.localizer.*;\r
+\r
+public class MirBasicDataModelLocalizer implements MirDataModelLocalizer {\r
+  private EntityAdapterModel model;\r
+\r
+  public MirBasicDataModelLocalizer() {\r
+  }\r
+\r
+  public EntityAdapterModel adapterModel() throws MirLocalizerFailure {\r
+    if (model==null)\r
+      model = buildModel();\r
+\r
+    return model;\r
+  };\r
+\r
+  protected void constructContentAdapterDefinition(EntityAdapterDefinition anEntityAdapterDefinition) throws MirLocalizerFailure {\r
+    try {\r
+      anEntityAdapterDefinition.addDBDateField("creationdate", "webdb_create");\r
+      anEntityAdapterDefinition.addDBDateField("changedate", "webdb_lastchange");\r
+      anEntityAdapterDefinition.addMirDateField("date", "date");\r
+      anEntityAdapterDefinition.addCalculatedField("to_topics", new ContentToTopicsField());\r
+      anEntityAdapterDefinition.addCalculatedField("to_comments", new ContentToCommentsField());\r
+\r
+      anEntityAdapterDefinition.addCalculatedField("to_media_images",  new ContentToMediaField( "image" ));\r
+      anEntityAdapterDefinition.addCalculatedField("to_uploaded_media", new ContentToMediaField( "uploadedMedia" ));\r
+      anEntityAdapterDefinition.addCalculatedField("to_media_audio", new ContentToMediaField( "audio" ));\r
+      anEntityAdapterDefinition.addCalculatedField("to_media_video", new ContentToMediaField( "video" ));\r
+      anEntityAdapterDefinition.addCalculatedField("to_media_other", new ContentToMediaField( "otherMedia" ));\r
+      anEntityAdapterDefinition.addCalculatedField("to_media_icon", new ContentToIconField());\r
+\r
+      anEntityAdapterDefinition.addCalculatedField("description_parsed", new FilteredField("description"));\r
+      anEntityAdapterDefinition.addCalculatedField("content_data_parsed", new FilteredField("content_data"));\r
+    }\r
+    catch (Throwable t) {\r
+      throw new MirLocalizerFailure(t.getMessage(), t);\r
+    }\r
+  }\r
+\r
+  protected void constructCommentAdapterDefinition(EntityAdapterDefinition anEntityAdapterDefinition) throws MirLocalizerFailure {\r
+    try {\r
+      anEntityAdapterDefinition.addDBDateField("creationdate", "webdb_create");\r
+      anEntityAdapterDefinition.addCalculatedField("to_content", new CommentToContentField());\r
+\r
+      anEntityAdapterDefinition.addCalculatedField("description_parsed", new FilteredField("description"));\r
+      anEntityAdapterDefinition.addCalculatedField("operations", new CommentToOperationsField());\r
+    }\r
+    catch (Throwable t) {\r
+      throw new MirLocalizerFailure(t.getMessage(), t);\r
+    }\r
+  }\r
+\r
+  protected EntityAdapterModel buildModel() throws MirLocalizerFailure {\r
+    EntityAdapterModel result = new EntityAdapterModel();\r
+\r
+    try {\r
+      EntityAdapterDefinition definition;\r
+\r
+      definition = new EntityAdapterDefinition();\r
+      constructContentAdapterDefinition( definition );\r
+      result.addMapping( "content", DatabaseContent.getInstance(), definition);\r
+\r
+      definition = new EntityAdapterDefinition();\r
+      constructCommentAdapterDefinition( definition );\r
+      result.addMapping( "comment", DatabaseComment.getInstance(), definition);\r
+\r
+      result.addMapping( "articleType", DatabaseArticleType.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "breakingNews", DatabaseBreaking.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "feature", DatabaseFeature.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "imageType", DatabaseImageType.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "language", DatabaseLanguage.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "mediaFolder", DatabaseMediafolder.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "mediaType", DatabaseMediaType.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "internalMessage", DatabaseMessages.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "topic", DatabaseTopics.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "user", DatabaseUsers.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "media", DatabaseMedia.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "uploadedMedia", DatabaseUploadedMedia.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "image", DatabaseImages.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "audio", DatabaseAudio.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "video", DatabaseVideo.getInstance(), new EntityAdapterDefinition());\r
+      result.addMapping( "otherMedia", DatabaseOther.getInstance(), new EntityAdapterDefinition());\r
+    }\r
+    catch (Throwable t) {\r
+      throw new MirLocalizerFailure(t.getMessage(), t);\r
+    }\r
+\r
+    return result;\r
+  }\r
+\r
+  protected class CommentToContentField implements EntityAdapterDefinition.CalculatedField {\r
+    public Object getValue(EntityAdapter anEntityAdapter) {\r
+      try {\r
+        return anEntityAdapter.getRelation(\r
+                    "id="+anEntityAdapter.get("to_media"),\r
+                    "id",\r
+                    "content" );\r
+      }\r
+      catch (Throwable t) {\r
+        throw new RuntimeException(t.getMessage());\r
+      }\r
+    }\r
+  }\r
+\r
+  protected class CommentToOperationsField implements EntityAdapterDefinition.CalculatedField {\r
+    public Object getValue(EntityAdapter anEntityAdapter) {\r
+      try {\r
+        Map operations = MirGlobal.localizer().adminInterface().simpleCommentOperations();\r
+        Iterator i = operations.entrySet().iterator();\r
+        List availableOperations = new Vector();\r
+\r
+        while (i.hasNext()) {\r
+          Map.Entry entry = (Map.Entry) i.next();\r
+\r
+          MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =\r
+            (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) entry.getValue();\r
+\r
+          if (operation.isAvailable(anEntityAdapter)) {\r
+            availableOperations.add(entry.getKey());\r
+          }\r
+        };\r
+\r
+        return availableOperations;\r
+      }\r
+      catch (Throwable t) {\r
+        throw new RuntimeException(t.getMessage());\r
+      }\r
+    }\r
+  }\r
+\r
+  protected class FilteredField implements EntityAdapterDefinition.CalculatedField {\r
+    String fieldName;\r
+\r
+    public FilteredField(String aFieldName) {\r
+      fieldName = aFieldName;\r
+    }\r
+\r
+    public Object getValue(EntityAdapter anEntityAdapter) {\r
+      try {\r
+        if (anEntityAdapter.get("is_html")!=null && anEntityAdapter.get("is_html").equals("1")) {\r
+          return anEntityAdapter.get(fieldName);\r
+        }\r
+        else {\r
+          return MirGlobal.localizer().producerAssistant().filterText((String) anEntityAdapter.get(fieldName));\r
+        }\r
+      }\r
+      catch (Throwable t) {\r
+        throw new RuntimeException(t.getMessage());\r
+      }\r
+    }\r
+  }\r
+\r
+  protected class ContentToCommentsField implements EntityAdapterDefinition.CalculatedField {\r
+    public Object getValue(EntityAdapter anEntityAdapter) {\r
+      try {\r
+        return anEntityAdapter.getRelation(\r
+                    "to_media="+anEntityAdapter.get("id")+" and is_published='1'",\r
+                    "webdb_create",\r
+                    "comment" );\r
+      }\r
+      catch (Throwable t) {\r
+        throw new RuntimeException(t.getMessage());\r
+      }\r
+    }\r
+  }\r
+\r
+  protected class ContentToTopicsField implements EntityAdapterDefinition.CalculatedField {\r
+    public Object getValue(EntityAdapter anEntityAdapter) {\r
+      try {\r
+        return anEntityAdapter.getRelation(\r
+                    "exists (select * from content_x_topic where content_id="+anEntityAdapter.get("id")+" and topic_id=id)",\r
+                    "title",\r
+                    "topic" );\r
+      }\r
+      catch (Throwable t) {\r
+        throw new RuntimeException(t.getMessage());\r
+      }\r
+    }\r
+  }\r
+\r
+  protected class ContentToMediaField implements EntityAdapterDefinition.CalculatedField {\r
+    String definition;\r
+\r
+    public ContentToMediaField(String aDefinition) {\r
+      definition = aDefinition;\r
+    }\r
+\r
+    public Object getValue(EntityAdapter anEntityAdapter) {\r
+      try {\r
+        return anEntityAdapter.getRelation(\r
+          "exists (select * from content_x_media where content_id="+anEntityAdapter.get("id")+" and media_id=id)",\r
+          "title",\r
+          definition);\r
+      }\r
+      catch (Throwable t) {\r
+        throw new RuntimeException(t.getMessage());\r
+      }\r
+    }\r
+  }\r
+\r
+  protected class ContentToIconField implements EntityAdapterDefinition.CalculatedField {\r
+    public Object getValue(EntityAdapter anEntityAdapter) {\r
+      EntityAdapter media;\r
+      Entity mediaType;\r
+      RewindableIterator iterator;\r
+      Map result;\r
+      MirMedia mediaHandler;\r
+      String tinyIcon;\r
+      String iconAlt;\r
+\r
+      try {\r
+        iterator = (RewindableIterator) (anEntityAdapter.get("to_uploaded_media"));\r
+        iterator.rewind();\r
+\r
+        tinyIcon = MirGlobal.getConfigProperty("Producer.Icon.TinyText");\r
+        iconAlt = "Text";\r
+\r
+        if (iterator.hasNext()) {\r
+          media = (EntityAdapter) iterator.next();\r
+\r
+          mediaType = ((EntityUploadedMedia) (media.getEntity())).getMediaType();\r
+          mediaHandler = MediaHelper.getHandler( mediaType );\r
+\r
+          if (mediaHandler.isVideo()) {\r
+            tinyIcon = MirGlobal.getConfigProperty("Producer.Icon.TinyVideo");\r
+            iconAlt = "Video";\r
+          }\r
+          else if (mediaHandler.isAudio()) {\r
+            tinyIcon = MirGlobal.getConfigProperty("Producer.Icon.TinyAudio");\r
+            iconAlt = "Audio";\r
+          }\r
+          else if (mediaHandler.isImage()) {\r
+            tinyIcon = MirGlobal.getConfigProperty("Producer.Icon.TinyImage");\r
+            iconAlt = "Image";\r
+          }\r
+          else {\r
+            tinyIcon = mediaHandler.getTinyIcon();\r
+            iconAlt = mediaHandler.getIconAlt();\r
+          }\r
+\r
+        }\r
+      }\r
+      catch (Throwable t) {\r
+        System.out.println("ContentToIconField: exception: " +t.getMessage());\r
+        t.printStackTrace(System.out);\r
+        throw new RuntimeException(t.getMessage());\r
+      }\r
+\r
+      result = new HashMap();\r
+      result.put("tiny_icon", MirGlobal.getConfigProperty("Producer.ImageRoot") + "/" + tinyIcon);\r
+      result.put("icon_alt", iconAlt);\r
+\r
+      return result;\r
+    }\r
+  }\r
+}
\ No newline at end of file
diff --git a/source/mircoders/localizer/basic/MirBasicGeneratorLocalizer.java b/source/mircoders/localizer/basic/MirBasicGeneratorLocalizer.java
new file mode 100755 (executable)
index 0000000..587b4b4
--- /dev/null
@@ -0,0 +1,24 @@
+package mircoders.localizer.basic;
+
+import freemarker.template.*;
+import mir.misc.*;
+import mir.generator.*;
+import mircoders.localizer.*;
+import mircoders.global.*;
+
+public class MirBasicGeneratorLocalizer implements MirGeneratorLocalizer {
+  protected static Logfile logger = Logfile.getInstance( MirGlobal.getConfigProperty("Home") + "/" + MirGlobal.getConfigProperty("Mir.Localizer.Logfile"));
+  private String templateRoot;
+
+  public MirBasicGeneratorLocalizer (String aTemplateRoot) {
+    templateRoot = aTemplateRoot;
+  }
+
+  public Generator.GeneratorLibrary makeGeneratorLibrary() throws MirLocalizerException, MirLocalizerFailure {
+    return new FreemarkerGenerator.FreemarkerGeneratorLibrary(templateRoot);
+  };
+
+  public WriterEngine makeWriterEngine() throws MirLocalizerException, MirLocalizerFailure {
+    return new MirBasicWriterEngine(MirGlobal.getConfigProperty("Mir.DefaultEncoding"));
+  }
+}
diff --git a/source/mircoders/localizer/basic/MirBasicLocalizer.java b/source/mircoders/localizer/basic/MirBasicLocalizer.java
new file mode 100755 (executable)
index 0000000..40eef61
--- /dev/null
@@ -0,0 +1,35 @@
+package mircoders.localizer.basic;
+
+import mir.misc.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
+
+public class MirBasicLocalizer implements MirLocalizer {
+  protected static Logfile logger = Logfile.getInstance( MirGlobal.getConfigProperty("Home") + "/" + MirGlobal.getConfigProperty("Mir.Localizer.Logfile"));
+
+  public MirProducerLocalizer producers() throws MirLocalizerFailure, MirLocalizerException {
+    return new MirBasicProducerLocalizer();
+  }
+
+  public MirGeneratorLocalizer generators() {
+    return new MirBasicGeneratorLocalizer(MirGlobal.getConfigProperty("Home")+MirGlobal.getConfigProperty("HTMLTemplateProcessor.Dir"));
+  }
+
+  public MirOpenPostingLocalizer openPostings() {
+    return new MirBasicOpenPostingLocalizer();
+  }
+
+  public MirProducerAssistantLocalizer producerAssistant() {
+    return new MirBasicProducerAssistantLocalizer();
+  }
+
+  public MirDataModelLocalizer dataModel() {
+    return new MirBasicDataModelLocalizer();
+  };
+
+  public MirAdminInterfaceLocalizer adminInterface() throws MirLocalizerFailure, MirLocalizerException {
+    return new MirBasicAdminInterfaceLocalizer();
+  };
+
+
+}
\ No newline at end of file
diff --git a/source/mircoders/localizer/basic/MirBasicOpenPostingLocalizer.java b/source/mircoders/localizer/basic/MirBasicOpenPostingLocalizer.java
new file mode 100755 (executable)
index 0000000..5e19a34
--- /dev/null
@@ -0,0 +1,43 @@
+package mircoders.localizer.basic;
+
+import java.util.*;
+import javax.servlet.http.*;
+
+import mir.misc.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
+import mircoders.entity.*;
+
+public class MirBasicOpenPostingLocalizer implements MirOpenPostingLocalizer {
+  protected static Logfile logger = Logfile.getInstance( MirGlobal.getConfigProperty("Home") + "/" + MirGlobal.getConfigProperty("Mir.Localizer.Logfile"));
+
+  public void afterContentPosting() {
+    MirGlobal.producerEngine().addJob("media", "new");
+    MirGlobal.producerEngine().addJob("content", "new");
+    MirGlobal.producerEngine().addJob("startpage", "(default)");
+    MirGlobal.producerEngine().addJob("synchronization", "run");
+
+    MirGlobal.producerEngine().addJob("openposting", "new");
+    MirGlobal.producerEngine().addJob("topics", "new");
+    MirGlobal.producerEngine().addJob("synchronization", "run");
+  }
+
+  public void afterContentPosting(EntityContent aContent) {
+    afterContentPosting();
+  }
+  
+  public void afterCommentPosting() {
+    MirGlobal.producerEngine().addJob("content", "new");
+    MirGlobal.producerEngine().addJob("synchronization", "run");
+  }
+
+  public void afterCommentPosting(EntityComment aComment) {
+    afterCommentPosting();
+  }
+
+  public String chooseOpenPostingLanguage(HttpServletRequest req) {
+    Locale locale = req.getLocale();
+
+    return locale.getLanguage();
+  }
+}
diff --git a/source/mircoders/localizer/basic/MirBasicProducerAssistantLocalizer.java b/source/mircoders/localizer/basic/MirBasicProducerAssistantLocalizer.java
new file mode 100755 (executable)
index 0000000..344a812
--- /dev/null
@@ -0,0 +1,86 @@
+package mircoders.localizer.basic;
+
+import java.util.*;
+import java.io.*;
+import freemarker.template.utility.*;
+import mir.misc.*;
+import mir.entity.*;
+import mir.util.*;
+import mircoders.module.*;
+import mircoders.storage.*;
+import mircoders.localizer.*;
+import mircoders.global.*;
+
+public class MirBasicProducerAssistantLocalizer implements MirProducerAssistantLocalizer {
+  protected static Logfile logger = Logfile.getInstance( MirGlobal.getConfigProperty("Home") + "/" + MirGlobal.getConfigProperty("Mir.Localizer.Logfile"));
+
+  public void initializeGenerationValueSet(Map aValueSet) {
+    // ML: these config settings will be included more beautifully as soon as the new config system is in place
+
+    Map configMap = new HashMap();
+    Map utilityMap = new HashMap();
+
+    configMap.put("producerDocRoot", MirGlobal.getConfigProperty("Producer.DocRoot"));
+    configMap.put("storageRoot", MirGlobal.getConfigProperty("Producer.StorageRoot"));
+    configMap.put("productionHost", MirGlobal.getConfigProperty("Producer.ProductionHost"));
+    configMap.put("openAction", MirGlobal.getConfigProperty("Producer.OpenAction"));
+    configMap.put("docRoot", MirGlobal.getConfigProperty("RootUri"));
+    configMap.put("actionRoot", MirGlobal.getConfigProperty("RootUri")+"/servlet/Mir");
+    configMap.put("now", new DateToMapAdapter((new GregorianCalendar()).getTime()));
+    configMap.put("videoHost", MirGlobal.getConfigProperty("Producer.Video.Host"));
+    configMap.put("audioHost", MirGlobal.getConfigProperty("Producer.Audio.Host"));
+    configMap.put("imageHost", MirGlobal.getConfigProperty("Producer.Image.Host"));
+    configMap.put("imagePath", MirGlobal.getConfigProperty("Producer.Image.Path"));
+    configMap.put("mirVersion", MirGlobal.getConfigProperty("Mir.Version"));
+    configMap.put("defEncoding", MirGlobal.getConfigProperty("Mir.DefaultEncoding"));
+    configMap.put("all", Configuration.getConfs());
+
+    utilityMap.put("compressWhitespace", new freemarker.template.utility.CompressWhitespace() );
+    utilityMap.put("encodeHTML", new GeneratorHTMLFunctions.encodeHTMLGeneratorFunction());
+    utilityMap.put("encodeURI", new GeneratorHTMLFunctions.encodeURIGeneratorFunction());
+
+    aValueSet.put("config", configMap);
+    aValueSet.put("utility", utilityMap);
+
+    EntityList topicList=null;
+    EntityList entityList=null;
+    EntityList parentList=null;
+    EntityList languageList=null;
+
+    try {
+//      ModuleLinksImcs linksImcsModule = new ModuleLinksImcs(DatabaseLinksImcs.getInstance());
+      ModuleTopics topicsModule = new ModuleTopics(DatabaseTopics.getInstance());
+      ModuleLanguage languageModule = new ModuleLanguage(DatabaseLanguage.getInstance());
+
+      topicList = topicsModule.getTopicsList();
+//      entityList = linksImcsModule.getByWhereClause("", "sortpriority, title", -1);
+//      parentList = linksImcsModule.getByWhereClause("to_parent_id=NULL", "sortpriority, title", -1);
+      languageList = languageModule.getByWhereClause("", "id", -1);
+    }
+    catch (Throwable t) {
+      logger.printError("initializeGenerationValueSet: Exception "+t.getMessage());
+    }
+
+    aValueSet.put("topics", topicList);
+    aValueSet.put("imclist", entityList);
+    aValueSet.put("parentlist", parentList);
+
+    Map articleTypeMap = new HashMap();
+    articleTypeMap.put("openposting", "0");
+    articleTypeMap.put("newswire", "1");
+    articleTypeMap.put("feature", "2");
+    articleTypeMap.put("topicspecial", "3");
+    articleTypeMap.put("startspecial", "4");
+    aValueSet.put("articletype", articleTypeMap);
+  };
+
+  public String filterText(String aText) {
+    return StringUtil.createHTML(
+        StringUtil.deleteForbiddenTags(aText),
+        MirGlobal.getConfigProperty("Producer.ImageRoot"),
+        MirGlobal.getConfigProperty("Producer.MailLinkName"),
+        MirGlobal.getConfigProperty("Producer.ExtLinkName"),
+        MirGlobal.getConfigProperty("Producer.IntLinkName")
+    );
+  }
+}
diff --git a/source/mircoders/localizer/basic/MirBasicProducerLocalizer.java b/source/mircoders/localizer/basic/MirBasicProducerLocalizer.java
new file mode 100755 (executable)
index 0000000..741d0f1
--- /dev/null
@@ -0,0 +1,142 @@
+package mircoders.localizer.basic;
+
+import java.util.*;
+import java.io.*;
+import mir.producer.*;
+import mir.generator.*;
+import mir.producer.reader.*;
+import mir.misc.*;
+import mir.util.*;
+import mir.entity.adapter.*;
+import mircoders.global.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
+import mircoders.producer.reader.*;
+import mircoders.producer.*;
+
+public class MirBasicProducerLocalizer implements MirProducerLocalizer {
+  private Map producerFactories;
+  protected FileMonitor fileMonitor;
+  protected EntityAdapterModel model;
+  protected Generator.GeneratorLibrary generatorLibrary;
+  protected WriterEngine writerEngine;
+
+  protected static Logfile logger = Logfile.getInstance( MirGlobal.getConfigProperty("Home") + "/" + MirGlobal.getConfigProperty("Mir.Localizer.Logfile"));
+
+  public MirBasicProducerLocalizer() {
+
+    try {
+      producerFactories = new HashMap();
+      model = MirGlobal.localizer().dataModel().adapterModel();
+      generatorLibrary = MirGlobal.localizer().generators().makeGeneratorLibrary();
+      writerEngine = MirGlobal.localizer().generators().makeWriterEngine();
+    }
+    catch (Throwable t) {
+      logger.printError("MirBasicProducerLocalizer(): Exception "+t.getMessage());
+      model = new EntityAdapterModel();
+    }
+  }
+
+  public Map factories() throws MirLocalizerException {
+    if (fileMonitor==null || producerFactories == null || fileMonitor.hasChanged()) {
+      try {
+        Map newProducers = new HashMap();
+        FileMonitor newFileMonitor = new FileMonitor();
+        setupFactories(newProducers, newFileMonitor);
+
+        producerFactories = newProducers;
+        fileMonitor = newFileMonitor;
+      }
+      catch (Throwable t) {
+        logger.printError("MirBasicProducerLocalizer.factories(): Unable to setup factories: "+t.getMessage());
+      }
+    }
+
+    return producerFactories;
+  };
+
+  protected void setupContentFactory(CompositeProducerNode aProducerNode) {
+  }
+
+  protected void setupStartPageFactory(CompositeProducerNode aProducerNode) {
+  }
+
+  protected void setupSynchronizationFactory(CompositeProducerNode aProducerNode) {
+    if(MirGlobal.getConfigBooleanProperty("Rsync")){
+      aProducerNode.addSubNode(
+        new ScriptCallingProducerNode(MirGlobal.getConfigProperty("Rsync.Script.Path"))
+      );
+    }
+  }
+
+  protected void setupStaticFactory(CompositeProducerNode aProducerNode) {
+  }
+
+  protected void setupTopicsFactory(CompositeProducerNode aProducerNode) {
+  }
+
+  protected void setupProducerNodeBuilderLibrary(ProducerNodeBuilderLibrary aLibrary) {
+    DefaultProducerNodeBuilders.registerBuilders(aLibrary, model, generatorLibrary, writerEngine);
+    SupplementalProducerNodeBuilders.registerBuilders(aLibrary, model);
+  }
+
+  protected void setupFactories(Map aFactoriesMap, FileMonitor aFileMonitor) throws MirLocalizerException, MirLocalizerFailure {
+    ProducerConfigReader reader;
+    ProducerNodeBuilderLibrary library = new ProducerNodeBuilderLibrary();
+    setupProducerNodeBuilderLibrary(library);
+    List usedFiles = new Vector();
+
+    aFileMonitor.clear();
+    reader = new ProducerConfigReader();
+    reader.parseFile(MirGlobal.getConfigProperty("Home") + "/" + MirGlobal.getConfigProperty("Mir.Localizer.ProducerConfigFile"), library, aFactoriesMap, usedFiles);
+
+    Iterator i = usedFiles.iterator();
+    while (i.hasNext())
+      aFileMonitor.addFile((File) i.next());
+
+    setupFactories(aFactoriesMap);
+  }
+
+  protected void setupFactories(Map aFactoriesMap ) throws MirLocalizerException, MirLocalizerFailure {
+    CompositeProducerNode node;
+
+    try {
+      node = new CompositeProducerNode();
+      setupContentFactory( node );
+      if (node.getNrSubNodes()>0)
+        aFactoriesMap.put("content", new NodedProducerFactory(node));
+
+      node = new CompositeProducerNode();
+      setupStartPageFactory( node );
+      if (node.getNrSubNodes()>0)
+        aFactoriesMap.put("startpage", new NodedProducerFactory(node));
+
+      node = new CompositeProducerNode();
+      setupSynchronizationFactory( node );
+      if (node.getNrSubNodes()>0)
+        aFactoriesMap.put("synchronization", new NodedProducerFactory(node));
+
+      node = new CompositeProducerNode();
+      setupStaticFactory( node );
+      if (node.getNrSubNodes()>0)
+        aFactoriesMap.put("static", new NodedProducerFactory(node));
+
+      node = new CompositeProducerNode();
+      setupTopicsFactory( node );
+      if (node.getNrSubNodes()>0)
+        aFactoriesMap.put("topics", new NodedProducerFactory(node));
+
+      aFactoriesMap.put("media",
+                   new CompositeProducerFactory( new ProducerFactory[] {
+                      new OldProducerAdapterFactory(new ProducerImages()),
+                      new OldProducerAdapterFactory(new ProducerAudio()),
+                      new OldProducerAdapterFactory(new ProducerVideo()),
+                      new OldProducerAdapterFactory(new ProducerOther())
+                  } )
+      );
+    }
+    catch (Exception e) {
+      throw new MirLocalizerFailure(e);
+    }
+  };
+}
diff --git a/source/mircoders/localizer/basic/MirBasicWriterEngine.java b/source/mircoders/localizer/basic/MirBasicWriterEngine.java
new file mode 100755 (executable)
index 0000000..59f6f90
--- /dev/null
@@ -0,0 +1,47 @@
+package mircoders.localizer.basic;
+
+import java.util.*;
+import java.io.*;
+import mir.generator.*;
+import mircoders.localizer.*;
+
+public class MirBasicWriterEngine implements WriterEngine {
+  private String defaultEncoding;
+
+  public MirBasicWriterEngine(String aDefaultEncoding) {
+    defaultEncoding = aDefaultEncoding;
+  }
+
+  public Object openWriter(String anIdentifier, String anEncoding) throws MirLocalizerFailure {
+    String encoding;
+    File file;
+    File dir;
+
+    if (anEncoding!=null && !anEncoding.equals(""))
+      encoding = anEncoding;
+    else
+      encoding = defaultEncoding;
+//      MirGlobal.getConfigProperty("Mir.DefaultEncoding");
+
+    try {
+      file = new File( anIdentifier );
+      dir = new File(file.getParent());
+        if (dir!=null && !dir.exists()){
+          dir.mkdirs();
+      }
+
+      return new PrintWriter(
+        new OutputStreamWriter(
+          new FileOutputStream(file), encoding
+        )
+      );
+    }
+    catch (Throwable t) {
+      throw new MirLocalizerFailure("Failure while opening a PrintWriter: "+t.getMessage(),t);
+    }
+  };
+
+  public void closeWriter(Object aWriter) {
+    ((PrintWriter) aWriter).close();
+  };
+}
\ No newline at end of file
index 7cb409e..ed8e12c 100755 (executable)
@@ -55,12 +55,12 @@ public class MediaHandlerGeneric implements MirMedia
                             uploadedData);
             //were done with the data, dereference.
             uploadedData=null;
-            
+
             ent.setValueForProperty("publish_path",datePath+"/"+mediaFname);
             ent.setValueForProperty("size", size.toString());
             ent.update();
         } catch (Exception e) {
-            theLog.printError(e.toString()); 
+            theLog.printError(e.toString());
             throw new MirMediaException(e.toString());
         }
 
@@ -69,7 +69,7 @@ public class MediaHandlerGeneric implements MirMedia
 
     public void produce (Entity ent, Entity mediaTypeEnt )
       throws MirMediaException {
-      
+
       //check first if the media file exist since produced
       //location is also the storage location
       String date = ent.getValue("date");
@@ -78,9 +78,9 @@ public class MediaHandlerGeneric implements MirMedia
       String fname = getStoragePath()+relPath;
       if(! new File(fname).exists())
         throw new MirMediaException("error in MirMedia.produce(): "+relPath+
-                                    "does not exist!");
+                                    " does not exist!");
     }
-      
+
 
     //a method that will probably never get used..
     private byte[] getFile (String fileName)
@@ -90,11 +90,11 @@ public class MediaHandlerGeneric implements MirMedia
         if (size < 0) return null;
 
         byte[] container = new byte[(int)size];
-            
+
         try {
             FileUtil.read(fileName, container);
         } catch (Exception e) {
-            theLog.printError(e.toString()); 
+            theLog.printError(e.toString());
             throw new MirMediaException(e.toString());
         }
 
@@ -136,7 +136,7 @@ public class MediaHandlerGeneric implements MirMedia
 
     public String getIconAlt()
     {
-        return "Generic media"; 
+        return "Generic media";
     }
 
     public SimpleList getURL(Entity ent, Entity mediaTypeEnt)
@@ -167,6 +167,6 @@ public class MediaHandlerGeneric implements MirMedia
     }
 
 }
-        
-        
+
+
 
diff --git a/source/mircoders/producer/CompositeProducer.java b/source/mircoders/producer/CompositeProducer.java
new file mode 100755 (executable)
index 0000000..6bd3108
--- /dev/null
@@ -0,0 +1,27 @@
+package mircoders.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.producer.*;
+
+public class CompositeProducer implements mir.producer.Producer {
+
+  List producers;
+
+  public CompositeProducer() {
+    producers = new Vector();
+  }
+
+  public void addProducer(mir.producer.Producer aProducer) {
+    producers.add(aProducer);
+  }
+
+  public void produce( PrintWriter aLogger ) throws ProducerFailure, ProducerExc {
+    Iterator i;
+
+    i=producers.iterator();
+
+    while (i.hasNext())
+      ((mir.producer.Producer) i.next()).produce(aLogger);
+  }
+}
diff --git a/source/mircoders/producer/CompositeProducerFactory.java b/source/mircoders/producer/CompositeProducerFactory.java
new file mode 100755 (executable)
index 0000000..4019537
--- /dev/null
@@ -0,0 +1,62 @@
+package mircoders.producer;
+
+import java.util.*;
+import mir.entity.*;
+import mir.producer.*;
+
+public class CompositeProducerFactory implements ProducerFactory {
+  Map factories;          // verb -> Vector ( ProducerFactory )
+
+  public CompositeProducerFactory() {
+    factories = new HashMap();
+  }
+
+  public CompositeProducerFactory(ProducerFactory[] aSubProducerFactories) {
+    this();
+
+    int i;
+
+    for (i=0; i<aSubProducerFactories.length; i++) {
+      addFactory(aSubProducerFactories[i]);
+    }
+  }
+
+  private List factoriesForVerb(String aVerb) {
+    List result;
+
+    result=(List) factories.get(aVerb);
+
+    if (result==null) {
+      result=new Vector();
+
+      factories.put(aVerb, result);
+    }
+
+    return result;
+  }
+
+  public void addFactory(ProducerFactory aFactory) {
+    Iterator i;
+
+    i=aFactory.verbs();
+
+    while (i.hasNext()) {
+      factoriesForVerb((String) i.next()).add(aFactory);
+    }
+  }
+
+  public mir.producer.Producer makeProducer(String aVerb, Map aBasicValueSet) throws ProducerExc, ProducerFailure {
+    CompositeProducer result = new CompositeProducer();
+
+    Iterator i=factoriesForVerb(aVerb).iterator();
+
+    while (i.hasNext())
+      result.addProducer(((ProducerFactory) i.next()).makeProducer(aVerb, aBasicValueSet));
+
+    return result;
+  }
+
+  public Iterator verbs() {
+    return factories.keySet().iterator();
+  }
+}
diff --git a/source/mircoders/producer/ContentMarkingProducerNode.java b/source/mircoders/producer/ContentMarkingProducerNode.java
new file mode 100755 (executable)
index 0000000..30ffa73
--- /dev/null
@@ -0,0 +1,48 @@
+package mircoders.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.util.*;
+import mir.producer.*;
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.entity.*;
+
+
+public class ContentMarkingProducerNode implements ProducerNode {
+  private String contentKey;
+
+  public ContentMarkingProducerNode(String aContentKey) {
+    contentKey = aContentKey;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    Object data;
+    Entity entity;
+
+    try {
+      data = ParameterExpander.findValueForKey( aValueMap, contentKey );
+
+      if (! (data instanceof EntityAdapter)) {
+        throw new ProducerFailure("ContentMarkingProducerNode: value of '"+contentKey+"' is not an EntityAdapter, but an " + data.getClass().getName(), null);
+      }
+
+      entity = ((EntityAdapter) data).getEntity();
+      if (! (entity instanceof EntityContent)) {
+        throw new ProducerFailure("ContentMarkingProducerNode: value of '"+contentKey+"' is not a content EntityAdapter, but a " + entity.getClass().getName() + " adapter", null);
+      }
+
+      ((EntityContent) entity).setProduced(true);
+    }
+    catch (Throwable t) {
+      aLogger.println("Error while marking content: " + t.getMessage());
+      t.printStackTrace(aLogger);
+
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  }
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
\ No newline at end of file
diff --git a/source/mircoders/producer/ContentModifyingProducerNode.java b/source/mircoders/producer/ContentModifyingProducerNode.java
new file mode 100755 (executable)
index 0000000..0939b2e
--- /dev/null
@@ -0,0 +1,65 @@
+package mircoders.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.util.*;
+import mir.producer.*;
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.entity.*;
+import mircoders.module.*;
+import mircoders.storage.*;
+
+
+public class ContentModifyingProducerNode implements ProducerNode {
+  private String contentKey;
+  private String fieldNameExpression;
+  private String valueExpression;
+
+  public ContentModifyingProducerNode(String aContentKey, String aFieldNameExpression, String aValueExpression) {
+    contentKey = aContentKey;
+    fieldNameExpression = aFieldNameExpression;
+    valueExpression = aValueExpression;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    Object data;
+    Entity entity;
+    String value;
+    String fieldName;
+
+    try {
+      ModuleContent contentModule = new ModuleContent(DatabaseContent.getInstance());
+
+      data = ParameterExpander.findValueForKey( aValueMap, contentKey );
+
+      if (! (data instanceof EntityAdapter)) {
+        throw new ProducerFailure("ContentModifyingProducerNode: value of '"+contentKey+"' is not an EntityAdapter, but an " + data.getClass().getName(), null);
+      }
+
+      entity = ((EntityAdapter) data).getEntity();
+      if (! (entity instanceof EntityContent)) {
+        throw new ProducerFailure("ContentModifyingProducerNode: value of '"+contentKey+"' is not a content EntityAdapter, but a " + entity.getClass().getName() + " adapter", null);
+      }
+
+      value = ParameterExpander.expandExpression(aValueMap, valueExpression);
+      fieldName = ParameterExpander.expandExpression(aValueMap, fieldNameExpression);
+
+      entity.setValueForProperty("is_produced", "0");
+      entity.setValueForProperty(fieldName, value);
+      entity.update();
+
+      aLogger.println("  Modified content " + entity.get("id") + ": " + fieldName + " = " + value );
+    }
+    catch (Throwable t) {
+      aLogger.println("Error while modifying content: " + t.getMessage());
+      t.printStackTrace(aLogger);
+
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  }
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
diff --git a/source/mircoders/producer/IndexingProducerNode.java b/source/mircoders/producer/IndexingProducerNode.java
new file mode 100755 (executable)
index 0000000..2396fb1
--- /dev/null
@@ -0,0 +1,143 @@
+package mircoders.producer;
+
+import java.util.*;
+import java.io.*;
+
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.index.*;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+
+import freemarker.template.*;
+
+
+import mir.util.*;
+import mir.producer.*;
+//import mir.generator.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.entity.*;
+import mircoders.storage.*;
+
+
+public class IndexingProducerNode implements ProducerNode {
+  private String contentKey;
+  private String indexPath;
+
+
+  public IndexingProducerNode(String aContentKey, String pathToIndex) {
+    contentKey = aContentKey;
+    indexPath=pathToIndex;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    IndexWriter indexWriter;
+    Object data;
+    Entity entity;
+
+    long startTime;
+    long endTime;
+
+    startTime = System.currentTimeMillis();
+
+    try {
+      data = ParameterExpander.findValueForKey( aValueMap, contentKey );
+
+      if (! (data instanceof EntityAdapter)) {
+        throw new ProducerFailure("IndexingProducerNode: value of '"+contentKey+"' is not an EntityAdapter, but an " + data.getClass().getName(), null);
+      }
+
+      entity = ((EntityAdapter) data).getEntity();
+      if (! (entity instanceof EntityContent)) {
+        throw new ProducerFailure("IndexingProducerNode: value of '"+contentKey+"' is not a content EntityAdapter, but a " + entity.getClass().getName() + " adapter", null);
+      }
+      aLogger.println("Indexing " + (String) entity.getValue("id") + " into " + indexPath);
+      aLogger.flush();
+
+      IndexReader indexReader = IndexReader.open(indexPath);
+      indexReader.delete(new Term("id",entity.getValue("id")));
+      indexReader.close();
+
+      indexWriter = new IndexWriter(indexPath, new StandardAnalyzer(), false);
+      Document theDoc =  new Document();
+
+      // Keyword is stored and indexed, but not tokenized
+      // Text is tokenized,stored, indexed
+      // Unindexed is not tokenized or indexed, only stored
+      // Unstored is tokenized and indexed, but not stored
+
+      theDoc.add(Field.Keyword("id",entity.getValue("id")));
+      theDoc.add(Field.Keyword("where",entity.getValue("publish_path")+entity.getValue("id")+".shtml"));
+      theDoc.add(Field.Text("creator",entity.getValue("creator")));
+      theDoc.add(Field.Text("title",entity.getValue("title")));
+      theDoc.add(Field.Keyword("webdb_create",entity.getValue("webdb_create_formatted")));
+      theDoc.add(Field.UnStored("content_and_description",entity.getValue("description")+entity.getValue("content_data")));
+
+      //topics
+      TemplateModel topics=entity.get("to_topics");
+      aLogger.println("THE CLASS NAME WAS: "+entity.get("to_topics").getClass().getName());
+      while (((TemplateListModel)topics).hasNext()){
+          theDoc.add(Field.UnStored("topic",((TemplateHashModel)((TemplateListModel)topics).next()).get("title").toString()));
+      }
+
+
+      //media
+
+      //images
+      TemplateModel images=entity.get("to_media_images");
+      if (images != null){
+          theDoc.add(Field.UnStored("media","images"));
+      }
+      //audio
+      TemplateModel audio=entity.get("to_media_audio");
+      if (audio != null){
+          theDoc.add(Field.UnStored("media","audio"));
+      }
+      //video
+      TemplateModel video=entity.get("to_media_video");
+      if (video != null){
+          theDoc.add(Field.UnStored("media","video"));
+      }
+
+      //comments-just aggregate all relevant fields
+      String commentsAggregate = "";
+      TemplateModel comments=entity.get("to_comments");
+      if (comments != null){
+        while (((TemplateListModel)comments).hasNext()){
+          TemplateModel aComment = ((TemplateListModel)comments).next();
+          commentsAggregate = commentsAggregate + " " + ((TemplateHashModel)aComment).get("title").toString()
+            + " " + ((TemplateHashModel)aComment).get("creator").toString()
+            + " " + ((TemplateHashModel)aComment).get("text").toString();
+        }
+      }
+      theDoc.add(Field.UnStored("comments",commentsAggregate));
+
+      indexWriter.addDocument(theDoc);
+      indexWriter.close();
+
+    }
+    catch (Throwable t) {
+      aLogger.println("Error while indexing content: " + t.getMessage());
+      t.printStackTrace(aLogger);
+      //should remove index lock here.....jd
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+
+
+
+
+    endTime = System.currentTimeMillis();
+
+    aLogger.println("  IndexTime: " + (endTime-startTime) + " ms<br>");
+    aLogger.flush();
+  }
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
+
+
+
diff --git a/source/mircoders/producer/MediaGeneratingProducerNode.java b/source/mircoders/producer/MediaGeneratingProducerNode.java
new file mode 100755 (executable)
index 0000000..5f19248
--- /dev/null
@@ -0,0 +1,62 @@
+package mircoders.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.util.*;
+import mir.misc.*;
+import mir.media.*;
+import mir.producer.*;
+import mir.generator.*;
+import mir.entity.*;
+import mir.entity.adapter.*;
+//import mircoders.global.*;
+//import mircoders.localizer.*;
+import mircoders.entity.*;
+import mircoders.storage.*;
+
+public class MediaGeneratingProducerNode implements ProducerNode {
+  private String mediaEntityKey;
+
+  public MediaGeneratingProducerNode(String aMediaEntityKey) {
+    mediaEntityKey = aMediaEntityKey;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    Object data;
+    Entity entity;
+    Entity currentMediaType;
+    MirMedia currentMediaHandler;
+
+    try {
+      data = ParameterExpander.findValueForKey( aValueMap, mediaEntityKey );
+
+      if (!(data instanceof EntityAdapter)) {
+        throw new ProducerFailure("MediaGeneratingProducerNode: value of '"+mediaEntityKey+"' is not an EntityAdapter, but an " + data.getClass().getName(), null);
+      }
+
+      entity = ((EntityAdapter) data).getEntity();
+      if (! (entity instanceof EntityUploadedMedia)) {
+        throw new ProducerFailure("MediaGeneratingProducerNode: value of '"+mediaEntityKey+"' is not an uploaded media EntityAdapter, but a " + entity.getClass().getName() + " adapter", null);
+      }
+
+      currentMediaType = DatabaseUploadedMedia.getInstance().getMediaType(entity);
+
+      currentMediaHandler = MediaHelper.getHandler( currentMediaType );
+      currentMediaHandler.produce(entity,currentMediaType);
+      entity.setValueForProperty("publish_server", currentMediaHandler.getPublishHost());
+      entity.setValueForProperty("icon_is_produced", "1");
+      entity.setValueForProperty("is_produced", "1");
+      entity.update();
+    }
+    catch (Throwable t) {
+      aLogger.println("Error while generating media: " + t.getMessage());
+      t.printStackTrace(aLogger);
+
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  }
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
diff --git a/source/mircoders/producer/OldProducerAdapter.java b/source/mircoders/producer/OldProducerAdapter.java
new file mode 100755 (executable)
index 0000000..65656fc
--- /dev/null
@@ -0,0 +1,24 @@
+package mircoders.producer;
+
+import mir.producer.*;
+import java.io.*;
+
+public class OldProducerAdapter implements mir.producer.Producer {
+
+  private mircoders.producer.Producer oldProducer;
+  private Boolean forced;
+
+  public OldProducerAdapter( mircoders.producer.Producer anOldProducer, Boolean aForced ) {
+    oldProducer = anOldProducer;
+    forced = aForced;
+  }
+
+  public void produce( PrintWriter aLogger ) throws ProducerFailure {
+    try {
+      oldProducer.handle( aLogger, null, forced.booleanValue(), false );
+    }
+    catch (Throwable e) {
+      throw new ProducerFailure("Failure at handling old Producers",e);
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mircoders/producer/OldProducerAdapterFactory.java b/source/mircoders/producer/OldProducerAdapterFactory.java
new file mode 100755 (executable)
index 0000000..4d5cea0
--- /dev/null
@@ -0,0 +1,25 @@
+package mircoders.producer;
+
+import mir.producer.*;
+import java.util.*;
+
+public class OldProducerAdapterFactory implements ProducerFactory {
+
+  private mircoders.producer.Producer oldProducer;
+
+  public Iterator verbs() {
+    Vector verbList = new Vector();
+
+    verbList.add("new");
+    verbList.add("all");
+    return verbList.iterator();
+  }
+
+  public OldProducerAdapterFactory(mircoders.producer.Producer anOldProducer) {
+    oldProducer = anOldProducer;
+  }
+
+  public mir.producer.Producer makeProducer(String aVerb, Map anInitialValues) {
+    return new OldProducerAdapter(oldProducer, new Boolean(aVerb.equals("all")));
+  }
+}
\ No newline at end of file
diff --git a/source/mircoders/producer/PDFGeneratingProducerNode.java b/source/mircoders/producer/PDFGeneratingProducerNode.java
new file mode 100755 (executable)
index 0000000..4585604
--- /dev/null
@@ -0,0 +1,51 @@
+package mircoders.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.util.*;
+import mir.producer.*;
+import mir.misc.PDFUtil;
+
+public class PDFGeneratingProducerNode implements ProducerNode {
+  private String generatorExpression;
+  private String destinationExpression;
+
+  public PDFGeneratingProducerNode(String aGenerator, String aDestination) {
+    generatorExpression=aGenerator;
+    destinationExpression=aDestination;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+
+    String generatorIdentifier;
+    String destinationIdentifier;
+
+          long startTime;
+          long endTime;
+
+          startTime = System.currentTimeMillis();
+    try {
+
+      destinationIdentifier = ParameterExpander.expandExpression( aValueMap, destinationExpression );
+      generatorIdentifier = ParameterExpander.expandExpression( aValueMap, generatorExpression );
+
+      aLogger.println("Generating " + generatorIdentifier + " into " + destinationIdentifier);
+      aLogger.flush();
+
+      PDFUtil.makePDF(generatorIdentifier,destinationIdentifier);
+
+        }
+        catch (Throwable t) {
+          aLogger.println("  error while generating: " + t.getMessage());
+      aLogger.flush();
+    }
+    endTime = System.currentTimeMillis();
+
+    aLogger.println("  Time: " + (endTime-startTime) + " ms<br>");
+    aLogger.flush();
+  }
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
diff --git a/source/mircoders/producer/ProducerAll.java b/source/mircoders/producer/ProducerAll.java
deleted file mode 100755 (executable)
index f98c0fa..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-package mircoders.producer;
-
-import java.io.*;
-import java.lang.*;
-import java.util.*;
-
-import freemarker.template.*;
-
-import mir.misc.*;
-import mir.storage.*;
-import mir.module.*;
-import mir.entity.*;
-
-import mircoders.module.*;
-import mircoders.entity.*;
-import mircoders.storage.*;
-
-
-public class ProducerAll extends Producer{
-
-       private boolean rsync;
-
-       public static void main(String argv[])
-       {
-               try {   new ProducerAll().handle(new PrintWriter(System.out), null, false,false);       }
-               catch(Exception e) { System.err.println(e.toString()); }
-       }
-
-       // handle all
-       public void handle(PrintWriter htmlout, EntityUsers user, boolean force,boolean sync)
-    {
-               printHTML(htmlout, "Producer.All: started");
-
-               long                sessionConnectTime = 0;
-               long                startTime = (new java.util.Date()).getTime();
-    
-        try {
-            new ProducerImages().handle(htmlout, user, force,sync);
-        } catch (Exception e) {
-            logHTML(htmlout, "Producer.All <font color=\"red\">ERROR:</font>"
-                +" in ProducerImages continuing "+ e.toString());
-        }
-        try {
-            new ProducerAudio().handle(htmlout, user, force,sync);
-        } catch (Exception e) {
-            logHTML(htmlout, "Producer.All <font color=\"red\">ERROR:</font>"
-                +" in ProducerAudio continuing "+ e.toString());
-        }
-        try {
-            new ProducerVideo().handle(htmlout, user, force,sync);
-        } catch (Exception e) {
-            logHTML(htmlout, "Producer.All <font color=\"red\">ERROR:</font>"
-                +" in ProducerVideo continuing "+ e.toString());
-        }
-        try {
-            new ProducerOther().handle(htmlout, user, force,sync);
-        } catch (Exception e) {
-            logHTML(htmlout, "Producer.All <font color=\"red\">ERROR:</font>"
-                +" in ProducerOther continuing "+ e.toString());
-        }
-        try {
-            new ProducerStartPage().handle(htmlout, user, force,sync);
-        } catch (Exception e) {
-            logHTML(htmlout, "Producer.All <font color=\"red\">ERROR:</font>"
-                +" in Producer.StartPage continuing "+ e.toString());
-        }
-        try {
-            new ProducerContent().handle(htmlout, user, force,sync);
-        } catch (Exception e) {
-            logHTML(htmlout, "Producer.All <font color=\"red\">ERROR:</font>"
-                +" in Producer.Content continuing "+ e.toString());
-        }
-        try {
-            new ProducerOpenPosting().handle(htmlout, user, force,sync);
-        } catch (Exception e) {
-            logHTML(htmlout, "Producer.All <font color=\"red\">ERROR:</font>"
-                +" in Producer.OpenPosting continuing "+ e.toString());
-        }
-        try {
-            new ProducerTopics().handle(htmlout, user, force,sync);
-        } catch (Exception e) {
-            logHTML(htmlout, "Producer.All <font color=\"red\">ERROR:</font>"
-                +" in Producer.Topics continuing "+ e.toString());
-        }
-        try {
-            new ProducerNavigation().handle(htmlout, user, force,sync);
-        } catch (Exception e) {
-            logHTML(htmlout, "Producer.All <font color=\"red\">ERROR:</font>"
-                +" in Producer.Navigation continuing "+ e.toString());
-        }
-
-               // Finish
-               sessionConnectTime = new java.util.Date().getTime() - startTime;
-               logHTML(htmlout, "Producer.All finished: " + sessionConnectTime + " ms.");
-
-               // do we have to rsync the site
-               if (sync==true){
-                       sessionConnectTime = 0;
-                       if (Helper.rsync()!=0){
-                               sessionConnectTime = new java.util.Date().getTime() - startTime;
-                               logHTML(htmlout, "Rsync failed: " + sessionConnectTime + " ms.");
-                       } else {
-                               sessionConnectTime = new java.util.Date().getTime() - startTime;
-                               logHTML(htmlout, "Rsync succeded: " + sessionConnectTime + " ms.");
-                       }
-               }
-       }
-
-       // handle all
-       public void handle2(PrintWriter htmlout, EntityUsers user, boolean force,boolean sync)
-               throws StorageObjectException, ModuleException {
-               printHTML(htmlout, "Producer.All: started");
-
-               long                sessionConnectTime = 0;
-               long                startTime = (new java.util.Date()).getTime();
-               EntityContent   currentContent;
-
-               //get all new unproduced content-entities
-               String whereClause="is_produced='0' && to_article_type>0";
-               String orderBy="date desc";
-               EntityList entityList = contentModule.getContent(whereClause,orderBy,0,-1,null);
-
-               //get their values
-               while (entityList != null) {
-                       for(int i=0;i<entityList.size();i++) {
-                               currentContent = (EntityContent)entityList.elementAt(i);
-                               EntityList topicEntityList = DatabaseContentToTopics.getInstance().getTopics(currentContent);
-                               SimpleHash topicHash = HTMLTemplateProcessor.makeSimpleHash(topicEntityList);
-
-                               try {
-                                       //check if this content item is related to a topic
-                                       if(currentContent.getId().equals(topicHash.get("content_id"))){
-                                               // produce the ToicsList
-                                               new ProducerTopics().handle(htmlout, user, force,sync,topicHash.get("topic_id").toString());
-                                       }
-                               } catch (TemplateModelException e) {
-                                       logHTML(htmlout, e.toString());
-                               }
-                       }
-               }
-
-               new ProducerContent().handle(htmlout, user, force,sync);
-               new ProducerOpenPosting().handle(htmlout, user, force,sync);
-               new ProducerStartPage().handle(htmlout, user, force,sync);
-               new ProducerTopics().handle(htmlout, user, force,sync);
-
-               // Finish
-               sessionConnectTime = new java.util.Date().getTime() - startTime;
-               logHTML(htmlout, "Producer.All finished: " + sessionConnectTime + " ms.");
-       }
-}
-
diff --git a/source/mircoders/producer/ProducerContent.java b/source/mircoders/producer/ProducerContent.java
deleted file mode 100755 (executable)
index a4e14a5..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-package mircoders.producer;
-
-import java.io.*;
-import java.lang.*;
-import java.util.*;
-
-import freemarker.template.*;
-
-import mir.misc.*;
-import mir.storage.*;
-import mir.module.*;
-import mir.entity.*;
-
-import mircoders.entity.*;
-import mircoders.storage.*;
-
-//for pdf production
-import org.apache.fop.apps.* ;
-import org.xml.sax.InputSource;
-import org.xml.sax.XMLReader;
-import org.apache.log.*;
-
-public class ProducerContent extends Producer {
-
-       private String contentTemplate=MirConfig.getProp("Producer.Content.Template");
-       private String contentPrintableTemplate=MirConfig.getProp("Producer.PrintableContent.Template");
-       private String html2foStyleSheetName=MirConfig.getProp("Producer.PrintableContent.html2foStyleSheetName");
-       private String generateFO=MirConfig.getProp("GenerateFO");
-       private String generatePDF=MirConfig.getProp("GeneratePDF");
-       private String producerStorageRoot=MirConfig.getProp("Producer.StorageRoot");
-       private Logger fopLog=null;
-       private String templateDir = MirConfig.getPropWithHome("HTMLTemplateProcessor.Dir");
-       
-       public static void main(String argv[]){
-               //Configuration.initConfig("config");
-               System.out.println(MirConfig.getProp("Producer.DocRoot"));
-
-               try {
-                       new ProducerContent().handle(new PrintWriter(System.out), null,
-                                                                                                                                               false,false);
-               } catch(Exception e) {
-                       System.err.println(e.toString());
-               }
-       }
-
-       public void handle(PrintWriter htmlout, EntityUsers user, boolean force,
-                                                                               boolean sync)
-               throws StorageObjectException, ModuleException {
-
-               handle(htmlout,user,force,sync,null);
-       }
-
-       public void handle(PrintWriter htmlout, EntityUsers user, boolean force,
-                                                                                boolean sync, String id) throws StorageObjectException,
-                                                                                ModuleException
-       {
-
-               long                startTime = System.currentTimeMillis();
-               int                 pageCount=0;
-
-               String              whereClause = " ";
-               String              orderBy = " ";
-               String              htmlFileName = null;
-               String              foFileName = null;
-               String              pdfFileName = null;
-               EntityContent       currentContent;
-               EntityList          batchEntityList;
-               EntityUsers         userEntity=null;
-
-               int                 contentBatchsize =
-                                               Integer.parseInt(MirConfig.getProp("Producer.Content.Batchsize"));
-               // production of the content-pages
-
-               /** @todo this should be moved to ModuleContent */
-               orderBy="date desc, webdb_lastchange desc";
-               if(force==true){
-                       whereClause="is_published='1'";
-                       // if true: produces a single content item
-                       if(id !=null){
-                               whereClause += " AND id="+id;
-                               // I think this avoids a select count(*)...
-                               contentBatchsize=-1;
-                       }
-                       batchEntityList = contentModule.getContent(whereClause, orderBy, 0,
-                                                                                                                                                                                               contentBatchsize, userEntity);
-               } else {
-                       whereClause="is_produced='0' AND is_published='1'";
-                       //if true produces a single contentitem
-                       if(id !=null){
-                               whereClause += " AND id="+id;
-                               // this avoids a select count(*)...
-                               contentBatchsize=-1;
-                       }
-                       batchEntityList = contentModule.getContent(whereClause, orderBy, 0,
-                                                                                                                                                                                               contentBatchsize, userEntity);
-               }
-
-               while (batchEntityList!=null) {
-                       for(int i=0;i<batchEntityList.size();i++) {
-                               currentContent = (EntityContent)batchEntityList.elementAt(i);
-
-                               try {
-
-                                       SimpleHash mergeData=new SimpleHash();
-                                       mergeData.put("content", currentContent);
-
-                                       /** @todo this should be assembled in entity */
-                                       String date = currentContent.getValue("date");
-                                       String year = date.substring(0,4);
-                                       String month = date.substring(4,6);
-                                       htmlFileName =  "/" + year + "/" + month + "/" +
-                                                                                                       currentContent.getValue("id") + ".shtml";
-                                       
-                                       //produce html
-                                       boolean retVal = produce(contentTemplate, htmlFileName, mergeData, htmlout);
-                                       if ( retVal ) currentContent.setProduced(true);
-                                       
-                                       //produce xsl:fo and pdf version(if desired)
-                                       if (generateFO.toLowerCase().equals("yes")){
-            foFileName =  "/" + year + "/" + month + "/"
-                          + currentContent.getValue("id") + ".fo";
-            boolean foRetVal = produce(contentPrintableTemplate, foFileName,
-                                        mergeData, htmlout, "UTF8");
-                                       
-            if (generatePDF.toLowerCase().equals("yes")){
-              pdfFileName =  producerStorageRoot + "/" + year
-                              + "/" + month + "/"
-                              + currentContent.getValue("id") + ".pdf";
-              Driver driver = new Driver();
-                                               
-              Hierarchy hierarchy = Hierarchy.getDefaultHierarchy();
-              fopLog = hierarchy.getLoggerFor("fop");
-              fopLog.setPriority(Priority.WARN);
-                                               
-              driver.setLogger(fopLog);
-              driver.setRenderer(Driver.RENDER_PDF);
-              File foFile=new File(producerStorageRoot + foFileName);
-              File html2foStyleSheet=new File(templateDir+"/"
-                                              +html2foStyleSheetName);
-              InputHandler inputHandler =
-                new XSLTInputHandler(foFile, html2foStyleSheet);
-              XMLReader parser = inputHandler.getParser();
-              driver.setOutputStream(new FileOutputStream(pdfFileName));
-              driver.render(parser, inputHandler.getInputSource());
-            }
-                                       }
-                               } catch(Exception e) {
-                                       String errorText = "Producer.Content <font color=red>ERROR</font> while producing content ID:"
-                                                                               + currentContent.getId()+", skipping it :: "+e.toString();
-                                       logHTML(htmlout, errorText);
-                                       theLog.printError(errorText);
-                                       e.printStackTrace();
-                               }
-                               pageCount++;
-                       }//for
-                       // if next batch get it...
-                       if (batchEntityList.hasNextBatch()){
-                               batchEntityList = contentModule.getContent(whereClause, orderBy,
-                                                                                                                                                               batchEntityList.getNextBatch(),
-                                                                                                                                                               contentBatchsize, userEntity);
-                       } else {
-                               batchEntityList=null;
-                       }
-               }
-               logHTMLFinish(htmlout, "Content", pageCount, startTime, System.currentTimeMillis());
-               /** @todo why no syncing here? */
-       }
-}
-
diff --git a/source/mircoders/producer/ProducerFeature.java b/source/mircoders/producer/ProducerFeature.java
deleted file mode 100755 (executable)
index fad6184..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-package mircoders.producer;
-
-import java.io.*;
-import java.lang.*;
-import java.util.*;
-import java.sql.*;
-
-import freemarker.template.*;
-
-import mir.misc.*;
-import mir.storage.*;
-import mir.module.*;
-import mir.entity.*;
-
-import mircoders.module.*;
-import mircoders.entity.*;
-import mircoders.storage.*;
-
-
-
-public class ProducerFeature extends ProducerList {
-
-  public void handle(PrintWriter htmlout, EntityUsers user, boolean force, boolean sync)
-               throws StorageObjectException, ModuleException {
-               orderBy="date desc";
-               listTemplate = MirConfig.getProp("Producer.FeatureList.Template");
-               EntityList featureEntityList = featureModule.getByWhereClause("","title", -1);
-               boolean first=true;
-               whereClause="is_published!=true AND to_article_type=0 AND id IN (";
-               for(int i=0; i < featureEntityList.size(); i++){
-
-            try {
-                EntityTopics currentTopic = (EntityTopics)featureEntityList.elementAt(i);
-                EntityList contentEntityList = DatabaseContentToTopics.getInstance().getContent(currentTopic);
-                if(first==false) {
-                    whereClause += ",";
-                }
-                whereClause += currentTopic.getId();
-                fileDesc = currentTopic.getValue("filename").trim();
-                setAdditional("topic",currentTopic);
-            } catch (Exception e) {
-                logHTML(htmlout, "problem with feature skipping");
-            }
-
-                       first = false;
-               }
-               whereClause += ")";
-               handleIt(htmlout,user,force);
-       }
-
-  public static void main(String argv[]){
-    try {
-      new ProducerOpenPosting().handle(new PrintWriter(System.out), null,false, false);
-    } catch(Exception e) {
-      System.err.println(e.toString());
-    }
-  }
-}
diff --git a/source/mircoders/producer/ProducerList.java b/source/mircoders/producer/ProducerList.java
deleted file mode 100755 (executable)
index c3d134c..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-package mircoders.producer;
-
-import java.io.*;
-import java.lang.*;
-import java.lang.reflect.*;
-import java.util.*;
-import java.sql.*;
-
-import freemarker.template.*;
-
-import mir.misc.*;
-import mir.media.*;
-import mir.storage.*;
-import mir.module.*;
-import mir.entity.*;
-
-import mircoders.module.*;
-import mircoders.entity.*;
-import mircoders.storage.*;
-
-
-
-abstract public class ProducerList extends Producer {
-
-  public String listTemplate;
-  public String whereClause;
-  public String orderBy;
-  public String fileDesc;
-  protected HashMap additional = new HashMap();
-
-
-
-  public void handle(PrintWriter htmlout, EntityUsers user, boolean sync, boolean force)
-    throws StorageObjectException, ModuleException {
-    handleIt(htmlout,user,force);
-  }
-
-  /** @todo this should return the number of pages produced! */
-  public void handleIt(PrintWriter htmlout, EntityUsers user, boolean force)
-    throws StorageObjectException, ModuleException {
-
-    logHTML(htmlout, "Producer.List: started");
-    int newsPerPage = Integer.parseInt(MirConfig.getProp("Producer.StartPage.Newswire"));
-    long                sessionConnectTime = 0;
-    long                startTime = (new java.util.Date()).getTime();
-    String              htmlFileName = "";
-    String              currentMediaId;
-    EntityContent       currentContent;
-    EntityList          list;
-    EntityUsers         userEntity=null;
-    SimpleHash          imageHash = new SimpleHash();
-    int size = 0;
-    int listSize = 0;
-
-    int maxItemsOnPage = Integer.parseInt(MirConfig.getProp("Lists.Max.Items"));
-
-    try {
-      listSize = contentModule.getSize(whereClause);
-    } catch (Exception e) {
-      logHTML(htmlout,e.toString());
-    }
-
-    int modRest = listSize % maxItemsOnPage;
-    int numberOfPages = (listSize - modRest) / maxItemsOnPage;
-    boolean first=true;
-    for (int i = 0;i < numberOfPages+1;i ++) {
-      //break the loop, if only athe actuell pages should be produced
-      if (force == false && i==3) {
-        break;
-      }
-      //break, if only the first page has to be produced
-      if (force == false && modRest != 0 && first==false){
-        break;
-      }
-
-
-      if (first==true) {
-        //get the data for the first page
-        size=maxItemsOnPage + modRest;
-        list = contentModule.getContent(whereClause, orderBy, 0, size, userEntity);
-        first=false;
-      } else {
-        //get the data for the other pages
-        list = contentModule.getContent(whereClause, orderBy, size, maxItemsOnPage, userEntity);
-        size = size + maxItemsOnPage;
-      }
-
-      //now produce the pages
-      if (list!=null || force==true) {
-        SimpleHash mergeData = HTMLTemplateProcessor.makeSimpleHashWithEntitylistInfos(list);
-        //process hashmap additional and add to mergedata
-        if (additional != null) {
-          Set set = additional.keySet();
-          for (Iterator it = set.iterator();it.hasNext();) {
-            String key = (String)it.next();
-            mergeData.put(key,(TemplateModel)additional.get(key));
-          }
-        }
-
-        if (i==0){
-          htmlFileName = "/" + fileDesc + ".shtml";
-          mergeData.put("filename",fileDesc + ".shtml");
-          mergeData.put("previousPage","");
-          if(numberOfPages<=1){
-            mergeData.put("nextPage","");
-          } else {
-            mergeData.put("nextPage",fileDesc + (numberOfPages-1) + ".shtml");
-          }
-        } else {
-          if (i==1 && numberOfPages > 2){
-            mergeData.put("previousPage",fileDesc + ".shtml");
-            mergeData.put("nextPage",fileDesc + (numberOfPages-2) + ".shtml");
-          } else {
-            if (i==(numberOfPages-1)){
-              mergeData.put("previousPage",fileDesc + (numberOfPages-i+1) + ".shtml");
-              mergeData.put("nextPage","");
-            } else {
-              mergeData.put("previousPage",fileDesc + (numberOfPages-(i-1)) + ".shtml");
-              mergeData.put("nextPage",fileDesc + (numberOfPages-(i+1)) + ".shtml");
-            }
-          }
-          htmlFileName = "/" + fileDesc + (numberOfPages-i) + ".shtml";
-          mergeData.put("filename",fileDesc + (numberOfPages-i) + ".shtml");
-        }
-
-        //producing the html-files
-        boolean retVal = produce(listTemplate, htmlFileName, mergeData, htmlout);
-      } //end if
-    }//end for
-
-    sessionConnectTime = new java.util.Date().getTime() - startTime;
-    logHTML(htmlout, "Producer.List finished: " + sessionConnectTime + " ms.");
-  } //end handle
-
-  public void setAdditional(String key, TemplateModel value) {
-    additional.put(key,value);
-  }
-
-}
index a44dc43..efb0f76 100755 (executable)
@@ -76,6 +76,7 @@ abstract public class ProducerMedia extends Producer {
                             e.toString());
           logHTML(htmlout, "problem with media id: "+currentMedia.getId()+
                   " <font color=\"Red\"> failed!</font>: "+e.toString());
+          e.printStackTrace(htmlout);
         }
       }
 
diff --git a/source/mircoders/producer/ProducerNavigation.java b/source/mircoders/producer/ProducerNavigation.java
deleted file mode 100755 (executable)
index 2d8d1a8..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-package mircoders.producer;
-
-import java.io.*;
-import java.lang.*;
-import java.util.*;
-
-import freemarker.template.*;
-
-import mir.misc.*;
-import mir.storage.*;
-import mir.module.*;
-import mir.entity.*;
-
-import mircoders.entity.*;
-
-/**
- * Title:        mir - another content management system
- * Description:
- * Copyright:    Copyright (c) 2001
- * Company:      indymedia
- * @author idefix
- * @version 1.0
- */
-
-public class ProducerNavigation extends Producer {
-
-  private static String naviPageTemplate = MirConfig.getProp("Producer.Navigation.Template");
-
-  public void handle(PrintWriter htmlout, EntityUsers user, boolean forced, boolean sync)
-    throws mir.module.ModuleException, mir.storage.StorageObjectException {
-
-        printHTML(htmlout, "Producer.Navigation: started");
-
-               long                sessionConnectTime = 0;
-               long                startTime = (new java.util.Date()).getTime();
-               String              nowWebdbDate = StringUtil.date2webdbDate(new GregorianCalendar());
-               String              whereClause;
-               String              orderBy;
-               FileWriter          outputFile;
-               String              htmlFileName;
-               EntityContent       currentContent;
-               EntityList          entityList;
-               SimpleHash          naviPageModel;
-
-        // get the imclinks
-        entityList = linksImcsModule.getByWhereClause("", "sortpriority, title", -1);
-        EntityList theParentList = linksImcsModule.getByWhereClause("to_parent_id=NULL", "sortpriority, title", -1);
-
-               // put the informations into the navipagemodel
-               naviPageModel = new SimpleHash();
-               naviPageModel.put("topics", topicsModule.getTopicsList());
-        naviPageModel.put("imclist", entityList);
-        naviPageModel.put("parentlist", theParentList);
-
-               htmlFileName = "/navigation.inc";
-
-               produce(naviPageTemplate, htmlFileName, naviPageModel, new LineFilterWriter(htmlout));
-
-               // Finish
-               sessionConnectTime = new java.util.Date().getTime() - startTime;
-               logHTML(htmlout, "Producer.Navigation finished: " + sessionConnectTime + " ms.");
-
-               if(sync==true){
-                       Helper.rsync();
-                       logHTML(htmlout, "Producer.Startseite: rsync done");
-               }
-       }
-
-}
diff --git a/source/mircoders/producer/ProducerOpenPosting.java b/source/mircoders/producer/ProducerOpenPosting.java
deleted file mode 100755 (executable)
index 1278d63..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-package mircoders.producer;
-
-import java.io.*;
-import java.lang.*;
-import java.util.*;
-import java.sql.*;
-
-import freemarker.template.*;
-
-import mir.misc.*;
-import mir.storage.*;
-import mir.module.*;
-import mir.entity.*;
-
-import mir.module.*;
-import mircoders.entity.*;
-import mir.storage.*;
-
-
-
-public class ProducerOpenPosting extends ProducerList {
-
-
-
-  public void handle(PrintWriter htmlout, EntityUsers user, boolean force, boolean sync)
-    throws StorageObjectException, ModuleException
-  {
-    listTemplate = MirConfig.getProp("Producer.OpenPosting.Template");
-    whereClause="is_published='1'";
-    orderBy="date desc, webdb_create desc";
-    fileDesc="open";
-
-    setAdditional("topicslist",topicsModule.getTopicsList());
-    setAdditional("title",new SimpleScalar("Open-Posting"));
-    handleIt(htmlout,user,force);
-  }
-
-
-  public static void main(String argv[]){
-    try {
-      new ProducerOpenPosting().handle(new PrintWriter(System.out), null,false, false);
-    } catch(Exception e) {
-      System.err.println(e.toString());
-    }
-  }
-
-}
diff --git a/source/mircoders/producer/ProducerStartPage.java b/source/mircoders/producer/ProducerStartPage.java
deleted file mode 100755 (executable)
index e2185ad..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-package mircoders.producer;
-
-import java.io.*;
-import java.util.*;
-
-import freemarker.template.*;
-
-import mir.entity.*;
-import mir.misc.*;
-import mir.module.*;
-import mir.storage.*;
-import mircoders.module.*;
-import mircoders.storage.*;
-import mircoders.entity.*;
-
-
-public class ProducerStartPage extends Producer {
-
-  private static String startPageTemplate = MirConfig.getProp("Producer.StartPage.Template");
-  private static String featuresRSSTemplate = MirConfig.getProp("Producer.FeaturesRSS.Template");
-  private static int itemsPerPage = Integer.parseInt(MirConfig.getProp("Producer.StartPage.Items"));
-  private static int newsPerPage = Integer.parseInt(MirConfig.getProp("Producer.StartPage.Newswire"));
-
-  public static void main(String argv[]){
-    try {
-      // Why are we reloading the configuration here?
-      // is there something I'm missing?
-      // mh. <heckmann@hbe.ca>
-      // Configuration.initConfig(argv[0]);
-      new ProducerStartPage().handle(new PrintWriter(System.out), null);
-    } catch(Exception e) {
-      System.err.println(e.toString());
-    }
-  }
-
-  public void handle(PrintWriter htmlout, EntityUsers user, boolean force,boolean sync)
-    throws StorageObjectException, ModuleException
-  {
-    long    startTime = System.currentTimeMillis();
-    printHTML(htmlout, "Producer.StartPage: started");
-    SimpleHash startPageModel = new SimpleHash();
-
-    // breaking news
-    ModuleBreaking breakingModule = new ModuleBreaking(DatabaseBreaking.getInstance());
-    startPageModel.put("breakingnews", breakingModule.getBreakingNews());
-    startPageModel.put("topics", topicsModule.getTopicsList());
-    startPageModel.put("newswire", contentModule.getNewsWire(0,newsPerPage));
-    startPageModel.put("startspecial", contentModule.getStartArticle());
-    startPageModel.put("features", contentModule.getFeatures(0,itemsPerPage));
-    startPageModel.put("dc_now", new SimpleScalar(StringUtil.date2w3DateTime(new GregorianCalendar())));
-
-
-    /* @todo switch to compressed */
-    produce(startPageTemplate, "/index.shtml", startPageModel, htmlout);
-    
-    /* should be mandatory in light of new www.indy newswire.
-     *  but remember Mir is not indy specific. -mh. 
-     *  Also should it really always be produced in UTF8 chars -mh? 
-     */
-    produce(featuresRSSTemplate, "/features.1-0.rdf", startPageModel, htmlout, "UTF8");
-
-    // finished
-    logHTMLFinish(htmlout, "Startpage", 1, startTime, System.currentTimeMillis());
-
-    if(sync==true){
-      logHTML(htmlout, "Producer.Startpage: rsyncing...");
-      Helper.rsync();
-      printHTML(htmlout, "Producer.Startpage: rsync done");
-    }
-  }
-}
-
diff --git a/source/mircoders/producer/ProducerTopics.java b/source/mircoders/producer/ProducerTopics.java
deleted file mode 100755 (executable)
index 1f1a32b..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-package mircoders.producer;
-
-import java.io.*;
-import java.lang.*;
-import java.lang.reflect.*;
-import java.util.*;
-import java.sql.*;
-
-import freemarker.template.*;
-
-import mir.misc.*;
-import mir.media.*;
-import mir.storage.*;
-import mir.module.*;
-import mir.entity.*;
-
-import mircoders.entity.*;
-import mircoders.storage.*;
-
-
-
-public class ProducerTopics extends ProducerList {
-
-  public String where;
-  String              currentMediaId;
-  EntityList          upMediaEntityList;
-  EntityList          imageEntityList;
-  EntityList          currentMediaList;
-  Entity              mediaType;
-  EntityMedia         uploadedMedia;
-  Class               mediaHandlerClass=null;
-  MirMedia            mediaHandler=null;
-  String              mediaHandlerName=null;
-  Database            mediaStorage=null;
-  String              tinyIcon;
-  String              iconAlt;
-
-  public void handle(PrintWriter htmlout, EntityUsers user, boolean force, boolean sync, String id)
-    throws StorageObjectException, ModuleException {
-    where=id;
-    handle(htmlout,user,force,sync);
-  }
-
-  public void handle(PrintWriter htmlout, EntityUsers user, boolean force, boolean sync)
-    throws StorageObjectException, ModuleException
-  {
-    long startTime = System.currentTimeMillis();
-    int pageCount =0;
-    logHTML(htmlout, "Producer.Topics: started");
-
-    /** @todo should be done in static */
-    listTemplate = MirConfig.getProp("Producer.TopicList.Template");
-
-    orderBy="date desc, webdb_create desc";
-    EntityList topicsEntityList;
-    if(where==null){
-      topicsEntityList = topicsModule.getByWhereClause("","title", -1);
-    } else {
-      topicsEntityList = topicsModule.getByWhereClause(where,"title", -1);
-    }
-
-    for(int i=0; i < topicsEntityList.size(); i++){
-
-      EntityTopics currentTopic = (EntityTopics)topicsEntityList.elementAt(i);
-
-      try {
-      EntityList contentEntityList = DatabaseContentToTopics.getInstance().getContent(currentTopic);
-      String whereClauseSpecial=null;
-
-      if (contentEntityList!=null || force==true) {
-        if (contentEntityList!=null){
-          boolean first=true;
-          whereClause="is_published='1' AND to_article_type >= 0 AND to_article_type <=2 AND id IN (";
-          whereClauseSpecial="is_published='1' AND to_article_type=3 AND id IN (";
-          for(int j=0; j < contentEntityList.size(); j++){
-            if(first==false) {
-              whereClause += ",";
-              whereClauseSpecial += ",";
-            }
-            EntityContent currentContent = (EntityContent)contentEntityList.elementAt(j);
-            whereClause += currentContent.getId();
-            whereClauseSpecial += currentContent.getId();
-
-            setAdditional("topic",currentTopic);
-
-            first = false;
-          }
-          whereClause += ")";
-          whereClauseSpecial += ")";
-        }
-
-        if(contentEntityList==null && force==true){
-          //hihi, das ist eigentlich boese
-          whereClause="is_published='1' AND to_article_type>=0 AND id IN (0)";
-        }
-
-        fileDesc = currentTopic.getValue("filename");
-
-        // get the startarticle
-        EntityList entityList = contentModule.getContent(whereClauseSpecial,"date desc, webdb_create desc",0,1);
-        String currentMediaId = null;
-        SimpleHash imageHash = new SimpleHash();
-        EntityContent currentContent;
-        if(entityList != null && entityList.size()==1){
-          currentContent = (EntityContent)entityList.elementAt(0);
-          try {
-              setAdditional("special",currentContent);
-          } catch (Exception e) {
-            theLog.printError("ProducerTopics: problem with start special media: "+currentContent.getId()+" "+e.toString()+" <font color=\"red\">skipping</font>");
-            logHTML(htmlout,"ProducerTopics: problem with start special media: "+currentContent.getId()+" "+e.toString());
-          }
-        }
-
-        //set the list of topics
-        setAdditional("topicslist",topicsEntityList);
-
-        handleIt(htmlout,user,force);
-        pageCount++;
-      }
-      } catch (Exception e) {
-        theLog.printError("ProducerTopics: problem with start special media: "
-        +e.toString()+" <font color=\"red\">skipping</font>");
-        logHTML(htmlout,"ProducerTopics: problem with topic id: "
-        +currentTopic.getId()+ "<font color=\"red\">skipping</font>");
-      }
-    }
-    logHTMLFinish(htmlout, "Topics", pageCount, startTime, System.currentTimeMillis());
-  }
-
-  public static void main(String argv[]){
-    try {
-      new ProducerOpenPosting().handle(new PrintWriter(System.out), null,false, false);
-    } catch(Exception e) {
-      System.err.println(e.toString());
-    }
-  }
-}
diff --git a/source/mircoders/producer/reader/SupplementalProducerNodeBuilders.java b/source/mircoders/producer/reader/SupplementalProducerNodeBuilders.java
new file mode 100755 (executable)
index 0000000..9c71ec8
--- /dev/null
@@ -0,0 +1,77 @@
+package mircoders.producer.reader;
+
+import java.util.*;
+import mir.producer.*;
+import mir.producer.reader.*;
+import mir.util.*;
+import mir.entity.adapter.*;
+import mir.generator.*;
+import mircoders.producer.*;
+
+public class SupplementalProducerNodeBuilders {
+
+  public static void registerBuilders(ProducerNodeBuilderLibrary aBuilderLibrary, EntityAdapterModel aModel) {
+    aBuilderLibrary.registerBuilder("ModifyContent", ContentModifyingProducerNodeBuilder.class);
+    aBuilderLibrary.registerBuilder("MarkContent", ContentMartkingProducerNodeBuilder.class);
+  }
+
+  public static class ContentMartkingProducerNodeBuilder extends DefaultProducerNodeBuilders.AbstractProducerNodeBuilder {
+    private final static String   MARKER_KEY_ATTRIBUTE = DefaultProducerNodeBuilders.KEY_ATTRIBUTE;
+    private final static String[] MARKER_REQUIRED_ATTRIBUTES = { MARKER_KEY_ATTRIBUTE };
+    private final static String[] MARKER_OPTIONAL_ATTRIBUTES = {};
+    private final static String[] MARKER_SUBNODES = {};
+
+    private String key;
+
+    public ContentMartkingProducerNodeBuilder() {
+      super(MARKER_SUBNODES);
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributes(anAttributes, MARKER_REQUIRED_ATTRIBUTES, MARKER_OPTIONAL_ATTRIBUTES);
+
+      key = (String) anAttributes.get(MARKER_KEY_ATTRIBUTE);
+    };
+
+    public ProducerNode constructNode() {
+      return new ContentMarkingProducerNode(key);
+    };
+  }
+
+
+  public static class ContentModifyingProducerNodeBuilder extends DefaultProducerNodeBuilders.AbstractProducerNodeBuilder {
+    private final static String   MODIFYER_KEY_ATTRIBUTE = DefaultProducerNodeBuilders.KEY_ATTRIBUTE;
+    private final static String   MODIFYER_FIELD_ATTRIBUTE = "field";
+    private final static String   MODIFYER_VALUE_ATTRIBUTE = "value";
+    private final static String[] MODIFYER_REQUIRED_ATTRIBUTES = { MODIFYER_KEY_ATTRIBUTE, MODIFYER_FIELD_ATTRIBUTE, MODIFYER_VALUE_ATTRIBUTE };
+    private final static String[] MODIFYER_OPTIONAL_ATTRIBUTES = {};
+    private final static String[] MODIFYER_SUBNODES = {};
+
+    private String key;
+    private String field;
+    private String value;
+
+    public ContentModifyingProducerNodeBuilder() {
+      super(MODIFYER_SUBNODES);
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc {
+      ReaderTool.checkAttributes(anAttributes, MODIFYER_REQUIRED_ATTRIBUTES, MODIFYER_OPTIONAL_ATTRIBUTES);
+
+      key = (String) anAttributes.get(MODIFYER_KEY_ATTRIBUTE);
+      field = (String) anAttributes.get(MODIFYER_FIELD_ATTRIBUTE);
+      value = (String) anAttributes.get(MODIFYER_VALUE_ATTRIBUTE);
+    };
+
+    public ProducerNode constructNode() {
+      return new ContentModifyingProducerNode(key, field, value);
+    };
+  }
+
+
+/*
+  TODO:
+        [ ] Media Producing
+*/
+
+}
\ No newline at end of file
index dc5383d..57f225f 100755 (executable)
@@ -6,6 +6,7 @@ import java.util.*;
 import java.net.*;
 import javax.servlet.*;
 import javax.servlet.http.*;
+import org.apache.struts.util.MessageResources;
 
 import freemarker.template.*;
 
@@ -14,9 +15,14 @@ import mir.module.*;
 import mir.misc.*;
 import mir.entity.*;
 import mir.storage.*;
-
+import mir.generator.*;
 import mir.entity.*;
+import mir.entity.adapter.*;
+import mir.util.*;
+
 import mircoders.storage.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
 import mircoders.module.*;
 
 /*
@@ -29,98 +35,205 @@ import mircoders.module.*;
 public class ServletModuleComment extends ServletModule
 {
 
-       private ModuleContent     moduleContent;
-
-       // Singelton / Kontruktor
-       private static ServletModuleComment instance = new ServletModuleComment();
-       public static ServletModule getInstance() { return instance; }
-
-       private ServletModuleComment() {
-               theLog = Logfile.getInstance(MirConfig.getProp("Home") + MirConfig.getProp("ServletModule.Comment.Logfile"));
-               templateListString = MirConfig.getProp("ServletModule.Comment.ListTemplate");
-               templateObjektString = MirConfig.getProp("ServletModule.Comment.ObjektTemplate");
-               templateConfirmString = MirConfig.getProp("ServletModule.Comment.ConfirmTemplate");
-               try {
-                       mainModule = new ModuleComment(DatabaseComment.getInstance());
-                       moduleContent = new ModuleContent(DatabaseContent.getInstance());
-               }
-               catch (StorageObjectException e) {
-                       theLog.printError("servletmodule: comment could not be initialized");
-               }
-       }
-
-
-       public void list(HttpServletRequest req, HttpServletResponse res)
-               throws ServletModuleException
-       {
-                       // Parameter auswerten
-                       SimpleHash mergeData = new SimpleHash();
-                       String query_text = req.getParameter("query_text");
-                       mergeData.put("query_text",query_text);
-                       if (query_text!=null) mergeData.put("query_text_encoded",URLEncoder.encode(query_text));
-                       String query_field = req.getParameter("query_field");
-                       mergeData.put("query_field",query_field);
-                       String query_is_published = req.getParameter("query_is_published");
-                       mergeData.put("query_is_published",query_is_published);
-
-                       String offset = req.getParameter("offset");
-                       if (offset==null || offset.equals("")) offset="0";
-                       mergeData.put("offset",offset);
-
-                       // patching order
-                       String order = req.getParameter("order");
-                       if(order!=null) {
-                               mergeData.put("order", order);
-                               mergeData.put("order_encoded", URLEncoder.encode(order));
-                               if (order.equals("webdb_create")) order="webdb_create desc";
-                       }
-
-                       // sql basteln
-                       String whereClause=""; boolean isFirst=true;
-                       if (query_text!=null && !query_text.equalsIgnoreCase("")) {
-                               whereClause += "lower("+query_field+") like lower('%"+query_text+"%')"; isFirst=false;}
-                       if (query_is_published != null && !query_is_published.equals("")) {
-                               if (isFirst==false) whereClause+=" and ";
-                               whereClause += "is_published='"+query_is_published+"'";
-                               isFirst=false;
-                       }
-
-                       theLog.printDebugInfo("sql-whereclause: " + whereClause + " order: " + order + " offset: " + offset);
-
-                       // fetch und ausliefern
-                       try {
-
-                               if (query_text!=null || query_is_published!=null ) {
-                                       EntityList theList = mainModule.getByWhereClause(whereClause, order, (new Integer(offset)).intValue());
-                                       if (theList!=null && theList.size()>0) {
-
-                                               //make articleHash for comment
-                                               StringBuffer buf= new StringBuffer("id in (");boolean first=true;
-                                               for(int i=0;i<theList.size();i++) {
-                                                       if (first==false) buf.append(",");
-                                                       first=false;
-                                                       buf.append(theList.elementAt(i).getValue("to_media"));
-                                               }
-                                               buf.append(")");
-                                               SimpleHash articleHash = HTMLTemplateProcessor.makeSimpleHash(moduleContent.getByWhereClause(buf.toString(),-1));
-                                               mergeData.put("articleHash", articleHash);
-
-                                               // get comment
-                                               mergeData.put("contentlist",theList);
-                                               mergeData.put("count", (new Integer(theList.getCount())).toString());
-                                               mergeData.put("from", (new Integer(theList.getFrom())).toString());
-                                               mergeData.put("to", (new Integer(theList.getTo())).toString());
-                                               if (theList.hasNextBatch())
-                                                       mergeData.put("next", (new Integer(theList.getNextBatch())).toString());
-                                               if (theList.hasPrevBatch())
-                                                       mergeData.put("prev", (new Integer(theList.getPrevBatch())).toString());
-                                       }
-                               }
-                               // raus damit
-                               HTMLTemplateProcessor.process(res, templateListString, mergeData, res.getWriter(), getLocale(req));
-                       }
-                       catch (ModuleException e) {throw new ServletModuleException(e.toString());}
-                       catch (IOException e) {throw new ServletModuleException(e.toString());}
-                       catch (Exception e) {throw new ServletModuleException(e.toString());}
-       }
+  private ModuleContent     moduleContent;
+
+  // Singelton / Kontruktor
+  private static ServletModuleComment instance = new ServletModuleComment();
+  public static ServletModule getInstance() { return instance; }
+
+  private ServletModuleComment() {
+    theLog = Logfile.getInstance(MirConfig.getProp("Home") + MirConfig.getProp("ServletModule.Comment.Logfile"));
+    templateListString = MirConfig.getProp("ServletModule.Comment.ListTemplate");
+    templateObjektString = MirConfig.getProp("ServletModule.Comment.ObjektTemplate");
+    templateConfirmString = MirConfig.getProp("ServletModule.Comment.ConfirmTemplate");
+    try {
+      mainModule = new ModuleComment(DatabaseComment.getInstance());
+      moduleContent = new ModuleContent(DatabaseContent.getInstance());
+    }
+    catch (StorageObjectException e) {
+      theLog.printError("servletmodule: comment could not be initialized");
+    }
+  }
+
+  public void list(HttpServletRequest req, HttpServletResponse res)
+      throws ServletModuleException
+  {
+    // Parameter auswerten
+    SimpleHash mergeData = new SimpleHash();
+    String query_text = req.getParameter("query_text");
+    mergeData.put("query_text",query_text);
+    if (query_text!=null) mergeData.put("query_text_encoded",URLEncoder.encode(query_text));
+    String query_field = req.getParameter("query_field");
+    mergeData.put("query_field",query_field);
+    String query_is_published = req.getParameter("query_is_published");
+    mergeData.put("query_is_published",query_is_published);
+
+    String offset = req.getParameter("offset");
+    if (offset==null || offset.equals("")) offset="0";
+    mergeData.put("offset",offset);
+
+    // patching order
+    String order = req.getParameter("order");
+    if(order!=null) {
+      mergeData.put("order", order);
+      mergeData.put("order_encoded", URLEncoder.encode(order));
+      if (order.equals("webdb_create")) order="webdb_create desc";
+    }
+
+    // sql basteln
+    String whereClause=""; boolean isFirst=true;
+    if (query_text!=null && !query_text.equalsIgnoreCase("")) {
+    whereClause += "lower("+query_field+") like lower('%"+query_text+"%')"; isFirst=false;}
+    if (query_is_published != null && !query_is_published.equals("")) {
+      if (isFirst==false) whereClause+=" and ";
+      whereClause += "is_published='"+query_is_published+"'";
+      isFirst=false;
+    }
+
+    theLog.printDebugInfo("sql-whereclause: " + whereClause + " order: " + order + " offset: " + offset);
+
+    // fetch und ausliefern
+    try {
+
+      if (query_text!=null || query_is_published!=null ) {
+        EntityList theList = mainModule.getByWhereClause(whereClause, order, (new Integer(offset)).intValue());
+        if (theList!=null && theList.size()>0) {
+
+          //make articleHash for comment
+          StringBuffer buf= new StringBuffer("id in (");boolean first=true;
+          for(int i=0;i<theList.size();i++) {
+            if (first==false) buf.append(",");
+            first=false;
+            buf.append(theList.elementAt(i).getValue("to_media"));
+          }
+          buf.append(")");
+          SimpleHash articleHash = HTMLTemplateProcessor.makeSimpleHash(moduleContent.getByWhereClause(buf.toString(),-1));
+          mergeData.put("articleHash", articleHash);
+
+          // get comment
+          mergeData.put("contentlist",theList);
+          mergeData.put("count", (new Integer(theList.getCount())).toString());
+          mergeData.put("from", (new Integer(theList.getFrom())).toString());
+          mergeData.put("to", (new Integer(theList.getTo())).toString());
+          if (theList.hasNextBatch())
+            mergeData.put("next", (new Integer(theList.getNextBatch())).toString());
+          if (theList.hasPrevBatch())
+            mergeData.put("prev", (new Integer(theList.getPrevBatch())).toString());
+        }
+      }
+      // raus damit
+      HTMLTemplateProcessor.process(res, templateListString, mergeData, res.getWriter(), getLocale(req));
+    }
+    catch (ModuleException e) {throw new ServletModuleException(e.toString());}
+    catch (IOException e) {throw new ServletModuleException(e.toString());}
+    catch (Exception e) {throw new ServletModuleException(e.toString());}
+  }
+
+  public void showArticleCommentList(Object aWriter, int anOffset, int anArticleId, Locale aLocale) throws ServletModuleException {
+    int nrCommentsPerPage = 20;
+
+    Object comments;
+    Map generationData;
+    Generator generator;
+    int totalNrComments;
+    EntityAdapterModel model;
+    MessageResources messages = MessageResources.getMessageResources("bundles.admin");
+
+    try {
+      generator = MirGlobal.localizer().generators().makeGeneratorLibrary().makeGenerator("admin/commentlist2.template");
+      model = MirGlobal.localizer().dataModel().adapterModel();
+
+//    commentList = mainModule.getByWhereClause(whereClause, order, offset);
+
+      generationData = new HashMap();
+      MirGlobal.localizer().producerAssistant().initializeGenerationValueSet(generationData);
+
+      comments =
+        new CachingRewindableIterator(
+          new EntityIteratorAdapter( "to_media = " + anArticleId,
+               "webdb_create desc",
+               nrCommentsPerPage,
+               model,
+              "comment",
+              nrCommentsPerPage,
+              anOffset
+          )
+        );
+
+      totalNrComments = model.getMappingForName("comment").getStorage().getSize("to_media = " + anArticleId);
+
+      generationData.put( "comments", comments);
+      generationData.put( "offset", new Integer(anOffset));
+      generationData.put( "articleid", new Integer(anArticleId));
+      generationData.put( "lang", new MessageMethodModel(aLocale, messages) );
+      generationData.put( "thisurl", "module=Comment&do=listarticlecomments&offset="+anOffset+"&articleid="+anArticleId);
+
+      if (anOffset>0) {
+        generationData.put( "previousurl", "module=Comment&do=listarticlecomments&offset="+
+                            Math.max( 0, anOffset - nrCommentsPerPage )+"&articleid="+anArticleId);
+        generationData.put("previous", new Integer(Math.max( 0, anOffset - nrCommentsPerPage )));
+      }
+
+      if (anOffset + nrCommentsPerPage < totalNrComments) {
+        generationData.put( "nexturl", "module=Comment&do=listarticlecomments&offset="+
+                            Math.min( anOffset + nrCommentsPerPage, totalNrComments-1 )+"&articleid="+anArticleId);
+        generationData.put("next", new Integer(Math.min( anOffset + nrCommentsPerPage, totalNrComments-1 )));
+      }
+
+      generator.generate(aWriter, generationData, new PrintWriter(new NullWriter()));
+    }
+    catch (Throwable t) {
+      t.printStackTrace(System.out);
+      throw new ServletModuleException(t.getMessage());
+    }
+  }
+
+  public void listarticlecomments(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException
+  {
+    String articleIdString = req.getParameter("articleid");
+    String offsetString = req.getParameter("offset");
+    int offset = 0;
+    int articleId = 0;
+
+    try {
+      offset = Integer.parseInt(offsetString);
+    }
+    catch (Throwable t) {
+    }
+
+    try {
+      articleId  = Integer.parseInt(articleIdString);
+
+      showArticleCommentList( res.getWriter(), offset, articleId, getLocale(req));
+    }
+    catch (ServletModuleException e) {
+      throw e;
+    }
+    catch (Throwable e) {
+      e.printStackTrace(System.out);
+      throw new ServletModuleException(e.getMessage());
+    }
+  }
+
+  public void performarticlecommentsoperation(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException {
+    String commentIdString = req.getParameter("commentid");
+    String articleIdString = req.getParameter("articleid");
+    String offsetString = req.getParameter("offset");
+    String operation = req.getParameter("operation");
+    int offset = 0;
+    int articleId = 0;
+
+    try {
+      articleId  = Integer.parseInt(articleIdString);
+
+      showArticleCommentList( res.getWriter(), offset, articleId, getLocale(req));
+    }
+    catch (ServletModuleException e) {
+      throw e;
+    }
+    catch (Throwable e) {
+      e.printStackTrace(System.out);
+      throw new ServletModuleException(e.getMessage());
+    }
+  }
 }
index 9871d94..627efc9 100755 (executable)
@@ -26,10 +26,13 @@ import mircoders.entity.*;
  *  ServletModuleContent -
  *  deliver html for the article admin form.
  *
- * @version $Revision: 1.19 $
+ * @version $Revision: 1.20 $
  * @author $Author: mh $
  *
  * $Log: ServletModuleContent.java,v $
+ * Revision 1.20  2002/08/25 19:00:11  mh
+ * merge of localization branch into HEAD. mh and zap
+ *
  * Revision 1.19  2002/07/20 22:24:25  mh
  * made the add() method use _showObject. Fixes a bug that cause the popUps not to show up when adding an article in the admin
  *
@@ -166,8 +169,12 @@ public class ServletModuleContent extends ServletModule
         withValues.put("is_published","0");
       if (!withValues.containsKey("is_html"))
         withValues.put("is_html","0");
-      if (withValues.get("creator").toString().equals(""))
-        withValues.put("creator","Anonym");
+
+//      ML: this is not multi-language friendly and this can be done in a template
+//      if (withValues.get("creator").toString().equals(""))
+//        withValues.put("creator","Anonym");
+
+
       String id = mainModule.add(withValues);
       DatabaseContentToTopics.getInstance().setTopics(id,req.getParameterValues("to_topic"));
       //theLog.printDebugInfo(":: content :: inserted");
@@ -317,8 +324,11 @@ public class ServletModuleContent extends ServletModule
         withValues.put("is_published","0");
       if (!withValues.containsKey("is_html"))
         withValues.put("is_html","0");
-      if (withValues.get("creator").toString().equals(""))
-        withValues.put("creator","Anonym");
+
+//      ML: this is not multi-language friendly and this can be done in a template
+//      if (withValues.get("creator").toString().equals(""))
+//        withValues.put("creator","Anonym");
+
       //theLog.printDebugInfo("updating. ");
       String id = mainModule.set(withValues);
       DatabaseContentToTopics.getInstance().setTopics(req.getParameter("id"),topic_id);
diff --git a/source/mircoders/servlet/ServletModuleLocalizer.java b/source/mircoders/servlet/ServletModuleLocalizer.java
new file mode 100755 (executable)
index 0000000..9c58d9f
--- /dev/null
@@ -0,0 +1,41 @@
+package mircoders.servlet;
+
+import java.util.*;
+
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+import mir.servlet.*;
+import mir.entity.adapter.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
+import mircoders.storage.*;
+import mircoders.entity.*;
+
+public class ServletModuleLocalizer extends ServletModule {
+  private static ServletModuleLocalizer instance = new ServletModuleLocalizer();
+
+  public static ServletModule getInstance() { return instance; }
+
+  public void commentoperation(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException
+  {
+    try {
+      String operationKey = req.getParameter("operation");
+      String commentId = req.getParameter("commentid");
+      EntityComment comment = (EntityComment) DatabaseComment.getInstance().selectById(commentId);
+      MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =
+          (MirAdminInterfaceLocalizer.MirSimpleEntityOperation)
+          MirGlobal.localizer().adminInterface().simpleCommentOperations().get(operationKey);
+
+      EntityAdapter adapter = MirGlobal.localizer().dataModel().adapterModel().makeEntityAdapter("comment", comment);
+
+      operation.perform( adapter );
+
+      res.sendRedirect(req.getParameter("returnuri"));
+    }
+    catch (Throwable t) {
+      t.printStackTrace(System.out);
+      throw new ServletModuleException(t.getMessage());
+    }
+  }
+}
\ No newline at end of file
index 2b8e463..b244ac9 100755 (executable)
@@ -34,6 +34,8 @@ import mircoders.storage.*;
 import mircoders.module.*;
 import mircoders.producer.*;
 import mircoders.media.MediaRequest;
+import mircoders.global.*;
+import mircoders.localizer.*;
 
 /*
  *  ServletModuleOpenIndy -
@@ -42,9 +44,12 @@ import mircoders.media.MediaRequest;
  *    open-postings to the newswire
  *
  * @author $Author: mh $
- * @version $Revision: 1.38 $ $Date: 2002/07/21 22:50:14 $
+ * @version $Revision: 1.39 $ $Date: 2002/08/25 19:00:11 $
  *
  * $Log: ServletModuleOpenIndy.java,v $
+ * Revision 1.39  2002/08/25 19:00:11  mh
+ * merge of localization branch into HEAD. mh and zap
+ *
  * Revision 1.38  2002/07/21 22:50:14  mh
  * cleanup coding style of getpdf() method
  *
@@ -65,6 +70,7 @@ public class ServletModuleOpenIndy extends ServletModule
   private String        postingFormTemplate, postingFormDoneTemplate,
                         postingFormDupeTemplate;
   private ModuleContent contentModule;
+  private ModuleComment commentModule;
   private ModuleImages  imageModule;
   private ModuleTopics  themenModule;
   private String        directOp ="yes";
@@ -83,13 +89,13 @@ public class ServletModuleOpenIndy extends ServletModule
       postingFormDoneTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingDoneTemplate");
       postingFormDupeTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingDupeTemplate");
       directOp = MirConfig.getProp("DirectOpenposting").toLowerCase();
-                       passwdProtection = MirConfig.getProp("PasswdProtection").toLowerCase();
+      passwdProtection = MirConfig.getProp("PasswdProtection").toLowerCase();
       mainModule = new ModuleComment(DatabaseComment.getInstance());
       contentModule = new ModuleContent(DatabaseContent.getInstance());
       themenModule = new ModuleTopics(DatabaseTopics.getInstance());
       imageModule = new ModuleImages(DatabaseImages.getInstance());
       defaultAction="addposting";
-                       
+
     }
     catch (StorageObjectException e) {
         theLog.printError("servletmoduleopenindy could not be initialized");
@@ -104,19 +110,27 @@ public class ServletModuleOpenIndy extends ServletModule
   public void addcomment(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException
   {
     String aid = req.getParameter("aid"); // the article id the comment will belong to
+    String language = req.getParameter("language");
+
     if (aid!=null && !aid.equals(""))
     {
-                       SimpleHash mergeData = new SimpleHash();
-
-                       // onetimepasswd
-                       if(passwdProtection.equals("yes")){
-                               String passwd = this.createOneTimePasswd();
-                               System.out.println(passwd);
-                               HttpSession session = req.getSession(false);
-                               session.setAttribute("passwd",passwd);
-                               mergeData.put("passwd", passwd);
-                       }
-                       
+      SimpleHash mergeData = new SimpleHash();
+
+      // onetimepasswd
+      if(passwdProtection.equals("yes")){
+        String passwd = this.createOneTimePasswd();
+        System.out.println(passwd);
+        HttpSession session = req.getSession(false);
+        session.setAttribute("passwd",passwd);
+        mergeData.put("passwd", passwd);
+      }
+
+      if (language!=null) {
+        HttpSession session = req.getSession(false);
+        session.setAttribute("Locale", new Locale(language, ""));
+        session.setAttribute("passwd",language);
+      }
+
       mergeData.put("aid", aid);
       deliver(req, res, mergeData, commentFormTemplate);
     }
@@ -129,7 +143,7 @@ public class ServletModuleOpenIndy extends ServletModule
    */
 
   public void inscomment(HttpServletRequest req, HttpServletResponse res)
-       throws ServletModuleException,ServletModuleUserException
+  throws ServletModuleException,ServletModuleUserException
   {
     String aid = req.getParameter("to_media"); // the article id the comment will belong to
     if (aid!=null && !aid.equals(""))
@@ -137,44 +151,50 @@ public class ServletModuleOpenIndy extends ServletModule
       // ok, collecting data from form
       try {
         HashMap withValues = getIntersectingValues(req, DatabaseComment.getInstance());
-       
+
         //no html in comments(for now)
         for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
             String k=(String)i.next();
             String v=(String)withValues.get(k);
-            
+
             withValues.put(k,StringUtil.removeHTMLTags(v));
         }
         withValues.put("is_published","1");
-                               
-                               //checking the onetimepasswd
-                               if(passwdProtection.equals("yes")){
-                                       HttpSession session = req.getSession(false);
-                                       String sessionPasswd = (String)session.getAttribute("passwd");
-                                       if ( sessionPasswd == null){
-                                               throw new ServletModuleUserException("Lost password");
-                                       }
-                                       String passwd = req.getParameter("passwd");
-                                       if ( passwd == null || (!sessionPasswd.equals(passwd))) {
-                                               throw new ServletModuleUserException("Missing password");
-                                       }
-                                       session.invalidate();
-                               }
-                               
+
+        //checking the onetimepasswd
+        if(passwdProtection.equals("yes")){
+          HttpSession session = req.getSession(false);
+          String sessionPasswd = (String)session.getAttribute("passwd");
+          if ( sessionPasswd == null){
+            throw new ServletModuleUserException("Lost password");
+          }
+          String passwd = req.getParameter("passwd");
+          if ( passwd == null || (!sessionPasswd.equals(passwd))) {
+            throw new ServletModuleUserException("Missing password");
+          }
+          session.invalidate();
+        }
+
         // inserting into database
         String id = mainModule.add(withValues);
         theLog.printDebugInfo("id: "+id);
         //insert was not successfull
         if(id==null){
           deliver(req, res, new SimpleHash(), commentFormDupeTemplate);
+        } else {
+          DatabaseContent.getInstance().setUnproduced("id="+aid);
+
+          try {
+            EntityComment comment = (EntityComment) DatabaseComment.getInstance().selectById(id);
+            MirGlobal.localizer().openPostings().afterCommentPosting(comment);
+          }
+          catch (Throwable t) {
+            throw new ServletModuleException(t.getMessage());
+          }
+          
+          
+          
         }
-        
-        // producing new page
-        new ProducerContent().handle(null, null, true, false, aid);
-
-        // sync the server
-        int exitValue = Helper.rsync();
-        theLog.printDebugInfo("rsync:"+exitValue);
 
         // redirecting to url
         // should implement back to article
@@ -196,16 +216,16 @@ public class ServletModuleOpenIndy extends ServletModule
   public void addposting(HttpServletRequest req, HttpServletResponse res)
     throws ServletModuleException {
     SimpleHash mergeData = new SimpleHash();
-               
-               // onetimepasswd
-               if(passwdProtection.equals("yes")){
-                       String passwd = this.createOneTimePasswd();
-                       System.out.println(passwd);
-                       HttpSession session = req.getSession(false);
-                       session.setAttribute("passwd",passwd);
-                       mergeData.put("passwd", passwd);
-               }
-                       
+
+    // onetimepasswd
+    if(passwdProtection.equals("yes")){
+      String passwd = this.createOneTimePasswd();
+      System.out.println(passwd);
+      HttpSession session = req.getSession(false);
+      session.setAttribute("passwd",passwd);
+      mergeData.put("passwd", passwd);
+    }
+
     String maxMedia = MirConfig.getProp("ServletModule.OpenIndy.MaxMediaUploadItems");
     String numOfMedia = req.getParameter("medianum");
     if(numOfMedia==null||numOfMedia.equals("")){
@@ -213,7 +233,7 @@ public class ServletModuleOpenIndy extends ServletModule
     } else if(Integer.parseInt(numOfMedia) > Integer.parseInt(maxMedia)) {
       numOfMedia = maxMedia;
     }
-    
+
     int mediaNum = Integer.parseInt(numOfMedia);
     SimpleList mediaFields = new SimpleList();
     for(int i =0; i<mediaNum;i++){
@@ -222,19 +242,24 @@ public class ServletModuleOpenIndy extends ServletModule
     }
     mergeData.put("medianum",numOfMedia);
     mergeData.put("mediafields",mediaFields);
-    
-    
+
+
     SimpleHash extraInfo = new SimpleHash();
     try{
       SimpleList popUpData = DatabaseLanguage.getInstance().getPopupData();
       extraInfo.put("languagePopUpData", popUpData );
       extraInfo.put("themenPopupData", themenModule.getTopicsAsSimpleList());
+
+      extraInfo.put("topics", themenModule.getTopicsList());
+
     } catch (Exception e) {
       theLog.printError("languagePopUpData or getTopicslist failed "
                         +e.toString());
       throw new ServletModuleException("OpenIndy -- failed getting language or topics: "+e.toString());
     }
-      
+
+
+
     deliver(req, res, mergeData, extraInfo, postingFormTemplate);
   }
 
@@ -248,11 +273,10 @@ public class ServletModuleOpenIndy extends ServletModule
   {
     SimpleHash mergeData = new SimpleHash();
     boolean setMedia=false;
-               boolean setTopic = false;
+    boolean setTopic = false;
 
     try {
       WebdbMultipartRequest mp = new WebdbMultipartRequest(req);
-
       EntityList mediaList = null;
       try {
         // new MediaRequest, "1" is the id for the openPosting user
@@ -262,32 +286,32 @@ public class ServletModuleOpenIndy extends ServletModule
       }
           
       HashMap withValues = mp.getParameters();
-                                                       
-                       //checking the onetimepasswd
-                       if(passwdProtection.equals("yes")){
-                               HttpSession session = req.getSession(false);
-                               String sessionPasswd = (String)session.getAttribute("passwd");
-                               if ( sessionPasswd == null){
-                                       throw new ServletModuleUserException("Lost password");
-                               }
-                               String passwd = (String)withValues.get("passwd");
-                               if ( passwd == null || (!sessionPasswd.equals(passwd))) {
-                                       throw new ServletModuleUserException("Missing password");
-                               }
-                               session.invalidate();
-                       }
+
+      //checking the onetimepasswd
+      if(passwdProtection.equals("yes")){
+        HttpSession session = req.getSession(false);
+        String sessionPasswd = (String)session.getAttribute("passwd");
+        if ( sessionPasswd == null){
+          throw new ServletModuleUserException("Lost password");
+        }
+        String passwd = (String)withValues.get("passwd");
+        if ( passwd == null || (!sessionPasswd.equals(passwd))) {
+          throw new ServletModuleUserException("Missing password");
+        }
+        session.invalidate();
+      }
 
       if ((((String)withValues.get("title")).length() == 0) ||
           (((String)withValues.get("description")).length() == 0) ||
           (((String)withValues.get("content_data")).length() == 0))
             throw new ServletModuleUserException("Missing field");
-      
+
       // call the routines that escape html
 
       for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
         String k=(String)i.next();
         String v=(String)withValues.get(k);
-        
+
         if (k.equals("content_data")){
           //this doesn't quite work yet, so for now, all html goes
           //withValues.put(k,StringUtil.approveHTMLTags(v));
@@ -295,7 +319,7 @@ public class ServletModuleOpenIndy extends ServletModule
         } else {
           withValues.put(k,StringUtil.removeHTMLTags(v));
         }
-        
+
       }
 
       withValues.put("date", StringUtil.date2webdbDate(new GregorianCalendar()));
@@ -306,11 +330,13 @@ public class ServletModuleOpenIndy extends ServletModule
       withValues.put("is_published","1");
       // if op direct article-type == newswire
       if (directOp.equals("yes")) withValues.put("to_article_type","1");
-      
-      // owner is openposting user
+
       withValues.put("to_publisher","1");
-      if (withValues.get("creator").toString().equals(""))
-        withValues.put("creator","Anonym");
+
+      // owner is openposting user
+//      ML: this is not multi-language friendly and this can be done in a template
+//      if (withValues.get("creator").toString().equals(""))
+//        withValues.put("creator","Anonym");
 
       // inserting  content into database
       String cid = contentModule.add(withValues);
@@ -327,8 +353,8 @@ public class ServletModuleOpenIndy extends ServletModule
       }
 
       String[] to_topicsArr = mp.getParameterValues("to_topic");
-      
-                       if (to_topicsArr != null && to_topicsArr.length > 0) {
+
+      if (to_topicsArr != null && to_topicsArr.length > 0) {
         try{
           DatabaseContentToTopics.getInstance().setTopics(cid,to_topicsArr);
           setTopic = true;
@@ -345,22 +371,13 @@ public class ServletModuleOpenIndy extends ServletModule
         DatabaseContentToMedia.getInstance().addMedia(cid,mediaEnt.getId());
       }
 
-      // producing openpostinglist
-      new ProducerOpenPosting().handle(null,null,false,false);
-      // producing new page
-      new ProducerContent().handle(null, null, false, false,cid);
-      //if direct op producing startpage
-      if (directOp.equals("yes")) new ProducerStartPage().handle(null,null);
-      
-                       //produce the topicPages if set
-                       //should be more intelligent
-                       //if(setTopic==true) new ProducerTopics().handle(null,null);
-                       
-      // sync the server
-      //should be configureable
-      int exitValue = Helper.rsync();
-      theLog.printDebugInfo("rsync: "+exitValue);
-
+      try {
+        MirGlobal.localizer().openPostings().afterContentPosting(
+            (EntityContent)contentModule.getById(cid));
+      }
+      catch (Throwable t) {
+        throw new ServletModuleException(t.getMessage());
+      }
     }
     catch (MirMediaException e) { throw new ServletModuleException("MediaException: "+ e.toString());}
     catch (IOException e) { throw new ServletModuleException("IOException: "+ e.toString());}
@@ -439,17 +456,17 @@ public class ServletModuleOpenIndy extends ServletModule
         +", we do not support this mime-type. "
         +"Error One or more files of unrecognized type. Sorry");
   }
-       
-       protected String createOneTimePasswd(){
-               Random r = new Random();
-               int random = r.nextInt();
-               long l = System.currentTimeMillis();
-               l = (l*l*l*l)/random;
-               if(l<0) l = l * -1;
-               String returnString = ""+l;
-               return returnString.substring(5);
-       }
-      
+
+  protected String createOneTimePasswd(){
+    Random r = new Random();
+    int random = r.nextInt();
+    long l = System.currentTimeMillis();
+    l = (l*l*l*l)/random;
+    if(l<0) l = l * -1;
+    String returnString = ""+l;
+    return returnString.substring(5);
+  }
+
 }
 
 
index 1e4e0d2..cf03a62 100755 (executable)
@@ -10,9 +10,11 @@ import freemarker.template.*;
 
 import mir.servlet.*;
 import mir.misc.*;
+import mir.producer.*;
 
 import mircoders.producer.*;
 import mircoders.entity.*;
+import mircoders.global.*;
 
 /* Verteilerservlet, dass je nach Parameter task die Klasse Producer"TASK"
  * ueber die Methode handle(); aufruft
@@ -37,29 +39,51 @@ public class ServletModuleProducer extends ServletModule
        {
                try {
                        PrintWriter out = res.getWriter();
-                       String taskParam = req.getParameter("task");
-                       String forcedParam = req.getParameter("forced");
-      String syncParam = req.getParameter("sync");
-                       theLog.printInfo("Starting Task: " + taskParam);
-                       if (taskParam == null) {
-                               throw new ServletModuleException("Kein Task angegeben!");
-                       } else {
-        Class producerModule = Class.forName("mircoders.producer.Producer" + taskParam);
-        Producer producer = (Producer)producerModule.newInstance();
-        HttpSession session=req.getSession(false);
-                               EntityUsers user = (EntityUsers)session.getAttribute("login.uid");
-
-        if (forcedParam!=null && !forcedParam.equals("")) {
-          if (syncParam!=null && !syncParam.equals("")) {
-            producer.handle(out, user, true, true);
-          } else {
-            producer.handle(out, user, true,false);
+
+
+                       if (req.getParameter("producer")!=null) {
+      // ML: new producer system:
+
+                       String producerParam = req.getParameter("producer");
+                       String verbParam = req.getParameter("verb");
+
+                       MirGlobal.producerEngine().addJob(producerParam, verbParam);
+                       MirGlobal.producerEngine().printQueueStatus(out);
+
+//        ProducerFactory factory = (ProducerFactory) MirGlobal.localizer().producers().factories().get(producerParam);
+//        mir.producer.Producer producer = factory.makeProducer(verbParam);
+
+//        producer.produce(out);
+
+      }
+      else
+      {
+      // ML: old producer system:
+
+                       String taskParam = req.getParameter("task");
+                       String forcedParam = req.getParameter("forced");
+        String syncParam = req.getParameter("sync");
+                       theLog.printInfo("Starting Task: " + taskParam);
+                       if (taskParam == null) {
+                               throw new ServletModuleException("Kein Task angegeben!");
+                       } else {
+          Class producerModule = Class.forName("mircoders.producer.Producer" + taskParam);
+          mircoders.producer.Producer producer = (mircoders.producer.Producer) producerModule.newInstance();
+          HttpSession session=req.getSession(false);
+                               EntityUsers user = (EntityUsers)session.getAttribute("login.uid");
+
+          if (forcedParam!=null && !forcedParam.equals("")) {
+            if (syncParam!=null && !syncParam.equals("")) {
+              producer.handle(out, user, true, true);
+            } else {
+              producer.handle(out, user, true,false);
+            }
+                               } else {
+                                       producer.handle(out, user, false,false);
           }
-                               } else {
-                                       producer.handle(out, user, false,false);
-        }
 
-                       }
+                       }
+               }
                }
                catch (Exception e) {
       throw new ServletModuleException(e.toString());
index a72f8c9..3973373 100755 (executable)
                        <a href="${config.actionRoot}?module=Content&do=add&where=aktuell">${lang("start.content.new")}</a>
            <p>
                        <b>${lang("start.show")}:</b><br>
-                       <img src="${config.docRoot}/img/pointgris.gif" border=0>
-                       <a href="${config.actionRoot}?module=Content&do=list&where=newswire">${lang("start.content.newswire")}</a><br>
-                       <img src="${config.docRoot}/img/pointgris.gif" border=0>
-                       <a href="${config.actionRoot}?module=Content&do=list&where=feature">${lang("start.content.feature")}</a><br>
-                       <img src="${config.docRoot}/img/pointgris.gif" border=0>
-                       <a href="${config.actionRoot}?module=Content&do=list&where=themenspecial">${lang("start.content.topicspecial")}</a><br>
-                       <img src="${config.docRoot}/img/pointgris.gif" border=0>
-                       <a href="${config.actionRoot}?module=Content&do=list&where=special">${lang("start.content.startspecial")}</a><br>
+      <list data.articletypes as a>
+                       <img src="${config.docRoot}/img/pointgris.gif" border=0>
+                       <a href="${config.actionRoot}?module=Content&do=list&where=is_published%3d'1'%20and%20to_article_type%3D${a.id}&order=webdb_create%20desc">${a.name}</a><br>
+      </list>
+
+
                        <br>
                <img src="${config.docRoot}/img/pointgris.gif" border=0>
                        <a href="${config.actionRoot}?module=Content&do=list&where=nfrei" >${lang("start.content.not_published")}</a><br>
                <tr><td bgcolor="white">&nbsp;</td></tr>
                </table>
 
-
                        <font  face="Verdana, Arial, Helvetica, sans-serif" size="2" color="#663399">
-                       <b>${lang("start.generate.title")}</b></font>
+                       <b>Localizer producers</b></font>
+
 
                        <div align="left">
-                               <br>
-                               ${lang("start.generate.all.title")}:
-                               <br>
-                               <img src="${config.docRoot}/img/pointgris.gif" border=0>
-                               <a href="${config.actionRoot}?module=Producer&task=All">${lang("start.generate.all.new")}</a> &nbsp;|&nbsp;
-        <!--
-       <br>
-        <a href="${config.actionRoot}?module=Producer&task=All&forced=1">alles (!)(forced, update auf www > 5min.)</a>
-        &nbsp;|&nbsp;
-        <br>
-        <a href="${config.actionRoot}?module=Producer&task=All&forced=1&sync=1">alles (!)(www sofort, nur im Notfall)</a>
-        &nbsp;|&nbsp;
-        <br>
-       -->
-                               <br>${lang("start.generate.parts.title")}:
-                               <br>
-                       <img src="${config.docRoot}/img/pointgris.gif" border=0>
-                               <a href="${config.actionRoot}?module=Producer&task=StartPage">${lang("start.generate.startpages.new")}</a>
-                               &nbsp;|&nbsp;
-                               <a href="${config.actionRoot}?module=Producer&task=StartPage&forced=1">${lang("start.generate.all_forced")}</a>
-                               &nbsp;|&nbsp;
-                               <a href="${config.actionRoot}?module=Producer&task=StartPage&forced=1&sync=1">${lang("start.generate.all_sync")}</a>
-                               <br>
-                               <img src="${config.docRoot}/img/pointgris.gif" border=0>
-                       <a href="${config.actionRoot}?module=Producer&task=Content">${lang("start.generate.content.new")}</a>
-                               &nbsp;|&nbsp;
-                               <a href="${config.actionRoot}?module=Producer&task=Content&forced=1">${lang("start.generate.all_forced")}</a>
-                               <br>
-                       <img src="${config.docRoot}/img/pointgris.gif" border=0>
-                               <a href="${config.actionRoot}?module=Producer&task=Topics">${lang("start.generate.topics.new")}</a>
-                               &nbsp;|&nbsp;
-                               <a href="${config.actionRoot}?module=Producer&task=Topics&forced=1">${lang("start.generate.all_forced")}</a>
-                               <br>
-                               <a href="${config.actionRoot}?module=Producer&task=OpenPosting">
-                       <img src="${config.docRoot}/img/pointgris.gif" border=0>${lang("start.generate.postings.new")}</a>
-                               &nbsp;|&nbsp;
-                               <a href="${config.actionRoot}?module=Producer&task=OpenPosting&forced=1">${lang("start.generate.all_forced")}</a>
-                               <br>
-                               <a href="${config.actionRoot}?module=Producer&task=Images">
-                       <img src="${config.docRoot}/img/pointgris.gif" border=0>${lang("start.generate.images.new")}</a>
-                               &nbsp;|&nbsp;
-                               <a href="${config.actionRoot}?module=Producer&task=Images&forced=1">${lang("start.generate.all_forced")}</a>
-                <br>
-                               <a href="${config.actionRoot}?module=Producer&task=Audio">
-                       <img src="${config.docRoot}/img/pointgris.gif" border=0>${lang("start.generate.audio.new")}</a>
-                               &nbsp;|&nbsp;
-                               <a href="${config.actionRoot}?module=Producer&task=Audio&forced=1">${lang("start.generate.all_forced")}</a>
-<br>
-                               <a href="${config.actionRoot}?module=Producer&task=Video">
-                       <img src="${config.docRoot}/img/pointgris.gif" border=0>${lang("start.generate.video.new")}</a>
-                               &nbsp;|&nbsp;
-                               <a href="${config.actionRoot}?module=Producer&task=Video&forced=1">${lang("start.generate.all_forced")}</a>
-<br>
-                               <a href="${config.actionRoot}?module=Producer&task=Other">
-                       <img src="${config.docRoot}/img/pointgris.gif" border=0>${lang("start.generate.other.new")}</a>
-                               &nbsp;|&nbsp;
-                               <a href="${config.actionRoot}?module=Producer&task=Other&forced=1">${lang("start.generate.all_forced")}</a>
-
-                               <br>
-        <a href="${config.actionRoot}?module=Producer&task=Navigation">
-                       <img src="${config.docRoot}/img/pointgris.gif" border=0>${lang("start.generate.navigation")}</a>
-                               <br>
+                         <table>
+                           <tr><th>producer</th><th>verbs</th></tr>
+
+                         <list data.producers as p>
+                           <tr>
+                           <td>${p.key}</td>
+
+               <td>
+                 <table>
+                   <tr>
+                             <list p.verbs as v>
+                               <td width="30">
+                               <a href="${config.actionRoot}?module=Producer&producer=${p.key}&verb=${v}">
+                                 ${v}
+                               </a>
+                               </td>
+                             </list>
+                               <tr>
+                             </table>
+               </td>
+                   </tr>
+
+                         </list>
+
+                         </table>
+                 </div>
+
 
 
        </td>
diff --git a/templates-dist/de/open/comment.template b/templates-dist/de/open/comment.template
deleted file mode 100755 (executable)
index 750db5e..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-<html>
-<head><title>indymedia.de | comment.commit</title></head>
-<body bgcolor="white" text="black" link="#006600" vlink="#009900" alink="red">
-                       
-<form action="${config.openAction}" method=post>
-<input type="hidden" name="do" value="inscomment">
-                       
-<table width="100%" border="0" cellspacing="0" cellpadding="4" bgcolor="silver">
-       <tr>
-               <td bgcolor="#663399" colspan="3">
-                       <font color="White"><b>Kommentierung eines Beitr&auml;gs bei Indymedia</b></font>
-               </td>
-       </tr>   
-       <tr>
-               <td bgcolor="#003300" colspan="3">
-                       <p>
-                               <font color="white"">
-                                       Hinweis: Dein Kommentar kann in jedem Stil und jeder Form sein, akademisch bis pers&ouml;nlich.<br>
-                                       Aber bitte bleibe beim <b>Thema des Artikels</b>, den Du kommentierst und versuche, <b>pr&auml;zise</b> zu sein.
-                               </font>
-                       </p>
-
-               </td>
-       </tr>
-       <tr>
-               <td bgcolor="#663399" colspan="3">
-                       <font face="Helvetica, Arial" color="white" size=+2><b>Kommentierungsformular</b></font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       <b>Titel des Kommentars:</b>
-               </td>
-               <td colspan="2">
-                       <input type="text" name="title" size="45" maxlength="45"> <font size="-1" color="#663399">(muss ausgef&uuml;llt werden)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       <b>Dein Name:</b>
-               </td>
-               <td colspan="2">
-                       <input type="text" name="creator" size="20" maxlength="45"> <font size="-1" color="#663399">(muss ausgef&uuml;llt werden)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       Deine eMail-Adresse:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="email" size="30" maxlength="80"> <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       Deine Web Adresse:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="main_url" size="40" maxlength="160" value="http://"> <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       Deine Telefon-Nr.:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="phone" size="30" maxlength="80"> <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       Deine Adresse:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="address" size="40" maxlength="160"><font size="-1"> <i>(optional)</i></font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       Die Sprache deines Kommentares:
-               </td>
-               <td colspan="2">
-                       <select name="to_language">
-                               <option value="0">de</option>
-                               <option value="1">en</option>
-                       </select> 
-                       <font size="-1"><i>(optional)</i></font>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top">
-                       <b>Dein Kommentar:</b>
-               </td>
-               <td bgcolor="#003300" colspan="2">
-                       &nbsp;<textarea name="description" rows="20" cols="60" wrap=virtual></textarea>
-                       <br><br>
-               </td>
-       </tr>
-       <tr>
-               <td>&nbsp;
-               </td>
-               <td bgcolor="#663399" valign="top" align="center">
-                       <br>
-                       &nbsp;<input type="submit" value="Kommentar abschicken"><br>
-
-               </td>
-               <td bgcolor="#003300" valign="top" align="center">
-                       <br>
-                       &nbsp;<input type="reset" value="Formular l&ouml;schen"><br>
-                       <input type="hidden" name="to_media" value="${data.aid}">
-                       <br>
-               </td>
-       </tr>
-</table>
-       
-</form>
-
-</body>
-</html>
diff --git a/templates-dist/de/open/comment_done.template b/templates-dist/de/open/comment_done.template
deleted file mode 100755 (executable)
index c9838a7..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html>
-<head>
-       <title>indymedia.de | open posting</title>
-</head>
-
-<body bgcolor="White" text="Black" link="#006600" vlink="#009900" alink="Red">
-
-<table width="100%" border="0" cellspacing="0" cellpadding="10">
-       <tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <font color="White"><b>Danke. Deine Ergänzung ist jetzt auf dem Weg zur Website!</b></font
-               </td>
-       </tr>
-       <tr>
-               <td bgcolor="#cccccc" align="center">
-
-                               <br>
-                               In wenigen Minuten ist Deine Ergänzung unter dem ergänzten Artikel.<br>
-                               Manchmal kann es aber aufgrund technischer Probleme etwas dauern bis sie erscheint.<br>
-                               <br>
-                               Die Moderationskriterien von indymedia.de kannst Du <a href="http://de.indymedia.org/static/moderation.html" target="_blank">hier</a> lesen.
-
-                               <br>
-                               <em>Gedulde Dich einen Moment - Es lohnt sich!</em><br>
-                               <br>
-
-               </td>
-       </tr>
-       <tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <a href="javascript:history.go(-2)"><font color="White"><b>&gt;&gt; Zur&uuml;ck zum kommentierten Artikel</b></font></a>
-               </td>
-       </tr> 
-</table>
-
-</body>
-</html>
diff --git a/templates-dist/de/open/comment_dupe.template b/templates-dist/de/open/comment_dupe.template
deleted file mode 100755 (executable)
index 9ec3648..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html>
-<head>
-       <title>indymedia.de | open posting - Kommentar-Duplikat</title>
-</head>
-
-<body bgcolor="White" text="Black" link="white" vlink="#009900" alink="Red">
-
-<table width="100%" border="0" cellspacing="0" cellpadding="10">
-       <tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <font color="White"><b>
-                               Immer ruhig mit den jungen Pferden!
-                       </b></font
-               </td>
-       </tr> 
-       <tr>
-               <td bgcolor="003300" width=70%>
-                       <font color="White">
-                               <br>
-                                       Du hast vermutlich den Reload-Button
-                                       benutzt oder versucht, Deinen Kommentar noch einmal zu posten. Das ist aber
-                                       unn&ouml;tig. Die Tatsache, dass Du diesen Text liest, bedeutet, dass Dein
-                                       Kommentar schon angekommen ist. Er wird gleich auf der Seite auftauchen. Versprochen.
-                               <br> 
-                               <center><em>Keine Panik</em></center><br>
-                               <br>
-                       </font>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <a href="javascript:history.go(-2)"><font color="White"><b>&gt;&gt; Zur&uuml;ck zum kommentierten Artikel</b></font></a>
-               </td>
-       </tr> 
-</table>
-
-</body>
-</html>
diff --git a/templates-dist/de/open/comment_en.template b/templates-dist/de/open/comment_en.template
deleted file mode 100755 (executable)
index 192e57f..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-<html>
-<head>
-       <title>indymedia.de | comment.commit</title>
-</head>
-
-<body bgcolor="White">
-<table>
-       <tr><td valign=top align=left>
-<font face="Helvetica, Arial" size=-1">
-<i><b>adding a comment</b></i><br>
- <!--endmenu-->
-
-<h3>Guidelines for commenting on news articles</h3>
-Thanks for contributing to the dynamic alternative news on active!
-<br><p>
-Add any responses to news articles that you feel are appropriate to
-www.indy's goals eg: social activitism, local communities, ecology and development.
-<br><p>
-The response article can be in any type of format you want, from traditional academic discourse, to subjective personal rants.
-<br><p>
-Please keep it on topic and concise.
-<br><p>
-<br><br> * = required field
-<p>
-
-<form action="https://work.indymedia.de/rk/servlet/OpenIndy" method=post>
-<input type="hidden" name="do" value="inscomment">
-<blockquote>
-       <table border=1 cellspacing=0 width="100%">
-       <tr bgcolor="">
-       <td><font face="Helvetica, Arial">
-       <b>Titel des Kommentars (*)</b><br>
-       <input type="text" name="title" size="45" maxlength="45">
-       <p>
-       <b>Dein Name (*)</b> <br>
-       <input type="text" name="creator" size="20" maxlength="45"><br>
-       <p>
-       <table border=0>
-       <tr>
-       <td><font face="Helvetica, Arial">
-       email (<i>optional</i>)
-       </font></td>
-       <td><font face="Helvetica, Arial">
-       web address (begin with http://) (<i>optional</i>)
-       </font></td></tr>
-       <tr>
-       <td>
-       <input type="text" name="email" size="30" maxlength="80">
-       </td><td>
-       <input type="text" name="main_url" size="40" maxlength="160">
-       </td></tr></table>
-
-       <p><table border=0>
-       <tr><td><font face="Helvetica, Arial">
-       phone (<i>optional</i>)
-       </font></td>
-       <td><font face="Helvetica, Arial">
-       address (<i>optional</i>)
-       </font></td></tr>
-       <tr><td>
-       <input type="text" name="phone" size="30" maxlength="80">
-       </td><td>
-       <input type="text" name="address" size="40" maxlength="160">
-       </td></tr>
-       <tr><td>
-
-           <b>language</b><br>
-the language of the submission<BR>
-<select name="to_language">
-<option value="0">de</option>
-<option value="1">en</option>
-</select><BR>
-</td></tr>
-       </table>
-       <p>
-       <b>your comment*</b><br>
-       <textarea name="description" rows="20" cols="60" wrap=virtual></textarea>
-       </table>
-       <center>
-       <input type="submit" value="add my comment">
-       <input type="reset" value="clear form">
-       <input type="hidden" name="to_media" value="${aid}">
-       </center>
-</form>
-
-</blockquote>
-</font>
-
-</td>
-</tr>
-</table>
-</body>
-</html>
\ No newline at end of file
diff --git a/templates-dist/de/open/posting.template b/templates-dist/de/open/posting.template
deleted file mode 100755 (executable)
index 6662274..0000000
+++ /dev/null
@@ -1,341 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//DE">
-<html>
-<head>
-       <title>indymedia.de | open posting</title>
-       <meta name="description" content="Indymedia Germany | Unabh&auml;ngiges Medienzentrum">
-       <meta name="author" content="IMC Kollektiv">
-       <meta name="keywords" content="Freie Medien, Gegen&ouml;ffentlichkeit">
-       <meta name="date" content="### Date ###Time">
-       <meta http-equiv="Content-Type" content="text/html; charset=iso-8559-1">
-       <meta name="robots" content="index">
-       <meta name="robots" content="follow">
-
-       <link rel=stylesheet type="text/css" href="${config.productionHost}/style/formate.css">
-</head>
-
-<body bgcolor="White" text="Black" link="#006600" vlink="#006600" alink="Red">
-
-
-<table width="99%" border="0" cellspacing="0" cellpadding="8" bgcolor="silver">
-       <tr>
-               <td align="left" bgcolor="#663399" colspan="3">
-                       <a href="#form"><font face="Verdana, Arial, Helvetica, sans-serif" size="-2" color="white"><b>&gt;&gt; Direkt zum Eingabeformular springen!</b></font></a>
-               <br>
-               </td>
-       </tr>
-       <tr>
-               <td align="center" colspan="3">
-                       <font size="+1" face="Verdana, Arial, Helvetica, sans-serif"><b>Ver&ouml;ffentliche Deinen Beitrag</b></font><br>
-               </td>
-       </tr>
-       <tr>
-               <td colspan="3" bgcolor="white">
-
-                                               <h3>Kurze Anleitung zum Posten eines Beitrages bei de.indymedia.org</h3>
-<!-- erklaerungstext -->
-
-<b>I</b>ndymedia ist ein basisdemokratischer Nachrichtenkanal.
-Wir arbeiten aus Liebe und aus Respekt gegenüber Menschen,
-die sich für eine bessere, lebenswertere Welt engagieren.
-Bei Indymedia kann grundsätzlich JedeR Texte, Videos, Audios oder Fotos
-zu politischen oder sozialen Themen veröffentlichen.
-<br><br>
-
-Indymedia will vor allem die Möglichkeit geben,
-subjektive Stellungnahmen verschiedenster Menschen
-'auf der Strasse' über politische Ereignisse oder aus
-der alltäglichen Lebenswelt zu veröffentlichen. Zudem
-ist Indymedia eine Plattform für Hintergrundberichte,
-die andere Hintergründe als kommerzielle Medien aufzeigen.
-<br><br>
-
-Um indymedia als Plattform für <b>eigene</b>
-Berichterstattung zu konturieren, werden bestimmte
-Beiträge nicht auf die Startseite gestellt. Dazu gehören:
-
-
-<ul>
-<li>
-Termine und Demoaufrufe [ Weil wir wissen, dass diese für die Mobilisierung
-sehr wichtig sind, verlinken wir zu verschiedenen Internetprojekten, auf
-denen Ihr gute Terminsammlungen findet ] Bei angelaufenen Kampagnen werden
-regelmäßig Termine und Aufrufe in die Mittelspalten-Texte als Links gesetzt.
-
-
-<li>
-schon an anderen Stellen veröffentlichte Texte und aus kommerziellen Medien
-kopierte Texte<br>
-[ hierbei sind Übersetzungen von Texten und Meldungen
-von hier kaum zugänglichen Medien eine Ausnahme ]
-
-
-<li>Gruppenstatements, Presseerklärungen, Diskussionspapiere, Massenmails
-<br>
-
-[auch hier geht es um die Zugänglichkeit von Texten. Beiträge von
-Gruppen, die schon auf zahlreichen anderen Internet-Seiten oder in
-Zeitschriften veröffentlicht wurden, werden nicht auf die Startseite
-gestellt, weil es nicht der Ansatz von indymedia ist alles
-irgendwie relevante auf der Seite zu versammeln, sondern eine
-Plattform für eigene  Berichterstattung zu sein. Unter eigener
-Berichtserstattung verstehen wir allerdings Presseerklärungen
-von Kleingruppen oder Diskussionspapiere einzelner.
-
-
-<li>
-superkurze Meldungen:
-
-
-<li>
-reine Kommentare ohne Nachrichtenwert<br>
-[ Zusätzlich zu den selbstverfassten Beiträgen, gibt es bei indymedia
-noch die Möglichkeit über Artikel zu diskutieren.
-Das könnt Ihr unter dem jeweiligen Artikel - einfach auf
-"Kommentar eingeben" klicken ]
-
-
-<li>
-Beiträge von hierarchischen Gruppen und Parteien
-
-
-<li>
-Außerdem gibt es Beiträge, die sofort in ein
-Müllarchiv kommen:
-<ul>
-       <li>Diskriminierender oder menschenverachtender Inhalt
-       <li>Offensichtlicher Spam
-</ul>
-</ul>
-
-<br><br>
-Was mit Eurem Beitrag passiert, lest Ihr am besten
-unter <a href="http://de.indymedia.org/static/ms.html" target="_blank">Grundsätze</a> und <a href="http://de.indymedia.org/static/moderation.html" target="_blank">Moderation</a> nach. Hier eine kurze Zusammenfassung:
-<br><br>
-
-Alle Beiträge werden sofort unzensiert veröffentlicht.<br>
-Allerdings erscheinen sie dann nicht gleich auf der
-Startseite, sondern auf der Open-Posting-Seite
-&quot;<a href="http://de.indymedia.org/open.html" target="_blank">alle Beiträge</a>&quot;.<br>
-Dort werden sie von Moderationskollektiven
-gelesen. Entsprechen sie den indymedia-Grundsätzen,
-erscheinen sie im Newswire der Startseite.
-In die Mittelspalte nehmen wir in der Regel Beiträge,
-die einen guten Überblick über ein aktuelles Thema geben.
-Diese Artikel werden von uns (möglichs in Absprache mit der AutorIn) auch leicht redigiert:
-Wir korrigieren Rechtschreibfehler, versuchen unverständliche
-Stellen zu glätten und setzen Links hinein.<br>
-Verlautbarungen,
-Texte, die keinen politischen oder sozialen Inhalt haben,
-reine Diskussionsbeiträge und Termine bleiben im Open Posting.
-Texte mit menschenverachtendem Inhalt oder Spam kommen ins
-Müllarchiv. Damit sind sie nicht mehr einsehbar. Wer
-sie trotzdem lesen will, kann sie per e-mail anfordern.
-Diese Moderationskriterien sind Resultat eines weltweiten
-Diskussionsprozesses über indymedia und werden ständig neu
-diskutiert und überarbeitet.
-<br><br>
-
-<b>Urheberrecht: </b>Unserer Auffassung nach sollten
-Beiträge, die an diese Site geschickt werden, frei zur
-nicht-kommerziellen Wiederverwertung sein. Wenn Du
-nicht möchtest, dass das für Deinen Beitrag zutrifft,
-dann nenne Deine Konditionen in der Zusammenfassung.
-<br><br>
-<a name="form"></a>
-               </td>
-       </tr>
-<form action="${config.openAction}?do=addposting" method="post">
-       <tr>
-               <td><b>Anzahl der Medien</b> <br>
-               (wenn Du mehr als eine Datei hochladen willst, bitte hier die Anzahl eintragen und den Knopf drücken, <b>bevor</b> Du weitere Felder ausfüllst.)</td>
-               <td colspan="2"><input type="text" name="medianum" value="${medianum}">&nbsp;<input type="submit" value="Anzahl festlegen">
-       </tr>
-</form>
-
-
-<form enctype="multipart/form-data" action="${config.openAction}?do=insposting" method="post">
-       <tr>
-               <td bgcolor="#663399" colspan="3">
-                       <center><font size="+2" face="Helvetica, Arial,sans-serif" color="white"><b>Ver&ouml;ffentlichungsformular</b></font></center>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top">
-                       Gib Deinem Beitrag einen <b>Titel</b>:<br>
-                       <font size="-2">(Bitte wähle einen möglichst klaren, aussagekräftigen Titel.)</font>
-               </td>
-               <td colspan="2" bgcolor="#003300">
-                       <input type="text" name="title" size="45" maxlength="45" value=""> <font size="-1" color="white"><br>(muss ausgef&uuml;llt werden)</font>
-               </td>
-       </tr>
-    <tr>
-        <td valign="top">
-            <b>Thema</b> Deines Beitrags:<br>
-       <font size="-2">(Mehrfachwahl ist möglich. Bitte dazu die [Strg]- bzw [Ctrl]-Taste benutzen)</font>
-        </td>
-       <td colspan="2">
-       <select name="data.to_topic" size="3" multiple>
-       <list themenPopupData as t>
-       <option value="${t.key}" <list to_topic as to><if (t.key == to)>selected</if></list>>${t.value}</option>
-       </list>
-       </select>
-       &nbsp;&nbsp;<font size="-1">(<i>optional</i>)</font>
-       </td>
-    </tr>
-       <tr>
-               <td valign="top">
-                       <b>AutorIn</b> des Beitrags:
-               </td>
-               <td colspan="2" bgcolor="#003300">
-                       <input type="text" name="creator" size="45" maxlength="45"> <font size="-1" color="white"><br>(muss ausgef&uuml;llt werden)</font>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top">
-                       Eine kurze <b>Zusammenfassung</b> des Beitrags:</b> <br>
-                       <font size="-2">(Sie soll den LeserInnen schnell vermitteln, worum es in Deinem Beitrag geht.
-                                       Falls Du den ersten Absatz Deines Artikels dazu wählst, achte bitte darauf ihn im Haupttextfeld weiter
-                                               unten nicht nochmal einzusetzen.)</font>
-               </td>
-               <td colspan="2" bgcolor="#003300">
-                       <textarea name="description" rows="6" cols="55" wrap=virtual></textarea>
-                       <font size="-1" color="white"><br>(nicht mehr als <b>5 Zeilen</b>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td colspan="3" bgcolor="#FFFFFF">
-               <font face="Helvetica, Arial, sans-serif" size=-1 color="#222222">
-               Die Kontaktinformationen sind optional, aber erm&ouml;glichen, dass die IndymedialeserInnen (z.B. auch JournalistInnen) Dich bez&uuml;glich Deines Beitrages, z.B. für Rückfragen, erreichen k&ouml;nnen, was auch eine Weiterverwertung Deines Beitrages an anderen Stellen erm&ouml;glicht.
-               </font>
-               </td>
-       </tr>
-
-       <tr>
-               <td>
-                       Deine eMail-Adresse:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="creator_email" size="55" maxlength="80" value=""><br>
-                                        <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       Eine Web-Adresse zum Artikel:
-               </td>
-               <td colspan="2">
-               <input type="text" name="creator_main_url" size="55" maxlength="160" value="http://"><br>
-                <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       Deine Adresse:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="creator_address" size="55" maxlength="160" value=""><br>
-                               <font size="-1"> <i>(optional)</i></font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       Deine Telefon-Nr.:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="creator_phone" size="20" maxlength="20" value=""><br>
-                       <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-
-               <tr>
-                       <td colspan="3" bgcolor="#FFFFFF">&nbsp;</td>
-       </tr>
-
-       <tr>
-               <td>
-                       Die Sprache deines Beitrages:
-               </td>
-               <td colspan="2">
-                       <select name="to_language">
-                               <list languagePopUpData as l>
-                               <option value="${l.key}">${l.value}</option>
-                               </list>
-                       </select>
-                       &nbsp;&nbsp;<font size="-1"><i>(optional)</i></font>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top">
-                       Dein <b>Artikel</b>:<br>
-                       <font size="-2">(Der Haupttext Deines Beitrages)</font>
-               </td>
-               <td bgcolor="#003300" colspan="2">
-                       &nbsp; <textarea name="content_data" rows="20" cols="55" wrap="soft"></textarea>
-                       <br><br>
-               </td>
-       </tr>
-
-       <tr>
-               <td>
-                       <b>Medien:</b>
-               </td>
-               <td colspan="2">
-                       Hier kannst Du eine oder mehrere Bild-, Audio- oder Videodateien zu Deinem Artikel hochladen.<br>
-                       <font size="-2">(Dazu wählst Du mit "Durchsuchen.." die entsprechende Datei auf Deiner Festplatte aus.)</font>
-               </td>
-       </tr>
-<list data.mediafields as m>
-       <tr>
-               <td>Media ${m}</td>
-               <td colspan="2">
-                       <INPUT TYPE="file" NAME="media${m}">
-                       <br><font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-               Medienunterschrift ${m}:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="media_title${m}" size="40" maxlength="80" value=""><br>
-                                       <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-</list>
-
-       <tr>
-               <td colspan="3" bgcolor="#FFFFFF">&nbsp;</td>
-       </tr>
-
-       <tr>
-               <td align="left" valign="center">
-
-                                             <!-- text -->
-                       Bitte drücke den Verschicken-Knopf<b> nur einmal</b>!<br>
-                       In wenigen Minuten erscheind Dein Beitrag dann auf der
-                       <a href="http://de.indymedia.org/open.html" target="_blank">
-                       <b>"Open Posting"</b></a> - Seite. &nbsp;
-                       Das ist nicht die Startseite.<br>
-                       Manchmal kann es aber aufgrund technischer Probleme
-                       etwas dauern bis er erscheint.
-                       <br>
-                       Die <b>Moderationskriterien</b> kannst Du
-                       <a href="http://de.indymedia.org/static/moderation.html" target="_blank"><b>hier nachlesen</b></a><br>
-
-               </td>
-               <td bgcolor="#663399" valign="center" align="center">
-       <input type="submit" value="Beitrag abschicken">
-
-               </td>
-               <td bgcolor="#003300" valign="center" align="center">
-                       <input type="reset" value="Formular l&ouml;schen">
-               </td>
-       </tr>
-</form>
-
-</table>
-
-
-
-</body>
-</html>
diff --git a/templates-dist/de/open/posting_done.template b/templates-dist/de/open/posting_done.template
deleted file mode 100755 (executable)
index 61873d2..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html>
-<head>
-       <title>indymedia.de | open posting</title>
-</head>
-
-<body bgcolor="White" text="Black" link="#006600" vlink="#666666" alink="Red">
-
-<table width="100%" border="0" cellspacing="0" cellpadding="4" bgcolor="#cccccc">
-       <tr>
-               <td align="center" bgcolor="#666666">
-               <font color="White">Hurra, Du hast Deinen Artikel abgeschickt!</font></td>
-       </tr>
-       <tr>
-               <td bgcolor="#eeeeee"><font color="#000000">
-
-
-<br>
-Dein Artikel landet in einigen Minuten auf der
-<a href="http://de.indymedia.org/open.html">
-"Open Posting"</a> - Seite. Das ist nicht die Startseite.
-Die Moderationskriterien kannst Du
-<a href="http://de.indymedia.org/static/moderation.html">hier lesen</a><br><br>
-<center><EM>Gedulde Dich einen Moment! Es lohnt sich!</EM></center><br><br>
-
-       </font>
-       </td>
-</tr>
-
-<tr>
-       <td valign="top" align="center" bgcolor="#666666">
-       <a href="javascript:history.go(-2)"><font color="White"><b>&gt;&gt; Zur&uuml;ck</b></font></a>
-               </td>
-       </tr>
-</table>
-</body>
-</html>
diff --git a/templates-dist/de/open/posting_dupe.template b/templates-dist/de/open/posting_dupe.template
deleted file mode 100755 (executable)
index df85132..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html>
-<head>
-       <title>indymedia.de | open posting - Posting-Duplikat</title>
-</head>
-
-<body bgcolor="White" text="Black" link="white" vlink="#009900" alink="Red">
-
-<table width="100%" border="0" cellspacing="0" cellpadding="10">
-       <tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <font color="White"><b>
-                               Immer ruhig mit den jungen Pferden!
-                       </b></font
-               </td>
-       </tr> 
-       <tr>
-               <td bgcolor="003300" width=70%>
-                       <font color="White">
-                               <br>
-                                       Du hast vermutlich den Reload-Button
-                                       benutzt oder versucht, Deinen Artikel noch einmal zu posten. Das ist aber
-                                       unn&ouml;tig. <br>
-                                       Die Tatsache, dass Du diesen Text liest, bedeutet, dass Dein
-                                       Posting schon angekommen ist. Er wird gleich auf der Seite auftauchen. Versprochen.
-                               <br><br>
-                                       Technischer Hintergrund ist, daß de.indy &uuml;ber einen
-                                       Proxy-Server läuft und da dauert es schon mal ein paar Minuten, bis ein neues Posting erscheint.
-                               <br> 
-                               <center><em>Keine Panik</em></center><br>
-                               <br>
-                       </font>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <a href="javascript:history.go(-2)"><font color="White"><b>&gt;&gt; Zur&uuml;ck</b></font></a>
-               </td>
-       </tr> 
-</table>
-
-</body>
-</html>
diff --git a/templates-dist/de/open/posting_en.template b/templates-dist/de/open/posting_en.template
deleted file mode 100755 (executable)
index f23b931..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-    <html>
-    <head>
-    <title>indymedia.de | open posting</title>
-    </head>
-
-    <body bgcolor="#000000"
-    fgcolor="white"
-    link="#ff9900"
-    alink="#999900"
-    vlink="#999900"
-    text="white">
-
-    <font face="Helvetica, Arial" color="white">
-
-<TABLE cellPadding=5 cellSpacing=0 border=0>
-
-<tr>
-<td valign=top align=left>
-<font face="Helvetica, Arial" size=-1 color="white">
-
-<i><b>publish your article</b></i><br>
-<p>
-
-<p>
-<table width="100%" bgcolor="#555555"><tr><td>
-<font size=+1>
-<b>Posting a piece on indymedia's newswire</b></font>
-</td></tr></table>
-<p>
-
-<p>
-<ul>
-<li><a href="#form">jump straight to the form!</a>
-</ul>
-
-
-<p>
-
-<blockquote>
-<font size=+2><b>T</b></font>he Independent Media Center is a collectively 
-run media outlet for the creation of radical, accurate, and passionate 
-tellings of the truth. We work out of a love and inspiration for people 
-to who continue to work for a better world, despite corporate media's 
-distortions and unwillingness to cover the efforts to free humanity. 
-
-<p>
-
-Indymedia is a democratic newswire. We <b>want</b> to see and hear the real
-stories, news, and opinions from around the world. While we struggle to 
-maintain the news wire as a completely open fourm we <i>do</i> monitor it
-and remove posts. <br>
-You can see the decisons we have made by viewing the
-<a href="http://www.indymedia.org/search-process.php3?hidden=true">hidden articles page</a>. In the 
-overwhelming number of cases, stories have been removed for the following
-reasons: <a href="http://www.indymedia.org/display.php3?article_id=4080">being comments, not news</a>, duplicate posts, 
-<a href="http://www.indymedia.org/display.php3?article_id=4004">obviously false or 
-libelous posts</a>, or inappropriate content.
-<br>
-We are working on the technology 
-to make this process more transparent, so that you can see when such decisions 
-have been made, and why.
-In future, we want our audience to be part of this process too. For the meantime,
-you can check out stories that we have choosen to remove by looking at the 
-<a href="http://www.indymedia.org/search-process.php3?hidden=true">hidden articles</a> page. 
-</blockquote>
-
-<br>
-
-Please use this form to contribute <b>new</b> stories and ideas.  We think
-comments belong with the story being discussed. So to have your say in response
-to a story on the site, please use the <b>add your comments</b> link at the
-bottom of the stories.
-
-<p>
-
-We think stories contributed to this site should be free for non-profit re-use.
-Copy left is an idea central to indymedia. For more information, check out
-<a href="http://www.opencontent.org">www.opencontent.org</a>. If you want to change that for your story, please give your conditions in the
-summary.
-<p>
-You can use this form to publish your text article, audio segment, video
-footage, or picture.  Please focus on activism issues and events. We (the
-people organising this site) may rearrange the display of submitted stories.
-
-<p>
-
-After stories have been published, they can be edited, linked or even deleted
-by the collective running this site, using the <a
-href="display.php3?led=y">story administration</a> page (password required). 
-<br>
-
-
-<p>
-
-
-<b>Remember:</b>
-
-<ul>
-
-<li>please post <b>news items only</b>, leave your comments for discussion
-areas
-
-<li>please try to post <b>just one copy</b> of your story - please only press 
-the publish button <b>once</b>. 
-
-</ul>
-
-
-<p>
-
-<a name="form"></a>
-
-
-
-<form enctype="multipart/form-data" action="new_data-process.php3" method=post>
-  <input type="hidden" name="MAX_FILE_SIZE" value="100000000"><p>
-  <table border=1 cellspacing=0 width="100%">
-       <tr bgcolor="">
-         <td bgcolor="#333333">
-               <table width="100%" bgcolor="#555555">
-               <tr>
-                       <td>
-                               <font face="Helvetica, Arial">
-                               <center><font size=+2><b>Publishing Form</b></font></center>
-                       </td>
-               </tr>
-               </table>
-               <br>
-               <font face="arial" size=+2><b> Step 1:</b><br><br></font>
-               <font face="arial" size=+1><b>Give your piece a title</b><br>
-           <input type="text" name="title" size="80" maxlength="80" value="">    
-       <p>
-               <font face="arial">
-       <b>Author or producer of the piece you're posting</b><br>
-           <input type="text" name="creator" size="80" maxlength="80" value="">
-           <br>
-       <p>
-        <b>the summary</b></font><font size=-1> (no more than 6 lines - include the 
-               duration of the piece if you are publishing audio or video)<br></font>
-           <textarea name="summary" rows="3" cols="80" wrap=virtual
-    
-></textarea>
-<br><br>
-
-
-
-    <table border=0>    
-    <tr><td><font face="Helvetica, Arial" size=-1>
-    including contact details below is optional but will mean our
-    audience (including journalists) can contact you about your story,
-    including for possible re-use in other places
-    </font>
-    </td></tr>
-    </table>
-
-    <table border=0>
-    <tr><td><font face="Helvetica, Arial">
-    <b>email</b> <i>optional</i>
-    </font></td>
-    <td><font face="Helvetica, Arial">
-    <b>phone</b> <i>optional</i>
-    </font></td>
-    <tr><td><font face="Helvetica, Arial">
-    <input type="text" name="contact" size="30" maxlength="80"
-    
-value="">
-    
-    </font></td>
-    <td><font face="Helvetica, Arial">
-    <input type="text" name="phone" size="30" maxlength="80"
-    
-value="">
-
-    </td></tr>
-    </table>
-
-    <p>
-
-    <table border=0>
-    <tr><td><font face="Helvetica, Arial">
-    <b>address</b> <i>optional</i>
-    </font></td></tr>
-    <tr><td>
-    <input type="text" name="address" size="70" maxlength="160"
-    
-value="">
-    
-    </td></tr>
-    </table>
-    <p>
-
-    <b>language</b><br>
-the language of your submission<BR>
-<select name="storylang">
-<option>czech</option>
-<option>dutch</option>
-<option selected>english</option>
-<option>french</option>
-<option>german</option>
-<option>italian</option>
-<option>japanese</option>
-<option>polish</option>
-<option>russian</option>
-<option>spanish</option>
-</select><BR>
-
-
-
-    <p>
-    <b>web address</b> <i>optional</i> </font><font size=-1>This provides a link to your website.<br>
-    </font><input type="text" name="link" size="70" maxlength="160"
-value="">
-    
-    <br><br>
-
-    </font>
-  </td></tr></table>
-
-  <p>
-
-<!-- STARTS SECOND STEP OF ENTRY FORM -->
-  <table border=1 cellspacing=0 width="100%" >
-    
-<tr bgcolor="#440000">
-       
-    
-    
-        
-    <td>
-    
-    
-    <font size=+2> <b>Step 2:</b><br><br>
-    <font face="Helvetica, Arial">
-    <font size=+1>Text that you would like to appear with your story.
-    If you are posting a text only piece, you can type or paste your story here.</font><br>
-<font size=-1>
-    the article (if you enter HTML code, select "html format" from the <b>type of upload</b> drop down box below)<br></font>
-    <textarea name="article" rows="20" cols="80" wrap="soft"
-></textarea>
-
-    </font>
-  </td></tr></table>
-
-  <p>
-
-
-
-<!-- STARTS THIRD STEP OF ENTRY FORM -->
-
-  <table border=1 cellspacing=0 width="100%">
-
-<tr bgcolor="#330000">
-       
-  
-    <td>
-    
-    
-    <font size=+2><b>Step 3:</b>
-    
-    <font face="Helvetica, Arial">
-   <font size=+1><b>multimedia stories</b></font><br>
-<font size=-1>
-Send in this file 
-      (limit 100 megs): 
-      <INPUT NAME="linked_file" TYPE="file"><p>
-    
-</font>
-    <font size=+1>
-  <B>Audio/Video/Images:</B></font><font size=-1> You need to
-    select the proper type for the content you are uploading. If you
-   are only uploading text, leave the setting on plain text. You
-   can upload html tags in a story if you wish.<br><br>
-    
-    <B>Type of upload:</B>     
-    <select name="mime_type">
-    
-<option selected value="text/plain">plain text
-    <option value="text/html">html format
-    <option value="text/x-url">just a web address
-    <option value="image/gif">gif image
-    <option value="image/jpeg">jpeg/jpg image
-    <option value="audio/mpeg">mp3 audio
-    <option value="audio/x-pn-realaudio">realaudio
-    <option value="video/x-pn-realvideo">realvideo
-    </select>
-    <p>
-    
-  
-    </font>
-  </td></tr></table>
-
-
-    
-
-  <P> <B>Press the publish button only once.</B> Uploading files can take a
-  long time and the confirmation page won't be shown until after the file has
-  finished uploading.
-
-  <center>
-  <p>
-  <input type="submit" name="action" value="Publish!">
- <input type=hidden name="publishtype" value="webcast">  <!--<input type=image src="uploads/pub-button.jpg" name="sub">-->
-  <p>
-  <input type="reset" value="clear form">
-  </center>
-       
-</form>
-
-<!-- $Id: posting_en.template,v 1.1 2001/08/25 12:37:39 idfx Exp $ -->
-
-</font>
-</td></tr></table>
-
-<!--
-<p>
-<center>
-<table width="100%" border=0 cellspacing=0 cellpadding=0>
-<tr><td  bgcolor="#66ccff" align=center>
-<font face="Helvetica, Arial">
-<a href="../calendar/?display=list&days=14">events</a> | 
-<a href="../groups/">groups</a> | 
-<a href="../news/">news</a> | 
-<a href="../howto/">how&nbsp;to</a> | 
-<a href="../about/">about&nbsp;us</a> |
-<a href="http://www.active.org.au/">www.active.org.au
-</a>
-</font>
-</table>
-
-<p>
-
-<font face="Helvetica, Arial">
-technology by <a href="http://www.cat.org.au">cat@lyst</a> /
-<a
-href="http://www.active.org.au/sydney/about/#howorg">active
-version 1.31</a>
-</font>
-</center>
------>
-</font></body></html>
-<!-- exiting cast-class -->
-
-
-
diff --git a/templates-dist/en/open/comment.template b/templates-dist/en/open/comment.template
deleted file mode 100755 (executable)
index 4d8e79d..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-<html>
-<head><title>indymedia.de | comment.commit</title></head>\r
-<body bgcolor="white" text="black" link="#006600" vlink="#009900" alink="red">\r
-
-<form action="${config.openAction}" method=post>
-<input type="hidden" name="do" value="inscomment">
-
-<table width="100%" border="0" cellspacing="0" cellpadding="4" bgcolor="silver">
-       <tr>
-               <td bgcolor="#663399" colspan="3">
-                       <font color="White"><b>Adding a coment to an article</b></font>
-               </td>
-       </tr>
-       <tr>
-               <td bgcolor="#003300" colspan="3">
-                       <p>
-                               <font color="white">
-                               Just some hints (introduction)on how to write  comments for
-                               Indymedia. here
-                               </font>
-                       </p>
-
-               </td>
-       </tr>
-       <tr>
-               <td bgcolor="#663399" colspan="3">
-                       <font face="Helvetica, Arial" color="white" size=+2><b>Comment-form</b></font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       <b>titel of comment</b>
-               </td>
-               <td colspan="2">
-                       <input type="text" name="title" size="45" maxlength="45"> <font size="-1" color="#663399">(has to be filled out)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       <b>your name:</b>
-               </td>
-               <td colspan="2">
-                       <input type="text" name="creator" size="20" maxlength="45"> <font size="-1" color="#663399">(muss ausgef&uuml;llt werden)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                        your eMail
-               </td>
-               <td colspan="2">
-                       <input type="text" name="email" size="30" maxlength="80"> <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       your Web Adress:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="main_url" size="40" maxlength="160" value="http://"> <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       your Telefon-Nr.:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="phone" size="30" maxlength="80"> <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       your Adress:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="address" size="40" maxlength="160"><font size="-1"> <i>(optional)</i></font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       language of your comment
-               </td>
-               <td colspan="2">
-                       <select name="to_language">
-                               <option value="0">de</option>
-                               <option value="1">en</option>
-                       </select>
-                       <font size="-1"><i>(optional)</i></font>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top">
-                       <b>your comment</b>
-               </td>
-               <td bgcolor="#003300" colspan="2">
-                       &nbsp;<textarea name="description" rows="20" cols="60" wrap=virtual></textarea>
-                       <br><br>
-               </td>
-       </tr>
-       <tr>
-               <td>&nbsp;
-               </td>
-               <td bgcolor="#663399" valign="top" align="center">
-                       <br>
-                       &nbsp;<input type="submit" value="Kommentar abschicken"><br>
-
-               </td>
-               <td bgcolor="#003300" valign="top" align="center">
-                       <br>
-                       &nbsp;<input type="reset" value="Formular l&ouml;schen"><br>
-                       <input type="hidden" name="to_media" value="${aid}">
-                       <br>
-               </td>
-       </tr>
-</table>
-
-</form>
-
-</body>
-</html>
diff --git a/templates-dist/en/open/comment.template.en b/templates-dist/en/open/comment.template.en
deleted file mode 100755 (executable)
index 99eae4e..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-<html>
-<head><title>indymedia.de | comment.commit</title></head>
-<body bgcolor="black">
-<table><tr>
-<td valign=top align=left>
-<font face="Helvetica, Arial" size=-1 color="white">
-<i><b>adding a comment</b></i><br>
- <!--endmenu--> 
-
-<h3>Guidelines for commenting on news articles</h3>
-Thanks for contributing to the dynamic alternative news on active!
-<br><p>
-Add any responses to news articles that you feel are appropriate to 
-www.indy's goals eg: social activitism, local communities, ecology and development. 
-<br><p>
-The response article can be in any type of format you want, from traditional academic discourse, to subjective personal rants.
-<br><p>
-Please keep it on topic and concise.
-<br><p>
-<br><br> * = required field
-<p>
-
-<form action="${config.openAction}" method=post>
-<input type="hidden" name="do" value="inscomment">
-<blockquote>
-       <table border=1 cellspacing=0 width="100%">
-       <tr bgcolor="">
-       <td><font face="Helvetica, Arial" color="white">
-       <b>title for your comment (*)</b><br>
-       <input type="text" name="title" size="45" maxlength="45">
-       <p>
-       <b>your name (*)</b> <br>
-       <input type="text" name="creator" size="20" maxlength="45"><br>
-       <p>
-       <table border=0>
-       <tr>
-       <td><font face="Helvetica, Arial" color="white">
-       email (<i>optional</i>)
-       </font></td>
-       <td><font face="Helvetica, Arial" color="white">
-       web address (begin with http://) (<i>optional</i>)
-       </font></td></tr>
-       <tr>
-       <td>
-       <input type="text" name="email" size="30" maxlength="80">
-       </td><td>
-       <input type="text" name="main_url" size="40" maxlength="160">
-       </td></tr></table>
-
-       <p><table border=0>
-       <tr><td><font face="Helvetica, Arial" color="white">
-       phone (<i>optional</i>)
-       </font></td>
-       <td><font face="Helvetica, Arial" color="white">
-       address (<i>optional</i>)
-       </font></td></tr>
-       <tr><td>
-       <input type="text" name="phone" size="30" maxlength="80">
-       </td><td>
-       <input type="text" name="address" size="40" maxlength="160">
-       </td></tr>
-       <tr><td>
-
-          <font face="Helvetica, Arial" color="white"> <b>language</b><br>
-the language of the submission<BR></font>
-<select name="to_language">
-<option value="0">de</option>
-<option value="1" selected>en</option>
-</select><BR>
-</td></tr>
-       </table>
-       <p>
-       <b>your comment*</b><br>
-       <textarea name="description" rows="20" cols="60" wrap=virtual></textarea>
-       </table>
-       <center>
-       <input type="submit" value="add my comment">
-       <input type="reset" value="clear form">
-       <input type="hidden" name="to_media" value="${aid}">
-       </center>
-</form>
-</blockquote>
-</font>
-</td>
-</tr></table>
-</body>
-</html>
diff --git a/templates-dist/en/open/comment_done.template b/templates-dist/en/open/comment_done.template
deleted file mode 100755 (executable)
index fc0a7a1..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html>
-<head>
-       <title>indymedia.de | open posting</title>
-</head>
-
-<body bgcolor="White" text="Black" link="white" vlink="#009900" alink="Red">
-
-<table width="100%" border="0" cellspacing="0" cellpadding="10">
-       <tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <font color="White"><b>Your comment is on the way to the Website!</b></font
-               </td>
-       </tr>
-       <tr>
-               <td bgcolor="003300">
-                       <font color="White">
-                               <br>
-                               Er landet direkt in einem intelligenten Filter - und wenn er keine rassistischen, sexistischen oder faschistischen Inhalte oder Werbung enth&auml;lt, wird er in K&uuml;rze auf http://www.germany.indymedia.org/newswire/ auftauchen.<br>
-                               <br> 
-                               <center><em>Gedulde Dich einen Moment - Es lohnt sich!</em></center><br>
-                               <br>
-                       </font>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <a href="javascript:history.go(-2)"><font color="White"><b>&gt;&gt; Zur&uuml;ck zum kommentierten Artikel</b></font></a>
-               </td>
-       </tr> 
-</table>
-
-</body>
-</html>
diff --git a/templates-dist/en/open/comment_dupe.template b/templates-dist/en/open/comment_dupe.template
deleted file mode 100755 (executable)
index 31dcb0b..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html>
-<head>
-       <title>indymedia.de | open posting - comment dupe</title>
-</head>
-
-<body bgcolor="White" text="Black" link="white" vlink="#009900" alink="Red">
-
-<table width="100%" border="0" cellspacing="0" cellpadding="10">
-       <tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <font color="White"><b>
-                               Keep calm. Things will happen soon.
-                       </b></font
-               </td>
-       </tr> 
-       <tr>
-               <td bgcolor="003300">
-                       <font color="White">
-                               <br>
-                                       You probably clicked on the reload button or submitted
-                                       your comment a second time. The fact that you can read
-                                       this text means that your comment has been recieved and
-                                       will soon be included in the article page.
-                               <br> 
-                               <center><em>Don't panic</em></center><br>
-                               <br>
-                       </font>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <a href="javascript:history.go(-2)"><font color="White"><b>&gt;&gt; Back to the commented article</b></font></a>
-               </td>
-       </tr> 
-</table>
-
-</body>
-</html>
diff --git a/templates-dist/en/open/minimal_posting.template b/templates-dist/en/open/minimal_posting.template
deleted file mode 100755 (executable)
index 3e3333c..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-<html>
-
-this is a minimal template need to successfully publish a story.  the
-current en/open/posting.template is out of date to the point of being
-broken.  this works.  though it could use a little design help :)
-
-<!-- begin MEDIANUM form -->
-<!-- how many media items to upload? -->
-<!-- submit simply re-displays *this* form -->
-<form action="${openAction}?do=addposting" method="post">
-  How many media items: 
-  <input type="text" name="medianum"
-   value="${medianum}">&nbsp;
-  <input type="submit" value="Update">
-</form>
-<!-- end MEDIANUM form -->
-
-<!-- begin MAINCONTENT form -->
-<!-- submit attempts to add new story -->
-<form enctype="multipart/form-data" action="${openAction}?do=insposting" method="post">
-
-Title: <input type="text" name="title" size="45" 
-maxlength="45" value=""> 
-<p>
-<!-- Pull down of available topics -->
-<!-- iterate over all available topics: themenPopupData -->
-<!-- if any topics are passed in (e.g. ?to_topic=3,2) then -->
-<!-- set topic to selected -->
-Topic: 
-<select name="to_topic" size="3" multiple> 
-  <list data.themenPopupData as t>
-     <option value="${t.key}"
-         <list to_topic as to>
-            <if (t.key == to)>selected</if>
-        </list>
-     >${t.value}</option>
-  </list>
-</select>
-<p>
-Author: <input type="text" name="creator" size="45" maxlength="45">
-<p>
-Summary:  <textarea name="description" rows="6" cols="45" wrap=virtual></textarea>
-<p>
-Your Email: <input type="text" name="creator_email" size="45"
-maxlength="80" value="">
-<p>
-Your Web Address:
-<input type="text" name="creator_main_url" size="45" maxlength="160" value="http://">
-<p>
-Address: <input type="text" name="creator_address" size="45" maxlength="160" value="">
-<p>
-Phone #: <input type="text" name="creator_phone" size="20" maxlength="20" value="">
-<p>
-<!-- generate list of known languages -->
-Language:
-<select name="to_language">
-  <list data.languagePopUpData as l>
-    <option value="${l.key}">${l.value}</option>
-  </list>
-</select>
-<p>
-Your Article:
-<textarea name="content_data" rows="20" cols="45" wrap="soft"></textarea>
-<p>
-<!-- generate N fields for uploading files -->
-<!-- where N is medianum -->
-Media Uploads:
-<list data.mediafields as m>
-    File ${m}
-    <INPUT TYPE="file" NAME="media${m}">
-    <br>
-     Title ${m}: <input type="text" name="media_title${m}" size="40" maxlength="80" value="">
-</list>
-<p>
-<input type="submit" value="Post"><br>
-
-</html>
diff --git a/templates-dist/en/open/posting.template b/templates-dist/en/open/posting.template
deleted file mode 100755 (executable)
index 47489d6..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//DE">
-<html>\r
-<head>\r
-       <title>indymedia.de | open posting</title>\r
-       <meta name="description" content="Indymedia Germany | Unabh&auml;ngiges Medienzentrum">\r
-       <meta name="author" content="IMC Kollektiv">\r
-       <meta name="keywords" content="Freie Medien, Gegen&ouml;ffentlichkeit">\r
-       <meta name="date" content="### Date ###Time">\r
-       <meta http-equiv="Content-Type" content="text/html; charset=iso-8559-1">\r
-       <meta name="robots" content="index">\r
-       <meta name="robots" content="follow">\r
-       <link rel=stylesheet type="text/css" href="${config.productionHost}/style/formate.css">
-</head>
-
-<body bgcolor="White" text="Black" link="white" vlink="white" alink="Red">
-
-
-<table width="99%" border="0" cellspacing="0" cellpadding="8" bgcolor="silver">
-       <tr>
-               <td align="center" bgcolor="#663399" colspan="3">
-                       <font face="Helvetica, Arial"><a href="#form">Jump dirctly to the form.</a></font>
-               <br>
-               </td>
-       </tr>
-       <tr>
-               <td align="center" colspan="3">
-                       <br>
-                       <font size="+2" face="Helvetica, Arial">Publish your article !</font><br><br>
-               </td>
-       </tr>
-       <tr>
-               <td colspan="3" bgcolor="white">
-                       <h3>Short introduction to open-posting in germany.indymedia</h3>
-
-                       <p><b>Short text about IMC and the idea of open-publishing</b> too lazy to translate all of this ;-) ----Das Independent Media Center ist ein kollektiv gef&uuml;hrtes Mediennetzwerk zur Produktion von radikalen, passionierten und durchaus auch subjektiven,  pers&ouml;nlichen Stellungnahmen verschiedenster Menschen 'auf der Strasse', z.B. vor, w&auml;hrend oder nach Kampagnen,  polit. Ereignissen oder aus der allt&auml;glichen Lebenswelt.  Wir arbeiten aus Liebe und aus Respekt gegen&uuml;ber Menschen, die sich f&uuml;r eine bessere, lebenswertere Welt engagieren, und deren Arbeit von den Medienkonzernen nicht oder nur verzerrt dargestellt wird.</p>
-
-                       <p>Indymedia ist ein demokratischer Nachrichtenkanal. Wir <b>wollen</b> Beitr&auml;ge, Artikel, Meinungen und Infos aus der ganzen Welt ver&ouml;ffentlichen. Alle Beitr&auml;ge werden sofort unzensiert ver&ouml;ffentlicht, sofern sie nicht in die im <b>Mission Statement</b> genannten Kategorien fallen. Allerdings erscheinen sie dann nicht gleich auf der Startseite, sondern auf einer eigenen Open-Posting-Seite. Dort werden sie von wechselnden Moderationsteams gegengelesen und
-                       anschliessend auf den newswire der Starttseite weitergeleitet.<br>
-                       Um diesen Ausschlussprozess so transparent wie m&ouml;glich zu gestalten, k&ouml;nnen alle nicht ver&ouml;ffentlichten Beitr&auml;ge  per e-mail angefordert weren.</p>
-
-                       <p>Bitte benutze dieses Formular nur, um <b>neue</b> Beitr&auml;ge und Ideen beizusteuern. Kommentare geh&ouml;ren zu dem jeweils diskutierten Beitrag. Wenn Du etwas zu einem Beitrag zu sagen hast, dann benutze daf&uuml;r bitte die <b>Kommentar-Funktion</b> am Ende jedes Beitrags.</p>
-
-                       <p>Unser Auffassung nach sollten Beitr&auml;ge, die an diese Site geschickt werden, frei zur nicht-kommerziellen Wiederverwertung sein. Wenn Du nicht m&ouml;chtest, dass das f&uuml;r Deinen Beitrag zutrifft, dann nenne Deine Konditionen in der Zusammenfassung.</p>
-
-                       <p>Du kannst dieses Formular benutzen, um Deinen Artikel, Deinen Audio-Beitrag, Deinen Video-Beitrag oder Deine Fotos zu ver&ouml;ffentlichen. Bitte beschr&auml;nke Dich auf  Beitr&auml;ge zu politischem oder sozialem Aktivismus. Wir (die Menschen, die diese Site organisieren) behalten uns vor, die Pr&auml;sentation der zugeschickten Beitr&auml;ge zu ver&auml;ndern. Weitere Informationen findest Du im <b>Mission Statement</b>.</p>
-
-                       <p>Nach dem Beitr&auml;ge ver&ouml;ffentlicht wurden, k&ouml;nnen sie vom Kollektiv, das diese Site betreut, editiert, verlinkt oder sogar gel&ouml;scht werden.</p>
-                       <br>
-
-                       <p><b>Zur Erinnerung:</b><p>
-
-                       <ul>
-                               <li>Bitte schicke <b>nur News-Artikel</b> und benutze zum Kommentieren von Artikeln das <b>Kommentierformular</b>, das Du unter jedem Artikel findest.
-                               <li>Bitte schicke <b>nur eine Kopie</b> Deines Artikels - Bitte dr&uuml;cke den Verschicken-Knopf nur einmal</b>.
-        <li><b>Ver&ouml;ffentliche nur selbst erstellte Beitr&auml;ge. (Keine Agenturmeldungen, Zeitungsartikel oder &auml;hnliches!)</b>.
-                       </ul>
-               </td>
-       </tr>
-<form action="${config.openAction}?do=addposting" method="post">
-       <tr>
-               <td>Number of Media Items</td>
-               <td colspan="2"><input type="text" name="medianum" value="${medianum}">&nbsp;<input type="submit">
-       </tr>
-</form>
-
-<a name="form"></a>
-<form enctype="multipart/form-data" action="${config.openAction}?do=insposting" method="post">
-
-       <tr>
-               <td bgcolor="#663399" colspan="3">
-                       <center><font size="+2" face="Helvetica, Arial" color="white"><b>Publishing Form</b></font></center>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top">
-                        <b>titel</b> of your article:
-               </td>
-               <td colspan="2" bgcolor="#003300">
-                       <input type="text" name="title" size="45" maxlength="45" value=""> <font size="-1" color="white"><br>(has to be filled out)</font>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top">
-                       <b>author</b> of this article:
-               </td>
-               <td colspan="2" bgcolor="#003300">
-                       <input type="text" name="creator" size="45" maxlength="45"> <font size="-1" color="white"><br>(has to be filled out)</font>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top">
-                       A short <b>abstract</b> of your article:</b>
-               </td>
-               <td colspan="2" bgcolor="#003300">
-                       <textarea name="description" rows="6" cols="45" wrap=virtual></textarea>
-                       <font size="-1" color="white"><br>(not more than <b>5 lines</b>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td colspan="3">
-               <font face="Helvetica, Arial" size=-1 color="#663399">
-               Contact information is optional but enables other people to get in touch with you.
-       </font>
-               </td>
-       </tr>
-
-       <tr>
-               <td>
-                       your eMail-Adress:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="creator_email" size="45" maxlength="80" value=""> <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       your Web Adress:
-               </td>
-               <td colspan="2">
-               <input type="text" name="creator_main_url" size="45" maxlength="160" value="http://">
-                <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       your Adress:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="creator_address" size="45" maxlength="160" value=""> <font size="-1"> <i>(optional)</i></font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       your Telefon-Nr.:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="creator_phone" size="20" maxlength="20" value=""> <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       language of your article:
-               </td>
-               <td colspan="2">
-                       <select name="to_language">
-                               <list languagePopUpData as l>
-                               <option value="${l.key}">${l.value}</option>
-                               </list>
-                       </select>
-                       <font size="-1"><i>(optional)</i></font>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top">
-                       your <b>article</b>:<br>
-                       fill in the text of your article here
-               </td>
-               <td bgcolor="#003300" colspan="2">
-                       &nbsp; <textarea name="content_data" rows="20" cols="45" wrap="soft"></textarea>
-                       <br><br>
-               </td>
-       </tr>
-
-       <tr>
-               <td>
-                       media:
-               </td>
-               <td colspan="2">
-                       upload media-files (so far only jpg|gif|mp3|avi|qt|mpeg)<br>
-               </td>
-       </tr>
-<list data.mediafields as m>
-       <tr>
-               <td>Media Item ${m}</td>
-               <td colspan="2">
-                       <INPUT TYPE="file" NAME="media${m}"> <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-       <tr>
-               <td>
-                       media sub-title ${m}:
-               </td>
-               <td colspan="2">
-                       <input type="text" name="media_title${m}" size="40" maxlength="80" value=""> <font size="-1">(<i>optional</i>)</font>
-               </td>
-       </tr>
-</list>
-
-       <tr>
-               <td><b          </td>
-               <td bgcolor="#663399" valign="top" align="center"><br>
-       &nbsp;<input type="submit" value="Submit (patience is a virtue!!)"><br>
-
-               </td>
-               <td bgcolor="#003300" valign="top" ge-aln="center">
-                       <br>
-                       &nbsp;<input type="reset" value="Form Reset"><br>
-               </td>
-       </tr>
-</table>
-
-
-
-</body>
-</html>
diff --git a/templates-dist/en/open/posting.template.en b/templates-dist/en/open/posting.template.en
deleted file mode 100755 (executable)
index 3f08bde..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-    <html>
-    <head>
-    <title>indymedia.de | open posting</title>
-    </head>
-
-    <body bgcolor="#000000"
-    fgcolor="white"
-    link="#ff9900"
-    alink="#999900"
-    vlink="#999900"
-    text="white">
-
-    <font face="Helvetica, Arial" color="white">
-
-<TABLE cellPadding=5 cellSpacing=0 border=0>
-
-<tr>
-<td valign=top align=left>
-<font face="Helvetica, Arial" size=-1 color="white">
-
-<i><b>publish your article</b></i><br>
-<p>
-
-<p>
-<table width="100%" bgcolor="#555555"><tr><td>
-<font size=+1>
-<b>Posting a piece on indymedia's newswire</b></font>
-</td></tr></table>
-<p>
-
-<p>
-<ul>
-<li><a href="#form">jump straight to the form!</a>
-</ul>
-
-
-<p>
-
-<blockquote>
-<font size=+2><b>T</b></font>he Independent Media Center is a collectively 
-run media outlet for the creation of radical, accurate, and passionate 
-tellings of the truth. We work out of a love and inspiration for people 
-to who continue to work for a better world, despite corporate media's 
-distortions and unwillingness to cover the efforts to free humanity. 
-
-<p>
-
-Indymedia is a democratic newswire. We <b>want</b> to see and hear the real
-stories, news, and opinions from around the world. While we struggle to 
-maintain the news wire as a completely open fourm we <i>do</i> monitor it
-and remove posts. <br>
-You can see the decisons we have made by viewing the
-<a href="http://www.indymedia.org/search-process.php3?hidden=true">hidden articles page</a>. In the 
-overwhelming number of cases, stories have been removed for the following
-reasons: <a href="http://www.indymedia.org/display.php3?article_id=4080">being comments, not news</a>, duplicate posts, 
-<a href="http://www.indymedia.org/display.php3?article_id=4004">obviously false or 
-libelous posts</a>, or inappropriate content.
-<br>
-We are working on the technology 
-to make this process more transparent, so that you can see when such decisions 
-have been made, and why.
-In future, we want our audience to be part of this process too. For the meantime,
-you can check out stories that we have choosen to remove by looking at the 
-<a href="http://www.indymedia.org/search-process.php3?hidden=true">hidden articles</a> page. 
-</blockquote>
-
-<br>
-
-Please use this form to contribute <b>new</b> stories and ideas.  We think
-comments belong with the story being discussed. So to have your say in response
-to a story on the site, please use the <b>add your comments</b> link at the
-bottom of the stories.
-
-<p>
-
-We think stories contributed to this site should be free for non-profit re-use.
-Copy left is an idea central to indymedia. For more information, check out
-<a href="http://www.opencontent.org">www.opencontent.org</a>. If you want to change that for your story, please give your conditions in the
-summary.
-<p>
-You can use this form to publish your text article, audio segment, video
-footage, or picture.  Please focus on activism issues and events. We (the
-people organising this site) may rearrange the display of submitted stories.
-
-<p>
-
-After stories have been published, they can be edited, linked or even deleted
-by the collective running this site, using the <a
-href="display.php3?led=y">story administration</a> page (password required). 
-<br>
-
-
-<p>
-
-
-<b>Remember:</b>
-
-<ul>
-
-<li>please post <b>news items only</b>, leave your comments for discussion
-areas
-
-<li>please try to post <b>just one copy</b> of your story - please only press 
-the publish button <b>once</b>. 
-
-</ul>
-
-
-<p>
-
-<a name="form"></a>
-
-
-
-<form enctype="multipart/form-data" action="new_data-process.php3" method=post>
-  <input type="hidden" name="MAX_FILE_SIZE" value="100000000"><p>
-  <table border=1 cellspacing=0 width="100%">
-       <tr bgcolor="">
-         <td bgcolor="#333333">
-               <table width="100%" bgcolor="#555555">
-               <tr>
-                       <td>
-                               <font face="Helvetica, Arial">
-                               <center><font size=+2><b>Publishing Form</b></font></center>
-                       </td>
-               </tr>
-               </table>
-               <br>
-               <font face="arial" size=+2><b> Step 1:</b><br><br></font>
-               <font face="arial" size=+1><b>Give your piece a title</b><br>
-           <input type="text" name="title" size="80" maxlength="80" value="">    
-       <p>
-               <font face="arial">
-       <b>Author or producer of the piece you're posting</b><br>
-           <input type="text" name="creator" size="80" maxlength="80" value="">
-           <br>
-       <p>
-        <b>the summary</b></font><font size=-1> (no more than 6 lines - include the 
-               duration of the piece if you are publishing audio or video)<br></font>
-           <textarea name="summary" rows="3" cols="80" wrap=virtual
-    
-></textarea>
-<br><br>
-
-
-
-    <table border=0>    
-    <tr><td><font face="Helvetica, Arial" size=-1>
-    including contact details below is optional but will mean our
-    audience (including journalists) can contact you about your story,
-    including for possible re-use in other places
-    </font>
-    </td></tr>
-    </table>
-
-    <table border=0>
-    <tr><td><font face="Helvetica, Arial">
-    <b>email</b> <i>optional</i>
-    </font></td>
-    <td><font face="Helvetica, Arial">
-    <b>phone</b> <i>optional</i>
-    </font></td>
-    <tr><td><font face="Helvetica, Arial">
-    <input type="text" name="contact" size="30" maxlength="80"
-    
-value="">
-    
-    </font></td>
-    <td><font face="Helvetica, Arial">
-    <input type="text" name="phone" size="30" maxlength="80"
-    
-value="">
-
-    </td></tr>
-    </table>
-
-    <p>
-
-    <table border=0>
-    <tr><td><font face="Helvetica, Arial">
-    <b>address</b> <i>optional</i>
-    </font></td></tr>
-    <tr><td>
-    <input type="text" name="address" size="70" maxlength="160"
-    
-value="">
-    
-    </td></tr>
-    </table>
-    <p>
-
-    <b>language</b><br>
-the language of your submission<BR>
-<select name="storylang">
-<option>czech</option>
-<option>dutch</option>
-<option selected>english</option>
-<option>french</option>
-<option>german</option>
-<option>italian</option>
-<option>japanese</option>
-<option>polish</option>
-<option>russian</option>
-<option>spanish</option>
-</select><BR>
-
-
-
-    <p>
-    <b>web address</b> <i>optional</i> </font><font size=-1>This provides a link to your website.<br>
-    </font><input type="text" name="link" size="70" maxlength="160"
-value="">
-    
-    <br><br>
-
-    </font>
-  </td></tr></table>
-
-  <p>
-
-<!-- STARTS SECOND STEP OF ENTRY FORM -->
-  <table border=1 cellspacing=0 width="100%" >
-    
-<tr bgcolor="#440000">
-       
-    
-    
-        
-    <td>
-    
-    
-    <font size=+2> <b>Step 2:</b><br><br>
-    <font face="Helvetica, Arial">
-    <font size=+1>Text that you would like to appear with your story.
-    If you are posting a text only piece, you can type or paste your story here.</font><br>
-<font size=-1>
-    the article (if you enter HTML code, select "html format" from the <b>type of upload</b> drop down box below)<br></font>
-    <textarea name="article" rows="20" cols="80" wrap="soft"
-></textarea>
-
-    </font>
-  </td></tr></table>
-
-  <p>
-
-
-
-<!-- STARTS THIRD STEP OF ENTRY FORM -->
-
-  <table border=1 cellspacing=0 width="100%">
-
-<tr bgcolor="#330000">
-       
-  
-    <td>
-    
-    
-    <font size=+2><b>Step 3:</b>
-    
-    <font face="Helvetica, Arial">
-   <font size=+1><b>multimedia stories</b></font><br>
-<font size=-1>
-Send in this file 
-      (limit 100 megs): 
-      <INPUT NAME="linked_file" TYPE="file"><p>
-    
-</font>
-    <font size=+1>
-  <B>Audio/Video/Images:</B></font><font size=-1> You need to
-    select the proper type for the content you are uploading. If you
-   are only uploading text, leave the setting on plain text. You
-   can upload html tags in a story if you wish.<br><br>
-    
-    <B>Type of upload:</B>     
-    <select name="mime_type">
-    
-<option selected value="text/plain">plain text
-    <option value="text/html">html format
-    <option value="text/x-url">just a web address
-    <option value="image/gif">gif image
-    <option value="image/jpeg">jpeg/jpg image
-    <option value="audio/mpeg">mp3 audio
-    <option value="audio/x-pn-realaudio">realaudio
-    <option value="video/x-pn-realvideo">realvideo
-    </select>
-    <p>
-    
-  
-    </font>
-  </td></tr></table>
-
-
-    
-
-  <P> <B>Press the publish button only once.</B> Uploading files can take a
-  long time and the confirmation page won't be shown until after the file has
-  finished uploading.
-
-  <center>
-  <p>
-  <input type="submit" name="action" value="Publish!">
- <input type=hidden name="publishtype" value="webcast">  <!--<input type=image src="uploads/pub-button.jpg" name="sub">-->
-  <p>
-  <input type="reset" value="clear form">
-  </center>
-       
-</form>
-
-<!-- $Id: posting.template.en,v 1.1 2001/09/26 09:34:27 idfx Exp $ -->
-
-</font>
-</td></tr></table>
-
-<!--
-<p>
-<center>
-<table width="100%" border=0 cellspacing=0 cellpadding=0>
-<tr><td  bgcolor="#66ccff" align=center>
-<font face="Helvetica, Arial">
-<a href="../calendar/?display=list&days=14">events</a> | 
-<a href="../groups/">groups</a> | 
-<a href="../news/">news</a> | 
-<a href="../howto/">how&nbsp;to</a> | 
-<a href="../about/">about&nbsp;us</a> |
-<a href="http://www.active.org.au/">www.active.org.au
-</a>
-</font>
-</table>
-
-<p>
-
-<font face="Helvetica, Arial">
-technology by <a href="http://www.cat.org.au">cat@lyst</a> /
-<a
-href="http://www.active.org.au/sydney/about/#howorg">active
-version 1.31</a>
-</font>
-</center>
------>
-</font></body></html>
-<!-- exiting cast-class -->
-
-
-
diff --git a/templates-dist/en/open/posting_done.template b/templates-dist/en/open/posting_done.template
deleted file mode 100755 (executable)
index d58649a..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html>
-<head>
-       <title>indymedia.de | open posting</title>
-</head>
-
-<body bgcolor="White" text="Black" link="#006600" vlink="#009900" alink="Red">
-<table><tr>
-<td valign=top align=left>
-<font face="Helvetica, Arial" size=-1>
-
-<table width="100%" border="0" cellspacing="0" cellpadding="4" bgcolor="#663399">
-                       <tr>
-       <td align="center"><font color="White">Hurra, Du hast Deinen Artikel abgeschickt!</font></td>
-                           
-                       </tr>
-               </table>
-<table border=1 cellspacing=0 width="100%">
-<tr>
-                       <td bgcolor="003300"><font color="White">
-
-<br>
-Dein Artikel landet jetzt direkt in einem intelligenten Filter. Wenn Dein Artikel keine rassistischen, sexistischen oder faschistischen Inhalte hatte, und auch nicht ganz ohne Inhalt, also leer war, dann wird er in K&uuml;rze auf http://www.germany.indymedia.org/newswire/ auftauchen. <br><br> 
-<center><EM>Gedulde Dich einen Moment! Es lohnt sich!</EM></center><br><br>
-
-</font>
-</td>
-</tr>
-<tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <a href="javascript:history.go(-2)"><font color="White"><b>&gt;&gt; Zur&uuml;ck</b></font></a>
-               </td>
-       </tr> 
-</table>
-</table>
-</body>
-</html>
\ No newline at end of file
diff --git a/templates-dist/en/open/posting_dupe.template b/templates-dist/en/open/posting_dupe.template
deleted file mode 100755 (executable)
index 07e0b18..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html>
-<head>
-       <title>indymedia.de | open posting - posting dupe</title>
-</head>
-
-<body bgcolor="White" text="Black" link="white" vlink="#009900" alink="Red">
-
-<table width="100%" border="0" cellspacing="0" cellpadding="10">
-       <tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <font color="White"><b>
-                               Keep calm. Things will happen soon.
-                       </b></font
-               </td>
-       </tr> 
-       <tr>
-               <td bgcolor="003300">
-                       <font color="White">
-                               <br>
-                                       You probably clicked on the reload button or submitted
-                                       your posting a second time. The fact that you can read
-                                       this text means that your posting has been recieved and
-                                       will soon be included in the article page.
-                               <br>
-                                       The technical background is that de.indy is connected to
-                                       a proxy server that is not updated every minute. 
-                               <br>
-                               <center><em>Don't panic</em></center><br>
-                               <br>
-                       </font>
-               </td>
-       </tr>
-       <tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <a href="javascript:history.go(-2)"><font color="White"><b>&gt;&gt; Back</b></font></a>
-               </td>
-       </tr> 
-</table>
-
-</body>
-</html>
diff --git a/templates-dist/nl/open/comment.template b/templates-dist/nl/open/comment.template
deleted file mode 100755 (executable)
index 97deb6e..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-<html>\r
-<head><title>indymedia.nl | commentaar leveren</title></head>\r
-<body bgcolor="white" text="black" link="#006600" vlink="#009900" alink="red">\r
-                       \r
-<form action="${openAction}" method=post>\r
-<input type="hidden" name="do" value="inscomment">\r
-                       \r
-<table width="100%" border="0" cellspacing="0" cellpadding="4" bgcolor="silver">\r
-       <tr>\r
-               <td bgcolor="#663399" colspan="3">\r
-                       <font color="White"><b>Commentaar leveren op een bericht</b></font>\r
-               </td>\r
-       </tr>   \r
-       <tr>\r
-               <td bgcolor="#003300" colspan="3">\r
-                       <p>\r
-                               <font color="white">\r
-                               Een paar hints bij het leveren van commentaar op berichten:\r
-                               Een goede discussie is leuker dan een scheldpartij. Lees het \r
-                               oorspronkelijke bericht eerst nog eens: misschien heb je iets\r
-                               over het hoofd gezien. Probeer je commentaar helder te houden.\r
-                               Controleer je commentaar even op fouten voordat je op de\r
-                               verstuurknop drukt.     \r
-                               </font>\r
-                       </p>\r
-\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td bgcolor="#663399" colspan="3">\r
-                       <font face="Helvetica, Arial" color="white" size=+2><b>Commentaarformulier</b></font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td>\r
-                       <b>titel van het commentaar</b>\r
-               </td>\r
-               <td colspan="2">\r
-                       <input type="text" name="title" size="45" maxlength="45"> <font size="-1" color="#663399">(moet ingevuld worden)</font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td>\r
-                       <b>je naam:</b>\r
-               </td>\r
-               <td colspan="2">\r
-                       <input type="text" name="creator" size="20" maxlength="45"> <font size="-1" color="#663399">(moet ingevuld worden)</font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td>\r
-                        je e-mailadres\r
-               </td>\r
-               <td colspan="2">\r
-                       <input type="text" name="email" size="30" maxlength="80"> <font size="-1">(<i>optioneel</i>)</font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td>\r
-                       je web-adres:\r
-               </td>\r
-               <td colspan="2">\r
-                       <input type="text" name="main_url" size="40" maxlength="160" value="http://"> <font size="-1">(<i>optioneel</i>)</font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td>\r
-                       je telefoonnummer:\r
-               </td>\r
-               <td colspan="2">\r
-                       <input type="text" name="phone" size="30" maxlength="80"> <font size="-1">(<i>optioneel</i>)</font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td>\r
-                       je adres:\r
-               </td>\r
-               <td colspan="2">\r
-                       <input type="text" name="address" size="40" maxlength="160"><font size="-1"> <i>(optioneel)</i></font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td>\r
-                       de taal van je keuze\r
-               </td>\r
-               <td colspan="2">\r
-                       <select name="to_language">\r
-                               <option value="0">de</option>\r
-                               <option value="1">en</option>\r
-                       </select> \r
-                       <font size="-1"><i>(optional)</i></font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td valign="top">\r
-                       <b>je commentaar</b>\r
-               </td>\r
-               <td bgcolor="#003300" colspan="2">\r
-                       &nbsp;<textarea name="description" rows="20" cols="60" wrap=virtual></textarea>\r
-                       <br><br>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td>&nbsp;\r
-               </td>\r
-               <td bgcolor="#663399" valign="top" align="center">\r
-                       <br>\r
-                       &nbsp;<input type="submit" value="commentaar versturen"><br>\r
-\r
-               </td>\r
-               <td bgcolor="#003300" valign="top" align="center">\r
-                       <br>\r
-                       &nbsp;<input type="reset" value="formulier leegmaken"><br>\r
-                       <input type="hidden" name="to_media" value="${aid}">\r
-                       <br>\r
-               </td>\r
-       </tr>\r
-</table>\r
-       \r
-</form>\r
-\r
-</body>\r
-</html>\r
diff --git a/templates-dist/nl/open/comment_done.template b/templates-dist/nl/open/comment_done.template
deleted file mode 100755 (executable)
index 2bdfafd..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">\r
-\r
-<html>\r
-<head>\r
-       <title>indymedia.de | open posting</title>\r
-</head>\r
-\r
-<body bgcolor="White" text="Black" link="white" vlink="#009900" alink="Red">\r
-\r
-<table width="100%" border="0" cellspacing="0" cellpadding="10">\r
-       <tr>\r
-               <td valign="top" align="center" bgcolor="#663399">\r
-                       <font color="White"><b>Je commentaar is onderweg naar Indymedia.nl!</b></font\r
-               </td>\r
-       </tr> \r
-       <tr>\r
-               <td bgcolor="003300">\r
-                       <font color="White">\r
-                               <br>\r
-                               Het beland nu eerst in een intelligent filter - Tenzij je commentaar seksistische, fascistische of racistisch inhoud bevat, of helemaal geen inhoud, dus leeg is, dan verschijnt het zo op http://www.indymedia.nl.<br>\r
-                               <br> \r
-                               <center><em>Momentje - Je zult verbaasd staan!</em></center><br>\r
-                               <br>\r
-                       </font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td valign="top" align="center" bgcolor="#663399">\r
-                       <a href="javascript:history.go(-2)"><font color="White"><b>&gt;&gt; Terug naar het bericht</b></font></a>\r
-               </td>\r
-       </tr> \r
-</table>\r
-\r
-</body>\r
-</html>\r
diff --git a/templates-dist/nl/open/comment_dupe.template b/templates-dist/nl/open/comment_dupe.template
deleted file mode 100755 (executable)
index c4fa662..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">\r
-\r
-<html>\r
-<head>\r
-       <title>indymedia.nl | open posting - dubbel commentaar</title>\r
-</head>\r
-\r
-<body bgcolor="White" text="Black" link="white" vlink="#009900" alink="Red">\r
-\r
-<table width="100%" border="0" cellspacing="0" cellpadding="10">\r
-       <tr>\r
-               <td valign="top" align="center" bgcolor="#663399">\r
-                       <font color="White"><b>\r
-                               Blijf kalm. Er gebeurt zo iets.\r
-                       </b></font\r
-               </td>\r
-       </tr> \r
-       <tr>\r
-               <td bgcolor="003300">\r
-                       <font color="White">\r
-                               <br>\r
-                                       Je hebt waarschijnlijk op de reload knop gedrukt of \r
-                                       geprobeerd je commentaar voor de tweede keer te versturen.\r
-                                       Dat je deze tekst te lezen krijgt betekent dat je\r
-                                       commentaar ontvangen is en zodadelijk verschijnt onder het\r
-                                       bericht waarop je hebt gereageerd.\r
-                               <br> \r
-                               <center><em>Don't panic</em></center><br>\r
-                               <br>\r
-                       </font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td valign="top" align="center" bgcolor="#663399">\r
-                       <a href="javascript:history.go(-2)"><font color="White"><b>&gt;&gt; Terug naar het bewuste bericht</b></font></a>\r
-               </td>\r
-       </tr> \r
-</table>\r
-\r
-</body>\r
-</html>\r
diff --git a/templates-dist/nl/open/posting.template b/templates-dist/nl/open/posting.template
deleted file mode 100755 (executable)
index fde4678..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//DE">\r
-<html>\r
-<head>\r
-       <title>indymedia.nl | open posting</title>\r
-       <meta name="description" content="Indymedia Nederland | Onafhankelijk Mediacentrum">\r
-       <meta name="author" content="Indymedia.nl">\r
-       <meta name="keywords" content="Vrije media, tegeninformatie">\r
-       <meta name="date" content="### Date ###Time">\r
-       <meta http-equiv="Content-Type" content="text/html; charset=iso-8559-1">\r
-       <meta name="robots" content="index">\r
-       <meta name="robots" content="follow">\r
-       <link rel=stylesheet type="text/css" href="${productionHost}/style/formate.css">\r
-</head>\r
-\r
-<body bgcolor="White" text="Black" link="white" vlink="white" alink="Red">\r
-\r
-\r
-<table width="99%" border="0" cellspacing="0" cellpadding="8" bgcolor="silver">\r
-       <tr>\r
-               <td align="center" bgcolor="#663399" colspan="3">\r
-                       <font face="Helvetica, Arial"><a href="#form">Meteen naar het formulier.</a></font>\r
-               <br>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td align="center" colspan="3">\r
-                       <br>\r
-                       <font size="+2" face="Helvetica, Arial">Publiceer je bericht!</font><br><br>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td colspan="3" bgcolor="white">\r
-                       <h3>Een korte introductie bij het plaatsen van berichten op Indymedia.nl</h3>\r
-\r
-                       <p>     De Nederlandse afdeling van het Indymedia Centrum is \r
-                               een collectief.Het is een medianetwerk dat radicale, \r
-                               gepassioneerde en zeker ook subjectieve, persoonlijke \r
-                               standpunten van allerlei verschillende mensen 'van de \r
-                               straat' publiceert. Daarbij horen ook berichten over \r
-                               campagnes, politieke gebeurtenissen en de dagelijkse \r
-                               leefwereld. We doen dit uit respect en liefde voor mensen \r
-                               die zich inzetten voor een betere, mooiere wereld, \r
-                               waarvan het werk niet of verdraaid weergegeven wordt in \r
-                               de reguliere media.</p>\r
-\r
-                       <p>     Indymedia is een democratische nieuwsbron. We willen verhalen,\r
-                               berichten, meningen en informatie uit de hele wereld openbaar maken.\r
-                               Alle berichten worden direct en ongecensureerd gepubliceerd, voor\r
-                               zover ze niet in de hieronder uitgesloten categorien\r
-                               vallen. De berichten verschijnen echter niet meteen midden op de voorpagina,\r
-                               maar wel op de 'newswire' (de rechterkolom van de pagina).\r
-                               Door wisselende teams van moderatoren worden berichten dan eventueel\r
-                               op midden de voorpagina gezet.\r
-                               Om helderheid te bevorderen is het mogelijk de niet gepubliceerde\r
-                               bijdragen per e-mail op te vragen.</p>\r
-\r
-                       <p>     Gebruik dit formulier alsjeblieft alleen voor nieuwe bijdragen en\r
-                               ideeën. Reacties horen onder het bijbehorende bericht: gebruik\r
-                               daarvoor de "reageer"-knop onder het desbetreffende bericht.</p>\r
-\r
-                       <p>     Volgens ons zou een bijdrage door niet-commerciele initiatieven weer\r
-                               hergebruikt moeten kunnen worden. Mocht je dit niet willen, laat dan\r
-                               weten dat dit niet mag, of anders onder welke condities wel of niet\r
-                               (bijvoorbeeld: "gebruik door derden  niet toegestaan" in de\r
-                               samenvatting)</p>\r
-\r
-                       <p>     Je kunt dit formulier gebruiken om je tekst, foto's, illustratie,\r
-                               audio, video, etcetera openbaar te maken.Beperk je tot bijdragen over\r
-                               sociaal en/of politiek activisme. Wij (de mensen achter deze website)\r
-                               mogen ten aller tijde ingezonden bijdragen veranderen. Meer daarover\r
-                               vind je hieronder. </p>\r
-\r
-                       <p>     Nadat een bijdrage verschenen is, kan deze door het collectief naar voren\r
-                               geschoven, van extra informatie voorzien of zelfs verwijderd worden.</p>\r
-                       <br>\r
-\r
-                       <p><b>Voor alle duidelijkheid:</b><p>\r
-\r
-                       <ul>\r
-                               <li>Stuur alleen nieuwe nieuwsberichten, gebruik voor het reageren op bestaande bijdragen de 'reageer'-knop onderaan desbetreffend bericht.\r
-                               <li>Stuur alleen een kopie van je bijdrage. Druk alsjeblieft maar 1 (een!) keer op de send-knop.\r
-                               <li>Stuur alleen zelfgeschreven/-gemaakte bijdragen. (Geen kopieen van krantenberichten, persberichten, of dergelijk!). \r
-                               <li>Wij verwijderen gejatte software en mp3-tjes en dergelijke zonder discussie\r
-                               <li>Puur fascistische bijdragen, niet functionele porno, spam en ander niet bediscussieerbare bijdrage worden verwijderd.\r
-                               <li>Voor straf verplaatst naar de Indymedia data-kerker worden: racistische bijdragen waarvan de auteur niet in discussie wil gaan, ellenlange teksten vanwege de tekst zelf (zoals nieuwsbrieven van politieke partijen) en bloot zonder doel.\r
-                       </ul>\r
-               </td>\r
-       </tr>\r
-<form action="${openAction}?do=addposting" method="post">\r
-       <tr>\r
-               <td>Het aantal media files dat meestuurt</td>\r
-               <td colspan="2"><input type="text" name="medianum" value="${medianum}">&nbsp;<input type="submit">\r
-       </tr>\r
-</form>\r
-\r
-<a name="form"></a>\r
-<form enctype="multipart/form-data" action="${openAction}?do=insposting" method="post">\r
-\r
-       <tr>\r
-               <td bgcolor="#663399" colspan="3">\r
-                       <center><font size="+2" face="Helvetica, Arial" color="white"><b>publicatieformulier</b></font></center>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td valign="top">\r
-                        <b>titel</b> van je bijdrage:\r
-               </td>\r
-               <td colspan="2" bgcolor="#003300">\r
-                       <input type="text" name="title" size="45" maxlength="45" value=""> <font size="-1" color="white"><br>(moet worden ingevuld)</font>\r
-               </td>\r
-       </tr>\r
-\r
-\r
-    <tr>\r
-        <td valign="top">\r
-            <b>Het thema</b> van jouw bijdrage\r
-        </td>\r
-       <td colspan="2">\r
-       <select name="to_topic" size="3" multiple>\r
-       <list themenPopupData as t>\r
-       <option value="${t.key}" <list to_topic as to><if (t.key == to)>selected</if></list>>${t.value}</option>            \r
-       </list>\r
-       </select>\r
-       <font size="-1">(<i>optioneel</i>)</font>\r
-       </td>\r
-    </tr>\r
-\r
-       \r
-       <tr>\r
-               <td valign="top">\r
-                       <b>auteur</b> van deze bijdrage:\r
-               </td>\r
-               <td colspan="2" bgcolor="#003300">\r
-                       <input type="text" name="creator" size="45" maxlength="45"> <font size="-1" color="white"><br>(moet worden ingevuld)</font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td valign="top">\r
-                       Een korte <b>omschrijving</b> van je bijdrage:</b>\r
-               </td>\r
-               <td colspan="2" bgcolor="#003300">\r
-                       <textarea name="description" rows="6" cols="45" wrap=virtual></textarea>\r
-                       <font size="-1" color="white"><br>(niet meer dan <b>5 regels</b>)</font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td colspan="3">\r
-               <font face="Helvetica, Arial" size=-1 color="#663399">\r
-               Contact informatie is niet verplicht, maar maakt het mogelijk voor andere mensen je te bereiken, mocht je dat willen, en dan is dat handig, nietwaar?\r
-       </font>\r
-               </td>\r
-       </tr>\r
-\r
-       <tr>\r
-               <td>\r
-                       je e-mailadres:\r
-               </td>\r
-               <td colspan="2">\r
-                       <input type="text" name="creator_email" size="45" maxlength="80" value=""> <font size="-1">(<i>optioneel</i>)</font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td>\r
-                       je webadres:\r
-               </td>\r
-               <td colspan="2">\r
-               <input type="text" name="creator_main_url" size="45" maxlength="160" value="http://">\r
-                <font size="-1">(<i>optioneel</i>)</font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td>\r
-                       je adres:\r
-               </td>\r
-               <td colspan="2">\r
-                       <input type="text" name="creator_address" size="45" maxlength="160" value=""> <font size="-1"> <i>(optioneel)</i></font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td>\r
-                       je telefoonnummer:\r
-               </td>\r
-               <td colspan="2">\r
-                       <input type="text" name="creator_phone" size="20" maxlength="20" value=""> <font size="-1">(<i>optioneel</i>)</font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td>\r
-                       de taal van je bijdrage:\r
-               </td>\r
-               <td colspan="2">\r
-                       <select name="to_language">\r
-                               <list languagePopUpData as l>\r
-                               <option value="${l.key}">${l.value}</option>    \r
-                               </list>\r
-                       </select>\r
-                       <font size="-1"><i>(optioneel)</i></font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td valign="top">\r
-                       je <b>bijdrage</b>:<br>\r
-                       vul de text van je bijdrage hier in\r
-               </td>\r
-               <td bgcolor="#003300" colspan="2">\r
-                       &nbsp; <textarea name="content_data" rows="20" cols="45" wrap="soft"></textarea>\r
-                       <br><br>\r
-               </td>\r
-       </tr>\r
-       \r
-       <tr>\r
-               <td>\r
-                       media:\r
-               </td>\r
-               <td colspan="2">\r
-                       upload media-files (tot nog toe alleen jpg|gif|mp3|avi|qt|mpeg|pdf|ra(realaudio)|rm(realvideo))<br>\r
-               </td>\r
-       </tr>\r
-<list data.mediafields as m>\r
-       <tr>    \r
-               <td>Media Item ${m}</td>\r
-               <td colspan="2">        \r
-                       <INPUT TYPE="file" NAME="media${m}"> <font size="-1">(<i>optioneel</i>)</font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td>\r
-                       media sub-title ${m}:\r
-               </td>\r
-               <td colspan="2">\r
-                       <input type="text" name="media_title${m}" size="40" maxlength="80" value=""> <font size="-1">(<i>optioneel</i>)</font>\r
-               </td>\r
-       </tr>\r
-</list>        \r
-       \r
-       <tr>\r
-               <td><b          </td>\r
-               <td bgcolor="#663399" valign="top" align="center"><br>\r
-       &nbsp;<input type="submit" value="Submit (even geduld!!)"><br>\r
-\r
-               </td>\r
-               <td bgcolor="#003300" valign="top" ge-aln="center">\r
-                       <br>\r
-                       &nbsp;<input type="reset" value="Form Reset"><br>\r
-               </td>\r
-       </tr>\r
-</table>\r
-\r
-\r
-\r
-</body>\r
-</html>\r
diff --git a/templates-dist/nl/open/posting_done.template b/templates-dist/nl/open/posting_done.template
deleted file mode 100755 (executable)
index 3fc66a0..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html>
-<head>
-       <title>indymedia.nl | open posting</title>
-</head>
-
-<body bgcolor="White" text="Black" link="#006600" vlink="#009900" alink="Red">
-<table><tr>
-<td valign=top align=left>
-<font face="sans-serif" size=-1>
-
-<table width="100%" border="0" cellspacing="0" cellpadding="15" bgcolor="#663399">
-                       <tr>
-       <td align="center"><font color="White">Hoera, je bericht is verstuurd!</font></td>
-                           
-                       </tr>
-               </table>
-<table border=1 cellspacing=0 width="100%">
-<tr>
-                       <td bgcolor="003300" align="center"><font color="White">
-
-<br>
-Je bericht belandt nu eerst in een slim filter. Tenzij je bericht seksistische, fascistische of racistisch inhoud bevat, of helemaal geen inhoud heeft, dan verschijnt het zo op <a href="http://www.indymedia.nl">http://www.indymedia.nl</a>. <br><br> 
-<center><EM>Heb een momentje geduld! Het is de moeite waard!</EM></center><br><br>
-
-</font>
-</td>
-</tr>
-<tr>
-               <td valign="top" align="center" bgcolor="#663399">
-                       <a href="javascript:history.go(-2)"><font color="White"><b>&gt;&gt; terug</b></font></a>
-               </td>
-       </tr> 
-</table>
-</table>
-</body>
-</html>
\ No newline at end of file
diff --git a/templates-dist/nl/open/posting_dupe.template b/templates-dist/nl/open/posting_dupe.template
deleted file mode 100755 (executable)
index 0528652..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">\r
-\r
-<html>\r
-<head>\r
-       <title>indymedia.nl | open posting - posting dupe</title>\r
-</head>\r
-\r
-<body bgcolor="White" text="Black" link="white" vlink="#009900" alink="Red">\r
-\r
-<table width="100%" border="0" cellspacing="0" cellpadding="10">\r
-       <tr>\r
-               <td valign="top" align="center" bgcolor="#663399">\r
-                       <font color="White"><b>\r
-                               Blijf rustig. Er gebeurt al iets.\r
-                       <br>\r
-                               Keep calm. Things will happen soon.\r
-                       </b></font\r
-               </td>\r
-       </tr> \r
-       <tr>\r
-               <td bgcolor="003300">\r
-                       <font color="White">\r
-                               <br>\r
-                                       Je hebt waarschijnlijk op de reload-knop gedrukt of\r
-                                       je hebt je bericht voor de tweede keer verstuurd. Dat\r
-                                       je deze tekst te lezen krijgt betekent dat je bericht \r
-                                       is ontvangen en zo verschijnt op de berichtenpagina.\r
-                               <br>\r
-                                       You probably clicked on the reload button or submitted\r
-                                       your posting a second time. The fact that you can read\r
-                                       this text means that your posting has been recieved and\r
-                                       will soon be included in the article page.\r
-                               <br>\r
-                                       De proxy server doet er soms een paar minuten over om de \r
-                                       inhoud te verversen.\r
-                               <br> \r
-                                       The technical background is that indymedia.nl is connected to\r
-                                       a proxy server that is not updated every minute. \r
-                               <br>\r
-                               <center><em>Don't panic</em></center><br>\r
-                               <br>\r
-                       </font>\r
-               </td>\r
-       </tr>\r
-       <tr>\r
-               <td valign="top" align="center" bgcolor="#663399">\r
-                       <a href="javascript:history.go(-2)"><font color="White"><b>&gt;&gt; Back</b></font></a>\r
-               </td>\r
-       </tr> \r
-</table>\r
-\r
-</body>\r
-</html>\r
diff --git a/templates-dist/open/comment_en.template b/templates-dist/open/comment_en.template
deleted file mode 100755 (executable)
index f5713b6..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-<html>
-<head><title>indymedia.de | comment.commit</title></head>
-<body bgcolor="White">
-<table><tr>
-<td valign=top align=left>
-<font face="Helvetica, Arial" size=-1 color="white">
-<i><b>adding a comment</b></i><br>
- <!--endmenu--> 
-
-<h3>Guidelines for commenting on news articles</h3>
-Thanks for contributing to the dynamic alternative news on active!
-<br><p>
-Add any responses to news articles that you feel are appropriate to 
-www.indy's goals eg: social activitism, local communities, ecology and development. 
-<br><p>
-The response article can be in any type of format you want, from traditional academic discourse, to subjective personal rants.
-<br><p>
-Please keep it on topic and concise.
-<br><p>
-<br><br> * = required field
-<p>
-
-<form action="https://work.indymedia.de/rk/servlet/OpenIndy" method=post>
-<input type="hidden" name="do" value="inscomment">
-<blockquote>
-       <table border=1 cellspacing=0 width="100%">
-       <tr bgcolor="">
-       <td><font face="Helvetica, Arial">
-       <b>Titel des Kommentars (*)</b><br>
-       <input type="text" name="title" size="45" maxlength="45">
-       <p>
-       <b>Dein Name (*)</b> <br>
-       <input type="text" name="creator" size="20" maxlength="45"><br>
-       <p>
-       <table border=0>
-       <tr>
-       <td><font face="Helvetica, Arial">
-       email (<i>optional</i>)
-       </font></td>
-       <td><font face="Helvetica, Arial">
-       web address (begin with http://) (<i>optional</i>)
-       </font></td></tr>
-       <tr>
-       <td>
-       <input type="text" name="email" size="30" maxlength="80">
-       </td><td>
-       <input type="text" name="main_url" size="40" maxlength="160">
-       </td></tr></table>
-
-       <p><table border=0>
-       <tr><td><font face="Helvetica, Arial">
-       phone (<i>optional</i>)
-       </font></td>
-       <td><font face="Helvetica, Arial">
-       address (<i>optional</i>)
-       </font></td></tr>
-       <tr><td>
-       <input type="text" name="phone" size="30" maxlength="80">
-       </td><td>
-       <input type="text" name="address" size="40" maxlength="160">
-       </td></tr>
-       <tr><td>
-
-           <b>language</b><br>
-the language of the submission<BR>
-<select name="to_language">
-<option value="0">de</option>
-<option value="1">en</option>
-</select><BR>
-</td></tr>
-       </table>
-       <p>
-       <b>your comment*</b><br>
-       <textarea name="description" rows="20" cols="60" wrap=virtual></textarea>
-       </table>
-       <center>
-       <input type="submit" value="add my comment">
-       <input type="reset" value="clear form">
-       <input type="hidden" name="to_media" value="${aid}">
-       </center>
-</form>
-</blockquote>
-</font>
-</td>
-</tr></table>
-</body>
-</html>
\ No newline at end of file
index 6bd4b96..eb33b80 100755 (executable)
@@ -71,7 +71,7 @@
        <font size="-2">${lang("open.posting.topic.info")}</font>
         </td>
        <td colspan="2">
-       <select name="data.to_topic" size="3" multiple>
+       <select name="to_topic" size="3" multiple>
        <list extra.themenPopupData as t>
        <option value="${t.key}" <list to_topic as to><if (t.key == to)>selected</if></list>>${t.value}</option>
        </list>
diff --git a/templates-dist/open/posting_en.template b/templates-dist/open/posting_en.template
deleted file mode 100755 (executable)
index 1fd1dff..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-    <html>
-    <head>
-    <title>indymedia.de | open posting</title>
-    </head>
-
-    <body bgcolor="#000000"
-    fgcolor="white"
-    link="#ff9900"
-    alink="#999900"
-    vlink="#999900"
-    text="white">
-
-    <font face="Helvetica, Arial" color="white">
-
-<TABLE cellPadding=5 cellSpacing=0 border=0>
-
-<tr>
-<td valign=top align=left>
-<font face="Helvetica, Arial" size=-1 color="white">
-
-<i><b>publish your article</b></i><br>
-<p>
-
-<p>
-<table width="100%" bgcolor="#555555"><tr><td>
-<font size=+1>
-<b>Posting a piece on indymedia's newswire</b></font>
-</td></tr></table>
-<p>
-
-<p>
-<ul>
-<li><a href="#form">jump straight to the form!</a>
-</ul>
-
-
-<p>
-
-<blockquote>
-<font size=+2><b>T</b></font>he Independent Media Center is a collectively 
-run media outlet for the creation of radical, accurate, and passionate 
-tellings of the truth. We work out of a love and inspiration for people 
-to who continue to work for a better world, despite corporate media's 
-distortions and unwillingness to cover the efforts to free humanity. 
-
-<p>
-
-Indymedia is a democratic newswire. We <b>want</b> to see and hear the real
-stories, news, and opinions from around the world. While we struggle to 
-maintain the news wire as a completely open fourm we <i>do</i> monitor it
-and remove posts. <br>
-You can see the decisons we have made by viewing the
-<a href="http://www.indymedia.org/search-process.php3?hidden=true">hidden articles page</a>. In the 
-overwhelming number of cases, stories have been removed for the following
-reasons: <a href="http://www.indymedia.org/display.php3?article_id=4080">being comments, not news</a>, duplicate posts, 
-<a href="http://www.indymedia.org/display.php3?article_id=4004">obviously false or 
-libelous posts</a>, or inappropriate content.
-<br>
-We are working on the technology 
-to make this process more transparent, so that you can see when such decisions 
-have been made, and why.
-In future, we want our audience to be part of this process too. For the meantime,
-you can check out stories that we have choosen to remove by looking at the 
-<a href="http://www.indymedia.org/search-process.php3?hidden=true">hidden articles</a> page. 
-</blockquote>
-
-<br>
-
-Please use this form to contribute <b>new</b> stories and ideas.  We think
-comments belong with the story being discussed. So to have your say in response
-to a story on the site, please use the <b>add your comments</b> link at the
-bottom of the stories.
-
-<p>
-
-We think stories contributed to this site should be free for non-profit re-use.
-Copy left is an idea central to indymedia. For more information, check out
-<a href="http://www.opencontent.org">www.opencontent.org</a>. If you want to change that for your story, please give your conditions in the
-summary.
-<p>
-You can use this form to publish your text article, audio segment, video
-footage, or picture.  Please focus on activism issues and events. We (the
-people organising this site) may rearrange the display of submitted stories.
-
-<p>
-
-After stories have been published, they can be edited, linked or even deleted
-by the collective running this site, using the <a
-href="display.php3?led=y">story administration</a> page (password required). 
-<br>
-
-
-<p>
-
-
-<b>Remember:</b>
-
-<ul>
-
-<li>please post <b>news items only</b>, leave your comments for discussion
-areas
-
-<li>please try to post <b>just one copy</b> of your story - please only press 
-the publish button <b>once</b>. 
-
-</ul>
-
-
-<p>
-
-<a name="form"></a>
-
-
-
-<form enctype="multipart/form-data" action="new_data-process.php3" method=post>
-  <input type="hidden" name="MAX_FILE_SIZE" value="100000000"><p>
-  <table border=1 cellspacing=0 width="100%">
-       <tr bgcolor="">
-         <td bgcolor="#333333">
-               <table width="100%" bgcolor="#555555">
-               <tr>
-                       <td>
-                               <font face="Helvetica, Arial">
-                               <center><font size=+2><b>Publishing Form</b></font></center>
-                       </td>
-               </tr>
-               </table>
-               <br>
-               <font face="arial" size=+2><b> Step 1:</b><br><br></font>
-               <font face="arial" size=+1><b>Give your piece a title</b><br>
-           <input type="text" name="title" size="80" maxlength="80" value="">    
-       <p>
-               <font face="arial">
-       <b>Author or producer of the piece you're posting</b><br>
-           <input type="text" name="creator" size="80" maxlength="80" value="">
-           <br>
-       <p>
-        <b>the summary</b></font><font size=-1> (no more than 6 lines - include the 
-               duration of the piece if you are publishing audio or video)<br></font>
-           <textarea name="summary" rows="3" cols="80" wrap=virtual
-    
-></textarea>
-<br><br>
-
-
-
-    <table border=0>    
-    <tr><td><font face="Helvetica, Arial" size=-1>
-    including contact details below is optional but will mean our
-    audience (including journalists) can contact you about your story,
-    including for possible re-use in other places
-    </font>
-    </td></tr>
-    </table>
-
-    <table border=0>
-    <tr><td><font face="Helvetica, Arial">
-    <b>email</b> <i>optional</i>
-    </font></td>
-    <td><font face="Helvetica, Arial">
-    <b>phone</b> <i>optional</i>
-    </font></td>
-    <tr><td><font face="Helvetica, Arial">
-    <input type="text" name="contact" size="30" maxlength="80"
-    
-value="">
-    
-    </font></td>
-    <td><font face="Helvetica, Arial">
-    <input type="text" name="phone" size="30" maxlength="80"
-    
-value="">
-
-    </td></tr>
-    </table>
-
-    <p>
-
-    <table border=0>
-    <tr><td><font face="Helvetica, Arial">
-    <b>address</b> <i>optional</i>
-    </font></td></tr>
-    <tr><td>
-    <input type="text" name="address" size="70" maxlength="160"
-    
-value="">
-    
-    </td></tr>
-    </table>
-    <p>
-
-    <b>language</b><br>
-the language of your submission<BR>
-<select name="storylang">
-<option>czech</option>
-<option>dutch</option>
-<option selected>english</option>
-<option>french</option>
-<option>german</option>
-<option>italian</option>
-<option>japanese</option>
-<option>polish</option>
-<option>russian</option>
-<option>spanish</option>
-</select><BR>
-
-
-
-    <p>
-    <b>web address</b> <i>optional</i> </font><font size=-1>This provides a link to your website.<br>
-    </font><input type="text" name="link" size="70" maxlength="160"
-value="">
-    
-    <br><br>
-
-    </font>
-  </td></tr></table>
-
-  <p>
-
-<!-- STARTS SECOND STEP OF ENTRY FORM -->
-  <table border=1 cellspacing=0 width="100%" >
-    
-<tr bgcolor="#440000">
-       
-    
-    
-        
-    <td>
-    
-    
-    <font size=+2> <b>Step 2:</b><br><br>
-    <font face="Helvetica, Arial">
-    <font size=+1>Text that you would like to appear with your story.
-    If you are posting a text only piece, you can type or paste your story here.</font><br>
-<font size=-1>
-    the article (if you enter HTML code, select "html format" from the <b>type of upload</b> drop down box below)<br></font>
-    <textarea name="article" rows="20" cols="80" wrap="soft"
-></textarea>
-
-    </font>
-  </td></tr></table>
-
-  <p>
-
-
-
-<!-- STARTS THIRD STEP OF ENTRY FORM -->
-
-  <table border=1 cellspacing=0 width="100%">
-
-<tr bgcolor="#330000">
-       
-  
-    <td>
-    
-    
-    <font size=+2><b>Step 3:</b>
-    
-    <font face="Helvetica, Arial">
-   <font size=+1><b>multimedia stories</b></font><br>
-<font size=-1>
-Send in this file 
-      (limit 100 megs): 
-      <INPUT NAME="linked_file" TYPE="file"><p>
-    
-</font>
-    <font size=+1>
-  <B>Audio/Video/Images:</B></font><font size=-1> You need to
-    select the proper type for the content you are uploading. If you
-   are only uploading text, leave the setting on plain text. You
-   can upload html tags in a story if you wish.<br><br>
-    
-    <B>Type of upload:</B>     
-    <select name="mime_type">
-    
-<option selected value="text/plain">plain text
-    <option value="text/html">html format
-    <option value="text/x-url">just a web address
-    <option value="image/gif">gif image
-    <option value="image/jpeg">jpeg/jpg image
-    <option value="audio/mpeg">mp3 audio
-    <option value="audio/x-pn-realaudio">realaudio
-    <option value="video/x-pn-realvideo">realvideo
-    </select>
-    <p>
-    
-  
-    </font>
-  </td></tr></table>
-
-
-    
-
-  <P> <B>Press the publish button only once.</B> Uploading files can take a
-  long time and the confirmation page won't be shown until after the file has
-  finished uploading.
-
-  <center>
-  <p>
-  <input type="submit" name="action" value="Publish!">
- <input type=hidden name="publishtype" value="webcast">  <!--<input type=image src="uploads/pub-button.jpg" name="sub">-->
-  <p>
-  <input type="reset" value="clear form">
-  </center>
-       
-</form>
-
-<!-- $Id: posting_en.template,v 1.1 2001/08/25 12:34:07 idfx Exp $ -->
-
-</font>
-</td></tr></table>
-
-<!--
-<p>
-<center>
-<table width="100%" border=0 cellspacing=0 cellpadding=0>
-<tr><td  bgcolor="#66ccff" align=center>
-<font face="Helvetica, Arial">
-<a href="../calendar/?display=list&days=14">events</a> | 
-<a href="../groups/">groups</a> | 
-<a href="../news/">news</a> | 
-<a href="../howto/">how&nbsp;to</a> | 
-<a href="../about/">about&nbsp;us</a> |
-<a href="http://www.active.org.au/">www.active.org.au
-</a>
-</font>
-</table>
-
-<p>
-
-<font face="Helvetica, Arial">
-technology by <a href="http://www.cat.org.au">cat@lyst</a> /
-<a
-href="http://www.active.org.au/sydney/about/#howorg">active
-version 1.31</a>
-</font>
-</center>
------>
-</font></body></html>
-<!-- exiting cast-class -->
-
-
-
index 6b6fcb5..a91c42e 100755 (executable)
@@ -1,6 +1,6 @@
 <html>
 <head>
-<title>${lang("producer.content.htmltitle")}${content.title}</title>
+<title>${lang("producer.content.htmltitle")}${data.content.title}</title>
 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
 <link rel="stylesheet" href="/style/mir.css" type="text/css">
                        <if data.content.to_media_images>
 
 <body bgcolor="#CCCCCC">
 <table width="760" border="0" cellpadding="0" cellspacing="1" align="center" bgcolor="#000000">
-  <tr bgcolor="#FFFFFF"> 
-    <td valign="top" align="left" width="150" bgcolor="#666666"> 
+  <tr bgcolor="#FFFFFF">
+    <td valign="top" align="left" width="150" bgcolor="#666666">
       <table width="150" border="0" cellspacing="0" cellpadding="0">
-        <tr> 
+        <tr>
           <td width="140">
-            <a href="${data.config.productionHost}${config.producerDocRoot}/">
+            <a href="${config.productionHost}${config.producerDocRoot}/">
              <img src="/images/mirlogo.jpg" width="150" height="205" border="0">
             </a>
           </td>
         </tr>
-        <tr valign="top"> 
-          <td width="140" bgcolor="#666666"> 
+        <tr valign="top">
+          <td width="140" bgcolor="#666666">
             <table width="100%" border="0" cellspacing="2" cellpadding="0">
-              <tr> 
-                <td> 
-               <!--#include virtual="../../navigation.inc" -->
+              <tr>
+                <td>
+                  <!--#include virtual="../../navigation.inc" -->
                 </td>
               </tr>
             </table>
     </td>
     <td align="left" valign="top" colspan="2" height="100%">
       <table width="100%" border="0" cellspacing="0" cellpadding="0">
-        <tr> 
-          <td> 
+        <tr>
+          <td>
             <table width="100%" border="0" cellspacing="0" cellpadding="0">
-              <tr> 
+              <tr>
                 <td><img src="/images/mirfont.gif" width="600" height="68"></td>
               </tr>
             </table>
           </td>
         </tr>
-        <tr bgcolor="#000000"> 
+        <tr bgcolor="#000000">
           <td height="1"><img src="images/1pixel.gif" width="1" height="1"></td>
         </tr>
-        <tr> 
-          <td align="left" valign="top"> 
+        <tr>
+          <td align="left" valign="top">
             <table width="100%" border="0" cellpadding="0" cellspacing="2" height="100%">
-              <tr> 
+              <tr>
                 <td width="100%" valign="top">
                   <table width="100%" border="0" cellspacing="0" cellpadding="0">
-
        <if config.generateFO=="yes">
          <tr><td align="right">          
          <if config.generatePDF=="yes">
                         <h2>${data.content.title}</h2>
                         <h4><i>${data.content.creator}, ${data.content.webdb_create_formatted}</i></h4>
                         <p><b>${data.content.description_parsed}</b>
+
+
           <!-- media -->
-          <list data.content.to_media_audio as media>
-            <list media["url"] as audio>
-              <p>
-                <img src="/img/${media["big_icon"]}" border="0" alt="">
-                <a href="${audio["publish_server"]}${audio["publish_path"]}">
-                ${audio["title"]} - ${media["descr"]}</a>
-              </p>
+
+            <list data.content.to_media_audio as media>
+                <list media["url"] as audio>
+                  <p>
+
+                    <img src="/img/${media["big_icon"]}" border="0" alt="">
+
+                    <a href="${audio["publish_server"]}${audio["publish_path"]}">
+                      ${audio["title"]} - ${media["descr"]}
+                    </a>
+                  </p>
+                </list>
             </list>
-          </list>
           <list data.content.to_media_video as media>
             <list media["url"] as video>
               <p>
               </p>
             </list>
           </list>
-          <list data.content.to_media_images as media>
-            <list media["url"] as image>
+
+          <list data.content.to_media_images as image>
               <p>
                 <img src="${image["publish_server"]}${image["publish_path"]}"
                  border="0" width="${image["img_width"]}"
                  height="${image["img_height"]}" alt="${image["title"]}">
                  <br><i>${image["title"]}</i>
               </p>
-            </list>
           </list>
+
           <!-- media -->
+
           <p>${data.content.content_data_parsed}</p>
-          <if content.creator_main_url || content.creator_email>
+          <if data.content.creator_main_url || data.content.creator_email>
                         <table width="100%" bgcolor="#FFFFFF">
                         <tr>
                            <td>
                     <tr>
                       <td><a href="${config.openAction}?do=addcomment&aid=${data.content.id}">
                           ${lang("producer.content.comment")}</a>
-                      </td>                
+                      </td>
                     </tr>
                     <if data.content.to_comments>
                     <list data.content.to_comments as c>
                        <tr>
                          <td colspan="2"><br>${c.description}</td>
                        </tr>
-                      <if c.email || c.main_url || c.address || c.phone || c.creator>
+                   <if c.email || c.main_url || c.address || c.phone || c.creator>
                        <tr>
                          <td bgcolor="#cccccc" colspan="2">
                         <if c.creator><b>${c.creator}</b></if>
-                        <if c.email || c.main_url> 
-                          <if c.email>
+                     <if c.email || c.main_url>
+                        <if c.email>
                            <br>
                            <img src="/images/mail_small.gif" width="12" height="10" border="0" alt="">${lang("producer.content.email")}: <a href="mailto:${c.email}"> ${c.email}</a>
-                           </if>
-                          <if c.main_url>
+                        </if>
+                        <if c.main_url>
                            <br>
                            <img src="/images/link_small.gif" width="12" height="10" border="0" alt="">
                            ${lang("producer.content.homepage")}: <a href="${c.main_url}" target="extern"> ${c.main_url}</a>
-                           </if>
-                         </if>
-                        </td>
+                        </if>
+                                     </if>
+                                         </td>
                       </tr>
-                    </if>
+                  </if>
                      </table>
                      </td>
                     </tr>
diff --git a/templates-dist/producer/producers.xml b/templates-dist/producer/producers.xml
new file mode 100755 (executable)
index 0000000..7ea479d
--- /dev/null
@@ -0,0 +1,111 @@
+<producers>
+  <nodedefinition name="Language">
+    <parameters>
+      <string name="languagecondition" defaultvalue=""/>
+      <string name="bundle" defaultvalue="bundles.producer" />
+      <node name="sub"/>    
+    </parameters>
+
+    <definition>
+      <Log message="logging: "/>
+      <Enumerate key="language" table="language" selection="${languagecondition}" order="code">
+        <Log message="  language.code = ${language.code}" />
+        <Resource bundle="${bundle}" key="lang" language="${language.code}"/>
+        <Define key="pathprefix" value="${language.code}/" />
+        <sub/>
+      </Enumerate>
+    </definition>
+  </nodedefinition>
+  <producer name="content">
+    <verbs>
+      <verb name="new">
+        <Set key="verbcondition" value="' and (not is_produced)'"/>
+      </verb>
+      <verb name="all">
+        <Set key="verbcondition" value="''"/>
+      </verb>
+    </verbs>
+    <body>
+      <Enumerate key="data.content" table="content" selection="is_published='t' ${verbcondition}"
+                  limit="10" order="webdb_create desc, date desc">
+        <Generate 
+            generator="/producer/content.template" 
+            destination="${config.storageRoot}/${data.content.date.formatted.yyyy}/${data.content.date.formatted.MM}/${data.content.id}.shtml"/>
+        <MarkContent key="data.content"/>            
+      </Enumerate>
+    </body>
+  </producer>  
+
+  <producer name="navigation">
+    <verbs>
+      <verb name="new"/>
+    </verbs>
+    <body>
+      <Log message="logging"/>
+      <Language>
+        <Generate 
+            generator="/producer/navigation.template" 
+            destination="${config.storageRoot}/${pathprefix}/navigation.inc"/>
+      </Language>
+    </body>
+  </producer>
+  
+  <producer name="topics">
+    <verbs>
+      <verb name="new">
+        <Set key="pages" value="1 + 1 -2 * 3 + 4 * ( 5+6 ) - 40 + 2"/>
+      </verb>
+      <verb name="all">
+        <Set key="pages" value="-1"/>
+      </verb> 
+    </verbs>
+    <body>
+      <Enumerate key="topic" table="topic">
+        <List key="data.special" table="content" 
+          selection="is_published='1' and to_article_type = ${articletype.topicspecial} and id in (select content_id from content_x_topic where topic_id = ${topic.id})"
+          order = "webdb_create desc, date desc" limit="1"/>
+      
+        <Batch key="data.contentlist" infokey="batch" table="content" 
+               process="pages" batchsize="20" minbatchsize="10"
+               selection="is_published='1' and to_article_type in (${articletype.newswire}, ${articletype.feature}) and id in (select content_id from content_x_topic where topic_id = ${topic.id})"
+               order="webdb_create asc">
+          <batches>
+            <Set key="filename" value="topic.filename ++ batch.current.identifier"/>
+            <Generate 
+                generator="/producer/topiclist.template" 
+                destination="${config.storageRoot}/${topic.filename}/${filename}.shtml"/>
+          </batches>
+          <batchlist>
+          </batchlist>
+        </Batch>
+      </Enumerate>
+    </body>
+  </producer>
+  
+  <producer name="startpage">
+    <verbs>
+      <verb name="new"/>
+    </verbs>
+
+    <body>
+      <List key="startspecial" table="content" limit="1"
+        selection="is_published=true and to_article_type=${articletype.startspecial}"
+        order="webdb_create desc, date desc"/>
+                                        
+      <List key="data.features" table="content" limit="10 12" 
+        selection="is_published=true and to_article_type=${articletype.feature}"
+        order="webdb_create desc, date desc"/>
+      <List key="data.newswire" table="content" limit="30"
+        selection="is_published=true and to_article_type=${articletype.newswire}"
+        order="webdb_create desc, date desc"/>
+         
+      <Generate 
+          generator="/producer/startpage.template" 
+          destination="${config.storageRoot}/index.shtml"/>
+    </body>
+  </producer>  
+  
+</producers>
+
+