summaryrefslogtreecommitdiff
path: root/platform/www/lib/plugins/farmer
diff options
context:
space:
mode:
Diffstat (limited to 'platform/www/lib/plugins/farmer')
-rw-r--r--platform/www/lib/plugins/farmer/.github/auto-comment.yml9
-rw-r--r--platform/www/lib/plugins/farmer/.travis.yml15
-rw-r--r--platform/www/lib/plugins/farmer/3rdparty/PHPIco.php248
-rw-r--r--platform/www/lib/plugins/farmer/3rdparty/RingIcon.php186
-rw-r--r--platform/www/lib/plugins/farmer/DokuWikiFarmCore.php375
-rw-r--r--platform/www/lib/plugins/farmer/README27
-rw-r--r--platform/www/lib/plugins/farmer/_animal/conf/acl.auth.php21
-rw-r--r--platform/www/lib/plugins/farmer/_animal/conf/local.php6
-rw-r--r--platform/www/lib/plugins/farmer/_animal/data/_dummy0
-rw-r--r--platform/www/lib/plugins/farmer/_animal/data/attic/_dummy0
-rw-r--r--platform/www/lib/plugins/farmer/_animal/data/cache/_dummy0
-rw-r--r--platform/www/lib/plugins/farmer/_animal/data/index/_dummy0
-rw-r--r--platform/www/lib/plugins/farmer/_animal/data/locks/_dummy0
-rw-r--r--platform/www/lib/plugins/farmer/_animal/data/log/_dummy0
-rw-r--r--platform/www/lib/plugins/farmer/_animal/data/media/wiki/dokuwiki-128.pngbin0 -> 33615 bytes
-rw-r--r--platform/www/lib/plugins/farmer/_animal/data/media_attic/_dummy0
-rw-r--r--platform/www/lib/plugins/farmer/_animal/data/media_meta/_dummy0
-rw-r--r--platform/www/lib/plugins/farmer/_animal/data/meta/_dummy0
-rw-r--r--platform/www/lib/plugins/farmer/_animal/data/pages/wiki/dokuwiki.txt64
-rw-r--r--platform/www/lib/plugins/farmer/_animal/data/pages/wiki/syntax.txt486
-rw-r--r--platform/www/lib/plugins/farmer/_animal/data/tmp/_dummy0
-rw-r--r--platform/www/lib/plugins/farmer/_test/core.test.php40
-rw-r--r--platform/www/lib/plugins/farmer/_test/general.test.php36
-rw-r--r--platform/www/lib/plugins/farmer/_test/getUserLine.test.php86
-rw-r--r--platform/www/lib/plugins/farmer/_test/helper.test.php64
-rw-r--r--platform/www/lib/plugins/farmer/action/ajax.php267
-rw-r--r--platform/www/lib/plugins/farmer/action/disable.php56
-rw-r--r--platform/www/lib/plugins/farmer/action/startup.php90
-rw-r--r--platform/www/lib/plugins/farmer/admin.php115
-rw-r--r--platform/www/lib/plugins/farmer/admin.svg1
-rw-r--r--platform/www/lib/plugins/farmer/admin/config.php126
-rw-r--r--platform/www/lib/plugins/farmer/admin/delete.php95
-rw-r--r--platform/www/lib/plugins/farmer/admin/info.php116
-rw-r--r--platform/www/lib/plugins/farmer/admin/new.php338
-rw-r--r--platform/www/lib/plugins/farmer/admin/plugins.php104
-rw-r--r--platform/www/lib/plugins/farmer/admin/setup.php151
-rw-r--r--platform/www/lib/plugins/farmer/all.less13
-rw-r--r--platform/www/lib/plugins/farmer/conf/default.php9
-rw-r--r--platform/www/lib/plugins/farmer/conf/metadata.php9
-rw-r--r--platform/www/lib/plugins/farmer/css/chosen-sprite.pngbin0 -> 538 bytes
-rw-r--r--platform/www/lib/plugins/farmer/css/chosen.less450
-rw-r--r--platform/www/lib/plugins/farmer/deleted.files11
-rw-r--r--platform/www/lib/plugins/farmer/helper.php334
-rw-r--r--platform/www/lib/plugins/farmer/includes/config.php13
-rw-r--r--platform/www/lib/plugins/farmer/includes/plugins.php12
-rw-r--r--platform/www/lib/plugins/farmer/includes/template.php27
-rw-r--r--platform/www/lib/plugins/farmer/lang/de/lang.php118
-rw-r--r--platform/www/lib/plugins/farmer/lang/de/notfound_404.txt3
-rw-r--r--platform/www/lib/plugins/farmer/lang/de/notfound_list.txt3
-rw-r--r--platform/www/lib/plugins/farmer/lang/de/settings.php13
-rw-r--r--platform/www/lib/plugins/farmer/lang/de/tab_config.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/de/tab_delete.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/de/tab_info.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/de/tab_new.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/de/tab_plugins.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/de/tab_setup.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/lang.php128
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/notfound_404.txt3
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/notfound_list.txt3
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/settings.php13
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/tab_config.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/tab_config_help.txt26
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/tab_delete.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/tab_info.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/tab_new.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/tab_new_help.txt31
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/tab_plugins.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/tab_plugins_help.txt16
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/tab_setup.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/en/tab_setup_help.txt37
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/lang.php109
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/notfound_404.txt3
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/notfound_list.txt4
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/settings.php9
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/tab_config.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/tab_config_help.txt37
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/tab_delete.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/tab_info.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/tab_new.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/tab_new_help.txt43
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/tab_plugins.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/tab_plugins_help.txt22
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/tab_setup.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/fr/tab_setup_help.txt52
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/lang.php106
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/notfound_404.txt3
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/notfound_list.txt3
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/settings.php9
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/tab_config.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/tab_config_help.txt25
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/tab_delete.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/tab_info.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/tab_new.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/tab_new_help.txt38
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/tab_plugins.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/tab_plugins_help.txt17
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/tab_setup.txt1
-rw-r--r--platform/www/lib/plugins/farmer/lang/ja/tab_setup_help.txt38
-rw-r--r--platform/www/lib/plugins/farmer/lang/nl/lang.php20
-rw-r--r--platform/www/lib/plugins/farmer/lang/pl/lang.php102
-rw-r--r--platform/www/lib/plugins/farmer/plugin.info.txt7
-rw-r--r--platform/www/lib/plugins/farmer/script.js2
-rw-r--r--platform/www/lib/plugins/farmer/script/jquery.chosen.js1257
-rw-r--r--platform/www/lib/plugins/farmer/script/plugins.js149
-rw-r--r--platform/www/lib/plugins/farmer/style.less104
105 files changed, 6577 insertions, 0 deletions
diff --git a/platform/www/lib/plugins/farmer/.github/auto-comment.yml b/platform/www/lib/plugins/farmer/.github/auto-comment.yml
new file mode 100644
index 0000000..f6a72e3
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/.github/auto-comment.yml
@@ -0,0 +1,9 @@
+# auto replies used by probot/auto-comment
+
+issuesOpened: >
+ Thank you for opening this issue.
+
+ [CosmoCode](https://www.cosmocode.de) is a software company in Berlin providing services for wiki, app and web development. As such we can't guarantee quick responses for issues opened on our Open Source projects.
+
+ If you require certain features or bugs fixed, you can always hire us. Feel free to contact us at dokuwiki@cosmocode.de for an offer.
+
diff --git a/platform/www/lib/plugins/farmer/.travis.yml b/platform/www/lib/plugins/farmer/.travis.yml
new file mode 100644
index 0000000..6814beb
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/.travis.yml
@@ -0,0 +1,15 @@
+# Config file for travis-ci.org
+
+language: php
+php:
+ - "7.3"
+ - "7.2"
+ - "7.1"
+ - "7.0"
+ - "5.6"
+env:
+ - DOKUWIKI=master
+ - DOKUWIKI=stable
+before_install: wget https://raw.github.com/splitbrain/dokuwiki-travis/master/travis.sh
+install: sh travis.sh
+script: cd _test && ./phpunit.phar --stderr --group plugin_farmer
diff --git a/platform/www/lib/plugins/farmer/3rdparty/PHPIco.php b/platform/www/lib/plugins/farmer/3rdparty/PHPIco.php
new file mode 100644
index 0000000..17b3b55
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/3rdparty/PHPIco.php
@@ -0,0 +1,248 @@
+<?php
+/*
+Copyright 2011-2013 Chris Jean & iThemes
+Licensed under GPLv2 or above
+
+Version 1.0.2
+
+Adjusted for DokuWiki Farmer Plugin
+*/
+
+namespace chrisbliss18\phpico;
+
+class PHPIco {
+ /**
+ * Images in the BMP format.
+ *
+ * @var array
+ * @access private
+ */
+ var $_images = array();
+
+ /**
+ * Constructor - Create a new ICO generator.
+ *
+ * If the constructor is not passed a file, a file will need to be supplied using the {@link PHP_ICO::add_image}
+ * function in order to generate an ICO file.
+ *
+ * @param bool|string $file Optional. Path to the source image file.
+ * @param array $sizes Optional. An array of sizes (each size is an array with a width and height) that the source image should be rendered at in the generated ICO file. If sizes are not supplied, the size of the source image will be used.
+ * @throws \Exception
+ */
+ function __construct( $file = false, $sizes = array() ) {
+ $required_functions = array(
+ 'getimagesize',
+ 'imagecreatefromstring',
+ 'imagecreatetruecolor',
+ 'imagecolortransparent',
+ 'imagecolorallocatealpha',
+ 'imagealphablending',
+ 'imagesavealpha',
+ 'imagesx',
+ 'imagesy',
+ 'imagecopyresampled',
+ );
+
+ foreach ( $required_functions as $function ) {
+ if ( ! function_exists( $function ) ) {
+ throw new \Exception( "The PHP_ICO class was unable to find the $function function, which is part of the GD library. Ensure that the system has the GD library installed and that PHP has access to it through a PHP interface, such as PHP's GD module. Since this function was not found, the library will be unable to create ICO files." );
+ }
+ }
+
+ if ( false != $file )
+ $this->add_image( $file, $sizes );
+ }
+
+ /**
+ * Add an image to the generator.
+ *
+ * This function adds a source image to the generator. It serves two main purposes: add a source image if one was
+ * not supplied to the constructor and to add additional source images so that different images can be supplied for
+ * different sized images in the resulting ICO file. For instance, a small source image can be used for the small
+ * resolutions while a larger source image can be used for large resolutions.
+ *
+ * @param string $file Path to the source image file.
+ * @param array $sizes Optional. An array of sizes (each size is an array with a width and height) that the source image should be rendered at in the generated ICO file. If sizes are not supplied, the size of the source image will be used.
+ * @return boolean true on success and false on failure.
+ */
+ function add_image( $file, $sizes = array() ) {
+ if ( false === ( $im = $this->_load_image_file( $file ) ) )
+ return false;
+
+
+ if ( empty( $sizes ) )
+ $sizes = array( imagesx( $im ), imagesy( $im ) );
+
+ // If just a single size was passed, put it in array.
+ if ( ! is_array( $sizes[0] ) )
+ $sizes = array( $sizes );
+
+ foreach ( (array) $sizes as $size ) {
+ list( $width, $height ) = $size;
+
+ $new_im = imagecreatetruecolor( $width, $height );
+
+ imagecolortransparent( $new_im, imagecolorallocatealpha( $new_im, 0, 0, 0, 127 ) );
+ imagealphablending( $new_im, false );
+ imagesavealpha( $new_im, true );
+
+ $source_width = imagesx( $im );
+ $source_height = imagesy( $im );
+
+ if ( false === imagecopyresampled( $new_im, $im, 0, 0, 0, 0, $width, $height, $source_width, $source_height ) )
+ continue;
+
+ $this->_add_image_data( $new_im );
+ }
+
+ return true;
+ }
+
+ /**
+ * Write the ICO file data to a file path.
+ *
+ * @param string $file Path to save the ICO file data into.
+ * @return boolean true on success and false on failure.
+ */
+ function save_ico( $file ) {
+ if ( false === ( $data = $this->_get_ico_data() ) )
+ return false;
+
+ if ( false === ( $fh = fopen( $file, 'w' ) ) )
+ return false;
+
+ if ( false === ( fwrite( $fh, $data ) ) ) {
+ fclose( $fh );
+ return false;
+ }
+
+ fclose( $fh );
+
+ return true;
+ }
+
+ /**
+ * Generate the final ICO data by creating a file header and adding the image data.
+ */
+ protected function _get_ico_data() {
+ if ( ! is_array( $this->_images ) || empty( $this->_images ) )
+ return false;
+
+
+ $data = pack( 'vvv', 0, 1, count( $this->_images ) );
+ $pixel_data = '';
+
+ $icon_dir_entry_size = 16;
+
+ $offset = 6 + ( $icon_dir_entry_size * count( $this->_images ) );
+
+ foreach ( $this->_images as $image ) {
+ $data .= pack( 'CCCCvvVV', $image['width'], $image['height'], $image['color_palette_colors'], 0, 1, $image['bits_per_pixel'], $image['size'], $offset );
+ $pixel_data .= $image['data'];
+
+ $offset += $image['size'];
+ }
+
+ $data .= $pixel_data;
+ unset( $pixel_data );
+
+
+ return $data;
+ }
+
+ /**
+ * Take a GD image resource and change it into a raw BMP format.
+ *
+ * @param resource $im
+ */
+ protected function _add_image_data( $im ) {
+ $width = imagesx( $im );
+ $height = imagesy( $im );
+
+
+ $pixel_data = array();
+
+ $opacity_data = array();
+ $current_opacity_val = 0;
+
+ for ( $y = $height - 1; $y >= 0; $y-- ) {
+ for ( $x = 0; $x < $width; $x++ ) {
+ $color = imagecolorat( $im, $x, $y );
+
+ $alpha = ( $color & 0x7F000000 ) >> 24;
+ $alpha = ( 1 - ( $alpha / 127 ) ) * 255;
+
+ $color &= 0xFFFFFF;
+ $color |= 0xFF000000 & ( $alpha << 24 );
+
+ $pixel_data[] = $color;
+
+
+ $opacity = ( $alpha <= 127 ) ? 1 : 0;
+
+ $current_opacity_val = ( $current_opacity_val << 1 ) | $opacity;
+
+ if ( ( ( $x + 1 ) % 32 ) == 0 ) {
+ $opacity_data[] = $current_opacity_val;
+ $current_opacity_val = 0;
+ }
+ }
+
+ if ( ( $x % 32 ) > 0 ) {
+ while ( ( $x++ % 32 ) > 0 )
+ $current_opacity_val = $current_opacity_val << 1;
+
+ $opacity_data[] = $current_opacity_val;
+ $current_opacity_val = 0;
+ }
+ }
+
+ $image_header_size = 40;
+ $color_mask_size = $width * $height * 4;
+ $opacity_mask_size = ( ceil( $width / 32 ) * 4 ) * $height;
+
+
+ $data = pack( 'VVVvvVVVVVV', 40, $width, ( $height * 2 ), 1, 32, 0, 0, 0, 0, 0, 0 );
+
+ foreach ( $pixel_data as $color )
+ $data .= pack( 'V', $color );
+
+ foreach ( $opacity_data as $opacity )
+ $data .= pack( 'N', $opacity );
+
+
+ $image = array(
+ 'width' => $width,
+ 'height' => $height,
+ 'color_palette_colors' => 0,
+ 'bits_per_pixel' => 32,
+ 'size' => $image_header_size + $color_mask_size + $opacity_mask_size,
+ 'data' => $data,
+ );
+
+ $this->_images[] = $image;
+ }
+
+ /**
+ * Read in the source image file and convert it into a GD image resource.
+ *
+ * @param string $file
+ * @return bool|resource
+ */
+ protected function _load_image_file( $file ) {
+ // Run a cheap check to verify that it is an image file.
+ if ( false === ( $size = getimagesize( $file ) ) )
+ return false;
+
+ if ( false === ( $file_data = file_get_contents( $file ) ) )
+ return false;
+
+ if ( false === ( $im = imagecreatefromstring( $file_data ) ) )
+ return false;
+
+ unset( $file_data );
+
+
+ return $im;
+ }
+}
diff --git a/platform/www/lib/plugins/farmer/3rdparty/RingIcon.php b/platform/www/lib/plugins/farmer/3rdparty/RingIcon.php
new file mode 100644
index 0000000..c8dfdbc
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/3rdparty/RingIcon.php
@@ -0,0 +1,186 @@
+<?php
+
+namespace splitbrain\RingIcon;
+
+/**
+ * Class RingIcon
+ *
+ * Generates a identicon/visiglyph like image based on concentric rings
+ *
+ * @todo add a mono color version
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @license MIT
+ * @package splitbrain\RingIcon
+ */
+class RingIcon
+{
+
+ protected $size;
+ protected $fullsize;
+ protected $rings;
+ protected $center;
+ protected $ringwidth;
+ protected $seed;
+ protected $ismono = false;
+ protected $monocolor = null;
+
+ /**
+ * RingIcon constructor.
+ * @param int $size width and height of the resulting image
+ * @param int $rings number of rings
+ */
+ public function __construct($size, $rings = 3)
+ {
+ $this->size = $size;
+ $this->fullsize = $this->size * 5;
+ $this->rings = 4;
+
+ $this->center = floor($this->fullsize / 2);
+ $this->ringwidth = floor($this->fullsize / $rings);
+
+ $this->seed = mt_rand() . time();
+ }
+
+ /**
+ * Generates an ring image
+ *
+ * If a seed is given, the image will be based on that seed
+ *
+ * @param string $seed initialize the genrator with this string
+ * @param string $file if given, the image is saved at that path, otherwise is printed to browser
+ */
+ public function createImage($seed = '', $file = '')
+ {
+ if (!$seed) {
+ $seed = mt_rand() . time();
+ }
+ $this->seed = $seed;
+
+ // monochrome wanted?
+ if($this->ismono) {
+ $this->monocolor = array(
+ $this->rand(20,255),
+ $this->rand(20,255),
+ $this->rand(20,255)
+ );
+ } else {
+ $this->monocolor = null;
+ }
+
+ // create
+ $image = $this->createTransparentImage($this->fullsize, $this->fullsize);
+ $arcwidth = $this->fullsize;
+ for ($i = $this->rings; $i > 0; $i--) {
+ $this->drawRing($image, $arcwidth);
+ $arcwidth -= $this->ringwidth;
+ }
+
+ // resample for antialiasing
+ $out = $this->createTransparentImage($this->size, $this->size);
+ imagecopyresampled($out, $image, 0, 0, 0, 0, $this->size, $this->size, $this->fullsize, $this->fullsize);
+ if ($file) {
+ imagepng($out, $file);
+ } else {
+ header("Content-type: image/png");
+ imagepng($out);
+ }
+ imagedestroy($out);
+ imagedestroy($image);
+ }
+
+ /**
+ * When set to true a monochrome version is returned
+ *
+ * @param bool $ismono
+ */
+ public function setMono($ismono) {
+ $this->ismono = $ismono;
+ }
+
+ /**
+ * Generate number from seed
+ *
+ * Each call runs MD5 on the seed again
+ *
+ * @param int $min
+ * @param int $max
+ * @return int
+ */
+ protected function rand($min, $max)
+ {
+ $this->seed = md5($this->seed);
+ $rand = hexdec(substr($this->seed, 0, 8));
+ return ($rand % ($max - $min + 1)) + $min;
+ }
+
+ /**
+ * Drawas a single ring
+ *
+ * @param resource $image
+ * @param int $arcwidth outer width of the ring
+ */
+ protected function drawRing($image, $arcwidth)
+ {
+ $color = $this->randomColor($image);
+ $transparency = $this->transparentColor($image);
+
+ $start = $this->rand(20, 360);
+ $stop = $this->rand(20, 360);
+ if($stop < $start) list($start, $stop) = array($stop, $start);
+
+ imagefilledarc($image, $this->center, $this->center, $arcwidth, $arcwidth, $stop, $start, $color, IMG_ARC_PIE);
+ imagefilledellipse($image, $this->center, $this->center, $arcwidth - $this->ringwidth,
+ $arcwidth - $this->ringwidth, $transparency);
+
+ imagecolordeallocate($image, $color);
+ imagecolordeallocate($image, $transparency);
+ }
+
+ /**
+ * Allocate a transparent color
+ *
+ * @param resource $image
+ * @return int
+ */
+ protected function transparentColor($image)
+ {
+ return imagecolorallocatealpha($image, 0, 0, 0, 127);
+ }
+
+ /**
+ * Allocate a random color
+ *
+ * @param $image
+ * @return int
+ */
+ protected function randomColor($image)
+ {
+ if($this->ismono) {
+ return imagecolorallocatealpha($image, $this->monocolor[0], $this->monocolor[1], $this->monocolor[2], $this->rand(0, 96));
+ }
+ return imagecolorallocate($image, $this->rand(0, 255), $this->rand(0, 255), $this->rand(0, 255));
+ }
+
+ /**
+ * Create a transparent image
+ *
+ * @param int $width
+ * @param int $height
+ * @return resource
+ * @throws \Exception
+ */
+ protected function createTransparentImage($width, $height)
+ {
+ $image = @imagecreatetruecolor($width, $height);
+ if (!$image) {
+ throw new \Exception('Missing libgd support');
+ }
+ imagealphablending($image, false);
+ $transparency = $this->transparentColor($image);
+ imagefill($image, 0, 0, $transparency);
+ imagecolordeallocate($image, $transparency);
+ imagesavealpha($image, true);
+ return $image;
+ }
+
+}
diff --git a/platform/www/lib/plugins/farmer/DokuWikiFarmCore.php b/platform/www/lib/plugins/farmer/DokuWikiFarmCore.php
new file mode 100644
index 0000000..6c8547a
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/DokuWikiFarmCore.php
@@ -0,0 +1,375 @@
+<?php
+
+/**
+ * Core Manager for the Farm functionality
+ *
+ * This class is initialized before any other DokuWiki code runs. Therefore it is
+ * completely selfcontained and does not use any of DokuWiki's utility functions.
+ *
+ * It's registered as a global $FARMCORE variable but you should not interact with
+ * it directly. Instead use the Farmer plugin's helper component.
+ *
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+class DokuWikiFarmCore {
+ /**
+ * @var array The default config - changed by loadConfig
+ */
+ protected $config = array(
+ 'base' => array(
+ 'farmdir' => '',
+ 'farmhost' => '',
+ 'basedomain' => '',
+ ),
+ 'notfound' => array(
+ 'show' => 'farmer',
+ 'url' => ''
+ ),
+ 'inherit' => array(
+ 'main' => 1,
+ 'acronyms' => 1,
+ 'entities' => 1,
+ 'interwiki' => 1,
+ 'license' => 1,
+ 'mime' => 1,
+ 'scheme' => 1,
+ 'smileys' => 1,
+ 'wordblock' => 1,
+ 'users' => 0,
+ 'plugins' => 0,
+ 'userstyle' => 0,
+ 'userscript' => 0,
+ 'styleini' => 0
+ )
+ );
+
+ /** @var string|false The current animal, false for farmer */
+ protected $animal = false;
+ /** @var bool true if an animal was requested but was not found */
+ protected $notfound = false;
+ /** @var bool true if the current animal was requested by host */
+ protected $hostbased = false;
+
+ /**
+ * DokuWikiFarmCore constructor.
+ *
+ * This initializes the whole farm by loading the configuration and setting
+ * DOKU_CONF depending on the requested animal
+ */
+ public function __construct() {
+ $this->loadConfig();
+ if($this->config['base']['farmdir'] === '') return; // farm setup not complete
+ $this->config['base']['farmdir'] = rtrim($this->config['base']['farmdir'], '/').'/'; // trailing slash always
+ define('DOKU_FARMDIR', $this->config['base']['farmdir']);
+
+ // animal?
+ $this->detectAnimal();
+
+ // setup defines
+ define('DOKU_FARM_ANIMAL', $this->animal);
+ if($this->animal) {
+ define('DOKU_CONF', DOKU_FARMDIR . $this->animal . '/conf/');
+ } else {
+ define('DOKU_CONF', DOKU_INC . '/conf/');
+ }
+
+ $this->setupCascade();
+ $this->adjustCascade();
+ }
+
+ /**
+ * @return array the current farm configuration
+ */
+ public function getConfig() {
+ return $this->config;
+ }
+
+ /**
+ * @return false|string
+ */
+ public function getAnimal() {
+ return $this->animal;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isHostbased() {
+ return $this->hostbased;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function wasNotfound() {
+ return $this->notfound;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAnimalDataDir() {
+ return DOKU_FARMDIR . $this->getAnimal() . '/data/';
+ }
+
+ /**
+ * @return string
+ */
+ public function getAnimalBaseDir() {
+ if($this->isHostbased()) return '/';
+ return getBaseURL() . '!' . $this->getAnimal();
+ }
+
+ /**
+ * Detect the current animal
+ *
+ * Sets internal members $animal, $notfound and $hostbased
+ *
+ * This borrows form DokuWiki's inc/farm.php but does not support a default conf dir
+ */
+ protected function detectAnimal() {
+ $farmdir = $this->config['base']['farmdir'];
+ $farmhost = $this->config['base']['farmhost'];
+
+ // check if animal was set via parameter (rewrite or CLI)
+ $animal = '';
+ if(isset($_REQUEST['animal'])) $animal = $_REQUEST['animal'];
+ if('cli' == php_sapi_name() && isset($_SERVER['animal'])) $animal = $_SERVER['animal'];
+ if($animal) {
+ // check that $animal is a string and just a directory name and not a path
+ if(!is_string($animal) || strpbrk($animal, '\\/') !== false) {
+ $this->notfound = true;
+ return;
+ };
+ $animal = strtolower($animal);
+
+ // check if animal exists
+ if(is_dir("$farmdir/$animal/conf")) {
+ $this->animal = $animal;
+ return;
+ } else {
+ $this->notfound = true;
+ return;
+ }
+ }
+
+ // no host - no host based setup. if we're still here then it's the farmer
+ if(!isset($_SERVER['HTTP_HOST'])) return;
+
+ // is this the farmer?
+ if(strtolower($_SERVER['HTTP_HOST']) == $farmhost) {
+ return;
+ }
+
+ // still here? check for host based
+ $this->hostbased = true;
+ $possible = $this->getAnimalNamesForHost($_SERVER['HTTP_HOST']);
+ foreach($possible as $animal) {
+ if(is_dir("$farmdir/$animal/conf/")) {
+ $this->animal = $animal;
+ return;
+ }
+ }
+
+ // no hit
+ $this->notfound = true;
+ return;
+ }
+
+ /**
+ * Return a list of possible animal names for the given host
+ *
+ * @param string $host the HTTP_HOST header
+ * @return array
+ */
+ protected function getAnimalNamesForHost($host) {
+ $animals = array();
+ $parts = explode('.', implode('.', explode(':', rtrim($host, '.'))));
+ for($j = count($parts); $j > 0; $j--) {
+ // strip from the end
+ $animals[] = implode('.', array_slice($parts, 0, $j));
+ // strip from the end without host part
+ $animals[] = implode('.', array_slice($parts, 1, $j));
+ }
+ $animals = array_unique($animals);
+ $animals = array_filter($animals);
+ usort(
+ $animals,
+ // compare by length, then alphabet
+ function ($a, $b) {
+ $ret = strlen($b) - strlen($a);
+ if($ret != 0) return $ret;
+ return $a > $b;
+ }
+ );
+ return $animals;
+ }
+
+ /**
+ * This sets up the default farming config cascade
+ */
+ protected function setupCascade() {
+ global $config_cascade;
+ $config_cascade = array(
+ 'main' => array(
+ 'default' => array(DOKU_INC . 'conf/dokuwiki.php',),
+ 'local' => array(DOKU_CONF . 'local.php',),
+ 'protected' => array(DOKU_CONF . 'local.protected.php',),
+ ),
+ 'acronyms' => array(
+ 'default' => array(DOKU_INC . 'conf/acronyms.conf',),
+ 'local' => array(DOKU_CONF . 'acronyms.local.conf',),
+ ),
+ 'entities' => array(
+ 'default' => array(DOKU_INC . 'conf/entities.conf',),
+ 'local' => array(DOKU_CONF . 'entities.local.conf',),
+ ),
+ 'interwiki' => array(
+ 'default' => array(DOKU_INC . 'conf/interwiki.conf',),
+ 'local' => array(DOKU_CONF . 'interwiki.local.conf',),
+ ),
+ 'license' => array(
+ 'default' => array(DOKU_INC . 'conf/license.php',),
+ 'local' => array(DOKU_CONF . 'license.local.php',),
+ ),
+ 'manifest' => array(
+ 'default' => array(DOKU_INC . 'conf/manifest.json',),
+ 'local' => array(DOKU_CONF . 'manifest.local.json',),
+ ),
+ 'mediameta' => array(
+ 'default' => array(DOKU_INC . 'conf/mediameta.php',),
+ 'local' => array(DOKU_CONF . 'mediameta.local.php',),
+ ),
+ 'mime' => array(
+ 'default' => array(DOKU_INC . 'conf/mime.conf',),
+ 'local' => array(DOKU_CONF . 'mime.local.conf',),
+ ),
+ 'scheme' => array(
+ 'default' => array(DOKU_INC . 'conf/scheme.conf',),
+ 'local' => array(DOKU_CONF . 'scheme.local.conf',),
+ ),
+ 'smileys' => array(
+ 'default' => array(DOKU_INC . 'conf/smileys.conf',),
+ 'local' => array(DOKU_CONF . 'smileys.local.conf',),
+ ),
+ 'wordblock' => array(
+ 'default' => array(DOKU_INC . 'conf/wordblock.conf',),
+ 'local' => array(DOKU_CONF . 'wordblock.local.conf',),
+ ),
+ 'acl' => array(
+ 'default' => DOKU_CONF . 'acl.auth.php',
+ ),
+ 'plainauth.users' => array(
+ 'default' => DOKU_CONF . 'users.auth.php',
+ ),
+ 'plugins' => array(
+ 'default' => array(DOKU_INC . 'conf/plugins.php',),
+ 'local' => array(DOKU_CONF . 'plugins.local.php',),
+ 'protected' => array(
+ DOKU_INC . 'conf/plugins.required.php',
+ DOKU_CONF . 'plugins.protected.php',
+ ),
+ ),
+ 'userstyle' => array(
+ 'screen' => array(DOKU_CONF . 'userstyle.css', DOKU_CONF . 'userstyle.less',),
+ 'print' => array(DOKU_CONF . 'userprint.css', DOKU_CONF . 'userprint.less',),
+ 'feed' => array(DOKU_CONF . 'userfeed.css', DOKU_CONF . 'userfeed.less',),
+ 'all' => array(DOKU_CONF . 'userall.css', DOKU_CONF . 'userall.less',),
+ ),
+ 'userscript' => array(
+ 'default' => array(DOKU_CONF . 'userscript.js',),
+ ),
+ 'styleini' => array(
+ 'default' => array(DOKU_INC . 'lib/tpl/%TEMPLATE%/' . 'style.ini'),
+ 'local' => array(DOKU_CONF . 'tpl/%TEMPLATE%/' . 'style.ini')
+ ),
+ );
+ }
+
+ /**
+ * This adds additional files to the config cascade based on the inheritence settings
+ *
+ * These are only added for animals, not the farmer
+ */
+ protected function adjustCascade() {
+ // nothing to do when on the farmer:
+ if(!$this->animal) return;
+
+ global $config_cascade;
+ foreach($this->config['inherit'] as $key => $val) {
+ if(!$val) continue;
+
+ // prepare what is to append or prepend
+ $append = array();
+ $prepend = array();
+ if($key == 'main') {
+ $append = array(
+ 'default' => array(DOKU_INC . 'conf/local.php'),
+ 'protected' => array(DOKU_INC . 'lib/plugins/farmer/includes/config.php')
+ );
+ } elseif($key == 'license') {
+ $append = array('default' => array(DOKU_INC . 'conf/' . $key . '.local.php'));
+ } elseif($key == 'userscript') {
+ $prepend = array('default' => array(DOKU_INC . 'conf/userscript.js'));
+ } elseif($key == 'userstyle') {
+ $prepend = array(
+ 'screen' => array(DOKU_INC . 'conf/userstyle.css', DOKU_INC . 'conf/userstyle.less',),
+ 'print' => array(DOKU_INC . 'conf/userprint.css', DOKU_INC . 'conf/userprint.less',),
+ 'feed' => array(DOKU_INC . 'conf/userfeed.css', DOKU_INC . 'conf/userfeed.less',),
+ 'all' => array(DOKU_INC . 'conf/userall.css', DOKU_INC . 'conf/userall.less',),
+ );
+ } elseif ($key == 'styleini') {
+ $append = array(
+ 'local' => array(
+ DOKU_INC . 'conf/tpl/%TEMPLATE%/style.ini'
+ )
+ );
+ } elseif($key == 'users') {
+ $config_cascade['plainauth.users']['protected'] = DOKU_INC . 'conf/users.auth.php';
+ } elseif($key == 'plugins') {
+ $append = array('default' => array(DOKU_INC . 'conf/plugins.local.php'));
+ } else {
+ $append = array('default' => array(DOKU_INC . 'conf/' . $key . '.local.conf'));
+ }
+
+ // add to cascade
+ foreach($prepend as $section => $data) {
+ $config_cascade[$key][$section] = array_merge($data, $config_cascade[$key][$section]);
+ }
+ foreach($append as $section => $data) {
+ $config_cascade[$key][$section] = array_merge($config_cascade[$key][$section], $data);
+ }
+ }
+
+ // add plugin overrides
+ $config_cascade['plugins']['protected'][] = DOKU_INC . 'lib/plugins/farmer/includes/plugins.php';
+ }
+
+ /**
+ * Loads the farm config
+ */
+ protected function loadConfig() {
+ $ini = DOKU_INC . 'conf/farm.ini';
+ if(!file_exists($ini)) return;
+ $config = parse_ini_file($ini, true);
+ foreach(array_keys($this->config) as $section) {
+ if(isset($config[$section])) {
+ $this->config[$section] = array_merge(
+ $this->config[$section],
+ $config[$section]
+ );
+ }
+ }
+
+ $this->config['base']['farmdir'] = trim($this->config['base']['farmdir']);
+ $this->config['base']['farmhost'] = strtolower(trim($this->config['base']['farmhost']));
+ }
+
+}
+
+// initialize it globally
+if(!defined('DOKU_UNITTEST')) {
+ global $FARMCORE;
+ $FARMCORE = new DokuWikiFarmCore();
+}
diff --git a/platform/www/lib/plugins/farmer/README b/platform/www/lib/plugins/farmer/README
new file mode 100644
index 0000000..0515a92
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/README
@@ -0,0 +1,27 @@
+farmer Plugin for DokuWiki
+
+A plugin to help with creating and administring wiki farm animals
+
+All documentation for this plugin can be found at
+https://dokuwiki.org/plugin:farmer
+
+If you install this plugin manually, make sure it is installed in
+lib/plugins/farmer/ - if the folder is called different it
+will not work!
+
+Please refer to http://www.dokuwiki.org/plugins for additional info
+on how to install plugins in DokuWiki.
+
+----
+Copyright (C) Michael Große, Andreas Gohr <dokuwiki@cosmocode.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; version 2 of the License
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+See the COPYING file in your DokuWiki folder for details
diff --git a/platform/www/lib/plugins/farmer/_animal/conf/acl.auth.php b/platform/www/lib/plugins/farmer/_animal/conf/acl.auth.php
new file mode 100644
index 0000000..14344d7
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/conf/acl.auth.php
@@ -0,0 +1,21 @@
+# acl.auth.php
+# <?php exit()?>
+# Don't modify the lines above
+#
+# Access Control Lists
+#
+# Editing this file by hand shouldn't be necessary. Use the ACL
+# Manager interface instead.
+#
+# If your auth backend allows special char like spaces in groups
+# or user names you need to urlencode them (only chars <128, leave
+# UTF-8 multibyte chars as is)
+#
+# none 0
+# read 1
+# edit 2
+# create 4
+# upload 8
+# delete 16
+
+* @ALL 8
diff --git a/platform/www/lib/plugins/farmer/_animal/conf/local.php b/platform/www/lib/plugins/farmer/_animal/conf/local.php
new file mode 100644
index 0000000..109a33a
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/conf/local.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Minimal local config
+ */
+$conf['useacl'] = 1;
+$conf['superuser'] = '@admin';
diff --git a/platform/www/lib/plugins/farmer/_animal/data/_dummy b/platform/www/lib/plugins/farmer/_animal/data/_dummy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/data/_dummy
diff --git a/platform/www/lib/plugins/farmer/_animal/data/attic/_dummy b/platform/www/lib/plugins/farmer/_animal/data/attic/_dummy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/data/attic/_dummy
diff --git a/platform/www/lib/plugins/farmer/_animal/data/cache/_dummy b/platform/www/lib/plugins/farmer/_animal/data/cache/_dummy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/data/cache/_dummy
diff --git a/platform/www/lib/plugins/farmer/_animal/data/index/_dummy b/platform/www/lib/plugins/farmer/_animal/data/index/_dummy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/data/index/_dummy
diff --git a/platform/www/lib/plugins/farmer/_animal/data/locks/_dummy b/platform/www/lib/plugins/farmer/_animal/data/locks/_dummy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/data/locks/_dummy
diff --git a/platform/www/lib/plugins/farmer/_animal/data/log/_dummy b/platform/www/lib/plugins/farmer/_animal/data/log/_dummy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/data/log/_dummy
diff --git a/platform/www/lib/plugins/farmer/_animal/data/media/wiki/dokuwiki-128.png b/platform/www/lib/plugins/farmer/_animal/data/media/wiki/dokuwiki-128.png
new file mode 100644
index 0000000..b2306ac
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/data/media/wiki/dokuwiki-128.png
Binary files differ
diff --git a/platform/www/lib/plugins/farmer/_animal/data/media_attic/_dummy b/platform/www/lib/plugins/farmer/_animal/data/media_attic/_dummy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/data/media_attic/_dummy
diff --git a/platform/www/lib/plugins/farmer/_animal/data/media_meta/_dummy b/platform/www/lib/plugins/farmer/_animal/data/media_meta/_dummy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/data/media_meta/_dummy
diff --git a/platform/www/lib/plugins/farmer/_animal/data/meta/_dummy b/platform/www/lib/plugins/farmer/_animal/data/meta/_dummy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/data/meta/_dummy
diff --git a/platform/www/lib/plugins/farmer/_animal/data/pages/wiki/dokuwiki.txt b/platform/www/lib/plugins/farmer/_animal/data/pages/wiki/dokuwiki.txt
new file mode 100644
index 0000000..e6fac5b
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/data/pages/wiki/dokuwiki.txt
@@ -0,0 +1,64 @@
+====== DokuWiki ======
+
+[[doku>wiki:dokuwiki|{{wiki:dokuwiki-128.png }}]] DokuWiki is a standards compliant, simple to use [[wp>Wiki]], mainly aimed at creating documentation of any kind. It is targeted at developer teams, workgroups and small companies. It has a simple but powerful [[wiki:syntax]] which makes sure the datafiles remain readable outside the Wiki and eases the creation of structured texts. All data is stored in plain text files -- no database is required.
+
+Read the [[doku>manual|DokuWiki Manual]] to unleash the full power of DokuWiki.
+
+===== Download =====
+
+DokuWiki is available at http://www.splitbrain.org/go/dokuwiki
+
+
+===== Read More =====
+
+All documentation and additional information besides the [[syntax|syntax description]] is maintained in the DokuWiki at [[doku>|www.dokuwiki.org]].
+
+**About DokuWiki**
+
+ * [[doku>features|A feature list]] :!:
+ * [[doku>users|Happy Users]]
+ * [[doku>press|Who wrote about it]]
+ * [[doku>blogroll|What Bloggers think]]
+ * [[http://www.wikimatrix.org/show/DokuWiki|Compare it with other wiki software]]
+
+**Installing DokuWiki**
+
+ * [[doku>requirements|System Requirements]]
+ * [[http://www.splitbrain.org/go/dokuwiki|Download DokuWiki]] :!:
+ * [[doku>changes|Change Log]]
+ * [[doku>Install|How to install or upgrade]] :!:
+ * [[doku>config|Configuration]]
+
+**Using DokuWiki**
+
+ * [[doku>syntax|Wiki Syntax]]
+ * [[doku>manual|The manual]] :!:
+ * [[doku>FAQ|Frequently Asked Questions (FAQ)]]
+ * [[doku>glossary|Glossary]]
+ * [[http://search.dokuwiki.org|Search for DokuWiki help and documentation]]
+
+**Customizing DokuWiki**
+
+ * [[doku>tips|Tips and Tricks]]
+ * [[doku>Template|How to create and use templates]]
+ * [[doku>plugins|Installing plugins]]
+ * [[doku>development|Development Resources]]
+
+**DokuWiki Feedback and Community**
+
+ * [[doku>newsletter|Subscribe to the newsletter]] :!:
+ * [[doku>mailinglist|Join the mailing list]]
+ * [[http://forum.dokuwiki.org|Check out the user forum]]
+ * [[doku>irc|Talk to other users in the IRC channel]]
+ * [[http://bugs.splitbrain.org/index.php?project=1|Submit bugs and feature wishes]]
+ * [[http://www.wikimatrix.org/forum/viewforum.php?id=10|Share your experiences in the WikiMatrix forum]]
+ * [[doku>thanks|Some humble thanks]]
+
+
+===== Copyright =====
+
+2004-2010 (c) Andreas Gohr <andi@splitbrain.org>((Please do not contact me for help and support -- use the [[doku>mailinglist]] or [[http://forum.dokuwiki.org|forum]] instead)) and the DokuWiki Community
+
+The DokuWiki engine is licensed under [[http://www.gnu.org/licenses/gpl.html|GNU General Public License]] Version 2. If you use DokuWiki in your company, consider [[doku>donate|donating]] a few bucks ;-).
+
+Not sure what this means? See the [[doku>faq:license|FAQ on the Licenses]].
diff --git a/platform/www/lib/plugins/farmer/_animal/data/pages/wiki/syntax.txt b/platform/www/lib/plugins/farmer/_animal/data/pages/wiki/syntax.txt
new file mode 100644
index 0000000..dd3154e
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/data/pages/wiki/syntax.txt
@@ -0,0 +1,486 @@
+====== Formatting Syntax ======
+
+[[doku>DokuWiki]] supports some simple markup language, which tries to make the datafiles to be as readable as possible. This page contains all possible syntax you may use when editing the pages. Simply have a look at the source of this page by pressing the //Edit this page// button at the top or bottom of the page. If you want to try something, just use the [[playground:playground|playground]] page. The simpler markup is easily accessible via [[doku>toolbar|quickbuttons]], too.
+
+===== Basic Text Formatting =====
+
+DokuWiki supports **bold**, //italic//, __underlined__ and ''monospaced'' texts. Of course you can **__//''combine''//__** all these.
+
+ DokuWiki supports **bold**, //italic//, __underlined__ and ''monospaced'' texts.
+ Of course you can **__//''combine''//__** all these.
+
+You can use <sub>subscript</sub> and <sup>superscript</sup>, too.
+
+ You can use <sub>subscript</sub> and <sup>superscript</sup>, too.
+
+You can mark something as <del>deleted</del> as well.
+
+ You can mark something as <del>deleted</del> as well.
+
+**Paragraphs** are created from blank lines. If you want to **force a newline** without a paragraph, you can use two backslashes followed by a whitespace or the end of line.
+
+This is some text with some linebreaks\\ Note that the
+two backslashes are only recognized at the end of a line\\
+or followed by\\ a whitespace \\this happens without it.
+
+ This is some text with some linebreaks\\ Note that the
+ two backslashes are only recognized at the end of a line\\
+ or followed by\\ a whitespace \\this happens without it.
+
+You should use forced newlines only if really needed.
+
+===== Links =====
+
+DokuWiki supports multiple ways of creating links.
+
+==== External ====
+
+External links are recognized automagically: http://www.google.com or simply www.google.com - You can set the link text as well: [[http://www.google.com|This Link points to google]]. Email addresses like this one: <andi@splitbrain.org> are recognized, too.
+
+ DokuWiki supports multiple ways of creating links. External links are recognized
+ automagically: http://www.google.com or simply www.google.com - You can set
+ link text as well: [[http://www.google.com|This Link points to google]]. Email
+ addresses like this one: <andi@splitbrain.org> are recognized, too.
+
+==== Internal ====
+
+Internal links are created by using square brackets. You can either just give a [[pagename]] or use an additional [[pagename|link text]].
+
+ Internal links are created by using square brackets. You can either just give
+ a [[pagename]] or use an additional [[pagename|link text]].
+
+[[doku>pagename|Wiki pagenames]] are converted to lowercase automatically, special characters are not allowed.
+
+You can use [[some:namespaces]] by using a colon in the pagename.
+
+ You can use [[some:namespaces]] by using a colon in the pagename.
+
+For details about namespaces see [[doku>namespaces]].
+
+Linking to a specific section is possible, too. Just add the section name behind a hash character as known from HTML. This links to [[syntax#internal|this Section]].
+
+ This links to [[syntax#internal|this Section]].
+
+Notes:
+
+ * Links to [[syntax|existing pages]] are shown in a different style from [[nonexisting]] ones.
+ * DokuWiki does not use [[wp>CamelCase]] to automatically create links by default, but this behavior can be enabled in the [[doku>config]] file. Hint: If DokuWiki is a link, then it's enabled.
+ * When a section's heading is changed, its bookmark changes, too. So don't rely on section linking too much.
+
+==== Interwiki ====
+
+DokuWiki supports [[doku>Interwiki]] links. These are quick links to other Wikis. For example this is a link to Wikipedia's page about Wikis: [[wp>Wiki]].
+
+ DokuWiki supports [[doku>Interwiki]] links. These are quick links to other Wikis.
+ For example this is a link to Wikipedia's page about Wikis: [[wp>Wiki]].
+
+==== Windows Shares ====
+
+Windows shares like [[\\server\share|this]] are recognized, too. Please note that these only make sense in a homogeneous user group like a corporate [[wp>Intranet]].
+
+ Windows Shares like [[\\server\share|this]] are recognized, too.
+
+Notes:
+
+ * For security reasons direct browsing of windows shares only works in Microsoft Internet Explorer per default (and only in the "local zone").
+ * For Mozilla and Firefox it can be enabled through different workaround mentioned in the [[http://kb.mozillazine.org/Links_to_local_pages_do_not_work|Mozilla Knowledge Base]]. However, there will still be a JavaScript warning about trying to open a Windows Share. To remove this warning (for all users), put the following line in ''conf/local.protected.php'':
+
+ $lang['js']['nosmblinks'] = '';
+
+==== Image Links ====
+
+You can also use an image to link to another internal or external page by combining the syntax for links and [[#images_and_other_files|images]] (see below) like this:
+
+ [[http://www.php.net|{{wiki:dokuwiki-128.png}}]]
+
+[[http://www.php.net|{{wiki:dokuwiki-128.png}}]]
+
+Please note: The image formatting is the only formatting syntax accepted in link names.
+
+The whole [[#images_and_other_files|image]] and [[#links|link]] syntax is supported (including image resizing, internal and external images and URLs and interwiki links).
+
+===== Footnotes =====
+
+You can add footnotes ((This is a footnote)) by using double parentheses.
+
+ You can add footnotes ((This is a footnote)) by using double parentheses.
+
+===== Sectioning =====
+
+You can use up to five different levels of headlines to structure your content. If you have more than three headlines, a table of contents is generated automatically -- this can be disabled by including the string ''<nowiki>~~NOTOC~~</nowiki>'' in the document.
+
+==== Headline Level 3 ====
+=== Headline Level 4 ===
+== Headline Level 5 ==
+
+ ==== Headline Level 3 ====
+ === Headline Level 4 ===
+ == Headline Level 5 ==
+
+By using four or more dashes, you can make a horizontal line:
+
+----
+
+===== Images and Other Files =====
+
+You can include external and internal [[doku>images]] with curly brackets. Optionally you can specify the size of them.
+
+Real size: {{wiki:dokuwiki-128.png}}
+
+Resize to given width: {{wiki:dokuwiki-128.png?50}}
+
+Resize to given width and height((when the aspect ratio of the given width and height doesn't match that of the image, it will be cropped to the new ratio before resizing)): {{wiki:dokuwiki-128.png?200x50}}
+
+Resized external image: {{http://de3.php.net/images/php.gif?200x50}}
+
+ Real size: {{wiki:dokuwiki-128.png}}
+ Resize to given width: {{wiki:dokuwiki-128.png?50}}
+ Resize to given width and height: {{wiki:dokuwiki-128.png?200x50}}
+ Resized external image: {{http://de3.php.net/images/php.gif?200x50}}
+
+
+By using left or right whitespaces you can choose the alignment.
+
+{{ wiki:dokuwiki-128.png}}
+
+{{wiki:dokuwiki-128.png }}
+
+{{ wiki:dokuwiki-128.png }}
+
+ {{ wiki:dokuwiki-128.png}}
+ {{wiki:dokuwiki-128.png }}
+ {{ wiki:dokuwiki-128.png }}
+
+Of course, you can add a title (displayed as a tooltip by most browsers), too.
+
+{{ wiki:dokuwiki-128.png |This is the caption}}
+
+ {{ wiki:dokuwiki-128.png |This is the caption}}
+
+If you specify a filename (external or internal) that is not an image (''gif, jpeg, png''), then it will be displayed as a link instead.
+
+For linking an image to another page see [[#Image Links]] above.
+
+===== Lists =====
+
+Dokuwiki supports ordered and unordered lists. To create a list item, indent your text by two spaces and use a ''*'' for unordered lists or a ''-'' for ordered ones.
+
+ * This is a list
+ * The second item
+ * You may have different levels
+ * Another item
+
+ - The same list but ordered
+ - Another item
+ - Just use indention for deeper levels
+ - That's it
+
+<code>
+ * This is a list
+ * The second item
+ * You may have different levels
+ * Another item
+
+ - The same list but ordered
+ - Another item
+ - Just use indention for deeper levels
+ - That's it
+</code>
+
+Also take a look at the [[doku>faq:lists|FAQ on list items]].
+
+===== Text Conversions =====
+
+DokuWiki can convert certain pre-defined characters or strings into images or other text or HTML.
+
+The text to image conversion is mainly done for smileys. And the text to HTML conversion is used for typography replacements, but can be configured to use other HTML as well.
+
+==== Text to Image Conversions ====
+
+DokuWiki converts commonly used [[wp>emoticon]]s to their graphical equivalents. Those [[doku>Smileys]] and other images can be configured and extended. Here is an overview of Smileys included in DokuWiki:
+
+ * 8-) %% 8-) %%
+ * 8-O %% 8-O %%
+ * :-( %% :-( %%
+ * :-) %% :-) %%
+ * =) %% =) %%
+ * :-/ %% :-/ %%
+ * :-\ %% :-\ %%
+ * :-? %% :-? %%
+ * :-D %% :-D %%
+ * :-P %% :-P %%
+ * :-O %% :-O %%
+ * :-X %% :-X %%
+ * :-| %% :-| %%
+ * ;-) %% ;-) %%
+ * ^_^ %% ^_^ %%
+ * :?: %% :?: %%
+ * :!: %% :!: %%
+ * LOL %% LOL %%
+ * FIXME %% FIXME %%
+ * DELETEME %% DELETEME %%
+
+==== Text to HTML Conversions ====
+
+Typography: [[DokuWiki]] can convert simple text characters to their typographically correct entities. Here is an example of recognized characters.
+
+-> <- <-> => <= <=> >> << -- --- 640x480 (c) (tm) (r)
+"He thought 'It's a man's world'..."
+
+<code>
+-> <- <-> => <= <=> >> << -- --- 640x480 (c) (tm) (r)
+"He thought 'It's a man's world'..."
+</code>
+
+The same can be done to produce any kind of HTML, it just needs to be added to the [[doku>entities|pattern file]].
+
+There are three exceptions which do not come from that pattern file: multiplication entity (640x480), 'single' and "double quotes". They can be turned off through a [[doku>config:typography|config option]].
+
+===== Quoting =====
+
+Some times you want to mark some text to show it's a reply or comment. You can use the following syntax:
+
+ I think we should do it
+
+ > No we shouldn't
+
+ >> Well, I say we should
+
+ > Really?
+
+ >> Yes!
+
+ >>> Then lets do it!
+
+I think we should do it
+
+> No we shouldn't
+
+>> Well, I say we should
+
+> Really?
+
+>> Yes!
+
+>>> Then lets do it!
+
+===== Tables =====
+
+DokuWiki supports a simple syntax to create tables.
+
+^ Heading 1 ^ Heading 2 ^ Heading 3 ^
+| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 |
+| Row 2 Col 1 | some colspan (note the double pipe) ||
+| Row 3 Col 1 | Row 3 Col 2 | Row 3 Col 3 |
+
+Table rows have to start and end with a ''|'' for normal rows or a ''^'' for headers.
+
+ ^ Heading 1 ^ Heading 2 ^ Heading 3 ^
+ | Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 |
+ | Row 2 Col 1 | some colspan (note the double pipe) ||
+ | Row 3 Col 1 | Row 3 Col 2 | Row 3 Col 3 |
+
+To connect cells horizontally, just make the next cell completely empty as shown above. Be sure to have always the same amount of cell separators!
+
+Vertical tableheaders are possible, too.
+
+| ^ Heading 1 ^ Heading 2 ^
+^ Heading 3 | Row 1 Col 2 | Row 1 Col 3 |
+^ Heading 4 | no colspan this time | |
+^ Heading 5 | Row 2 Col 2 | Row 2 Col 3 |
+
+As you can see, it's the cell separator before a cell which decides about the formatting:
+
+ | ^ Heading 1 ^ Heading 2 ^
+ ^ Heading 3 | Row 1 Col 2 | Row 1 Col 3 |
+ ^ Heading 4 | no colspan this time | |
+ ^ Heading 5 | Row 2 Col 2 | Row 2 Col 3 |
+
+You can have rowspans (vertically connected cells) by adding '':::'' into the cells below the one to which they should connect.
+
+^ Heading 1 ^ Heading 2 ^ Heading 3 ^
+| Row 1 Col 1 | this cell spans vertically | Row 1 Col 3 |
+| Row 2 Col 1 | ::: | Row 2 Col 3 |
+| Row 3 Col 1 | ::: | Row 2 Col 3 |
+
+Apart from the rowspan syntax those cells should not contain anything else.
+
+ ^ Heading 1 ^ Heading 2 ^ Heading 3 ^
+ | Row 1 Col 1 | this cell spans vertically | Row 1 Col 3 |
+ | Row 2 Col 1 | ::: | Row 2 Col 3 |
+ | Row 3 Col 1 | ::: | Row 2 Col 3 |
+
+You can align the table contents, too. Just add at least two whitespaces at the opposite end of your text: Add two spaces on the left to align right, two spaces on the right to align left and two spaces at least at both ends for centered text.
+
+^ Table with alignment ^^^
+| right| center |left |
+|left | right| center |
+| xxxxxxxxxxxx | xxxxxxxxxxxx | xxxxxxxxxxxx |
+
+This is how it looks in the source:
+
+ ^ Table with alignment ^^^
+ | right| center |left |
+ |left | right| center |
+ | xxxxxxxxxxxx | xxxxxxxxxxxx | xxxxxxxxxxxx |
+
+Note: Vertical alignment is not supported.
+
+===== No Formatting =====
+
+If you need to display text exactly like it is typed (without any formatting), enclose the area either with ''%%<nowiki>%%'' tags or even simpler, with double percent signs ''<nowiki>%%</nowiki>''.
+
+<nowiki>
+This is some text which contains addresses like this: http://www.splitbrain.org and **formatting**, but nothing is done with it.
+</nowiki>
+The same is true for %%//__this__ text// with a smiley ;-)%%.
+
+ <nowiki>
+ This is some text which contains addresses like this: http://www.splitbrain.org and **formatting**, but nothing is done with it.
+ </nowiki>
+ The same is true for %%//__this__ text// with a smiley ;-)%%.
+
+===== Code Blocks =====
+
+You can include code blocks into your documents by either indenting them by at least two spaces (like used for the previous examples) or by using the tags ''%%<code>%%'' or ''%%<file>%%''.
+
+ This is text is indented by two spaces.
+
+<code>
+This is preformatted code all spaces are preserved: like <-this
+</code>
+
+<file>
+This is pretty much the same, but you could use it to show that you quoted a file.
+</file>
+
+Those blocks were created by this source:
+
+ This is text is indented by two spaces.
+
+ <code>
+ This is preformatted code all spaces are preserved: like <-this
+ </code>
+
+ <file>
+ This is pretty much the same, but you could use it to show that you quoted a file.
+ </file>
+
+==== Syntax Highlighting ====
+
+[[wiki:DokuWiki]] can highlight sourcecode, which makes it easier to read. It uses the [[http://qbnz.com/highlighter/|GeSHi]] Generic Syntax Highlighter -- so any language supported by GeSHi is supported. The syntax uses the same code and file blocks described in the previous section, but this time the name of the language syntax to be highlighted is included inside the tag, e.g. ''<nowiki><code java></nowiki>'' or ''<nowiki><file java></nowiki>''.
+
+<code java>
+/**
+ * The HelloWorldApp class implements an application that
+ * simply displays "Hello World!" to the standard output.
+ */
+class HelloWorldApp {
+ public static void main(String[] args) {
+ System.out.println("Hello World!"); //Display the string.
+ }
+}
+</code>
+
+The following language strings are currently recognized: //4cs, 6502acme, 6502kickass, 6502tasm, 68000devpac, abap, actionscript-french, actionscript, actionscript3, ada, algol68, apache, applescript, asm, asp, autoconf, autohotkey, autoit, avisynth, awk, bascomavr, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, c_loadrunner, c_mac, caddcl, cadlisp, cfdg, cfm, chaiscript, cil, clojure, cmake, cobol, coffeescript, cpp, cpp-qt, csharp, css, cuesheet, d, dcs, delphi, diff, div, dos, dot, e, epc, ecmascript, eiffel, email, erlang, euphoria, f1, falcon, fo, fortran, freebasic, fsharp, gambas, genero, genie, gdb, glsl, gml, gnuplot, go, groovy, gettext, gwbasic, haskell, hicest, hq9plus, html, html5, icon, idl, ini, inno, intercal, io, j, java5, java, javascript, jquery, kixtart, klonec, klonecpp, latex, lb, lisp, llvm, locobasic, logtalk, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, magiksf, make, mapbasic, matlab, mirc, modula2, modula3, mmix, mpasm, mxml, mysql, newlisp, nsis, oberon2, objc, objeck, ocaml-brief, ocaml, oobas, oracle8, oracle11, oxygene, oz, pascal, pcre, perl, perl6, per, pf, php-brief, php, pike, pic16, pixelbender, pli, plsql, postgresql, povray, powerbuilder, powershell, proftpd, progress, prolog, properties, providex, purebasic, pycon, python, q, qbasic, rails, rebol, reg, robots, rpmspec, rsplus, ruby, sas, scala, scheme, scilab, sdlbasic, smalltalk, smarty, sql, systemverilog, tcl, teraterm, text, thinbasic, tsql, typoscript, unicon, uscript, vala, vbnet, vb, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, winbatch, whois, xbasic, xml, xorg_conf, xpp, yaml, z80, zxbasic//
+
+==== Downloadable Code Blocks ====
+
+When you use the ''%%<code>%%'' or ''%%<file>%%'' syntax as above, you might want to make the shown code available for download as well. You can do this by specifying a file name after language code like this:
+
+<code>
+<file php myexample.php>
+<?php echo "hello world!"; ?>
+</file>
+</code>
+
+<file php myexample.php>
+<?php echo "hello world!"; ?>
+</file>
+
+If you don't want any highlighting but want a downloadable file, specify a dash (''-'') as the language code: ''%%<code - myfile.foo>%%''.
+
+
+===== Embedding HTML and PHP =====
+
+You can embed raw HTML or PHP code into your documents by using the ''%%<html>%%'' or ''%%<php>%%'' tags. (Use uppercase tags if you need to enclose block level elements.)
+
+HTML example:
+
+<code>
+<html>
+This is some <span style="color:red;font-size:150%;">inline HTML</span>
+</html>
+<HTML>
+<p style="border:2px dashed red;">And this is some block HTML</p>
+</HTML>
+</code>
+
+<html>
+This is some <span style="color:red;font-size:150%;">inline HTML</span>
+</html>
+<HTML>
+<p style="border:2px dashed red;">And this is some block HTML</p>
+</HTML>
+
+PHP example:
+
+<code>
+<php>
+echo 'A logo generated by PHP:';
+echo '<img src="' . $_SERVER['PHP_SELF'] . '?=' . php_logo_guid() . '" alt="PHP Logo !" />';
+echo '(generated inline HTML)';
+</php>
+<PHP>
+echo '<table class="inline"><tr><td>The same, but inside a block level element:</td>';
+echo '<td><img src="' . $_SERVER['PHP_SELF'] . '?=' . php_logo_guid() . '" alt="PHP Logo !" /></td>';
+echo '</tr></table>';
+</PHP>
+</code>
+
+<php>
+echo 'A logo generated by PHP:';
+echo '<img src="' . $_SERVER['PHP_SELF'] . '?=' . php_logo_guid() . '" alt="PHP Logo !" />';
+echo '(inline HTML)';
+</php>
+<PHP>
+echo '<table class="inline"><tr><td>The same, but inside a block level element:</td>';
+echo '<td><img src="' . $_SERVER['PHP_SELF'] . '?=' . php_logo_guid() . '" alt="PHP Logo !" /></td>';
+echo '</tr></table>';
+</PHP>
+
+**Please Note**: HTML and PHP embedding is disabled by default in the configuration. If disabled, the code is displayed instead of executed.
+
+===== RSS/ATOM Feed Aggregation =====
+[[DokuWiki]] can integrate data from external XML feeds. For parsing the XML feeds, [[http://simplepie.org/|SimplePie]] is used. All formats understood by SimplePie can be used in DokuWiki as well. You can influence the rendering by multiple additional space separated parameters:
+
+^ Parameter ^ Description ^
+| any number | will be used as maximum number items to show, defaults to 8 |
+| reverse | display the last items in the feed first |
+| author | show item authors names |
+| date | show item dates |
+| description| show the item description. If [[doku>config:htmlok|HTML]] is disabled all tags will be stripped |
+| //n//[dhm] | refresh period, where d=days, h=hours, m=minutes. (e.g. 12h = 12 hours). |
+
+The refresh period defaults to 4 hours. Any value below 10 minutes will be treated as 10 minutes. [[wiki:DokuWiki]] will generally try to supply a cached version of a page, obviously this is inappropriate when the page contains dynamic external content. The parameter tells [[wiki:DokuWiki]] to re-render the page if it is more than //refresh period// since the page was last rendered.
+
+**Example:**
+
+ {{rss>http://slashdot.org/index.rss 5 author date 1h }}
+
+{{rss>http://slashdot.org/index.rss 5 author date 1h }}
+
+
+===== Control Macros =====
+
+Some syntax influences how DokuWiki renders a page without creating any output it self. The following control macros are availble:
+
+^ Macro ^ Description |
+| %%~~NOTOC~~%% | If this macro is found on the page, no table of contents will be created |
+| %%~~NOCACHE~~%% | DokuWiki caches all output by default. Sometimes this might not be wanted (eg. when the %%<php>%% syntax above is used), adding this macro will force DokuWiki to rerender a page on every call |
+
+===== Syntax Plugins =====
+
+DokuWiki's syntax can be extended by [[doku>plugins|Plugins]]. How the installed plugins are used is described on their appropriate description pages. The following syntax plugins are available in this particular DokuWiki installation:
+
+~~INFO:syntaxplugins~~
diff --git a/platform/www/lib/plugins/farmer/_animal/data/tmp/_dummy b/platform/www/lib/plugins/farmer/_animal/data/tmp/_dummy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_animal/data/tmp/_dummy
diff --git a/platform/www/lib/plugins/farmer/_test/core.test.php b/platform/www/lib/plugins/farmer/_test/core.test.php
new file mode 100644
index 0000000..d6a1dab
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_test/core.test.php
@@ -0,0 +1,40 @@
+<?php
+namespace plugin\struct\test;
+
+require_once(__DIR__ . '/../DokuWikiFarmCore.php');
+
+class DokuWikiFarmCore extends \DokuWikiFarmCore {
+ public function getAnimalNamesForHost($host) {
+ return parent::getAnimalNamesForHost($host);
+ }
+}
+
+
+/**
+ * @group plugin_farmer
+ * @group plugins
+ */
+class core_plugin_farmer_test extends \DokuWikiTest {
+
+ protected $pluginsEnabled = array('farmer');
+
+
+ public function test_hostsAnimals() {
+ $core = new DokuWikiFarmCore();
+
+ $input = 'www.foobar.example.com:8000';
+ $expect = array(
+ 'www.foobar.example.com.8000',
+ 'foobar.example.com.8000',
+ 'www.foobar.example.com',
+ 'foobar.example.com',
+ 'www.foobar.example',
+ 'foobar.example',
+ 'www.foobar',
+ 'foobar',
+ 'www',
+ );
+
+ $this->assertEquals($expect, $core->getAnimalNamesForHost($input));
+ }
+}
diff --git a/platform/www/lib/plugins/farmer/_test/general.test.php b/platform/www/lib/plugins/farmer/_test/general.test.php
new file mode 100644
index 0000000..af45139
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_test/general.test.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * General tests for the farmer plugin
+ *
+ * @group plugin_farmer
+ * @group plugins
+ */
+class general_plugin_farmer_test extends DokuWikiTest {
+
+ protected $pluginsEnabled = array('farmer');
+
+ /**
+ * Simple test to make sure the plugin.info.txt is in correct format
+ */
+ public function test_plugininfo() {
+ $file = __DIR__ . '/../plugin.info.txt';
+ $this->assertFileExists($file);
+
+ $info = confToHash($file);
+
+ $this->assertArrayHasKey('base', $info);
+ $this->assertArrayHasKey('author', $info);
+ $this->assertArrayHasKey('email', $info);
+ $this->assertArrayHasKey('date', $info);
+ $this->assertArrayHasKey('name', $info);
+ $this->assertArrayHasKey('desc', $info);
+ $this->assertArrayHasKey('url', $info);
+
+ $this->assertEquals('farmer', $info['base']);
+ $this->assertRegExp('/^https?:\/\//', $info['url']);
+ $this->assertTrue(mail_isvalid($info['email']));
+ $this->assertRegExp('/^\d\d\d\d-\d\d-\d\d$/', $info['date']);
+ $this->assertTrue(false !== strtotime($info['date']));
+ }
+}
diff --git a/platform/www/lib/plugins/farmer/_test/getUserLine.test.php b/platform/www/lib/plugins/farmer/_test/getUserLine.test.php
new file mode 100644
index 0000000..8f228cb
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_test/getUserLine.test.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace plugin\struct\test;
+
+class admin_plugin_farmer_new extends \admin_plugin_farmer_new {
+ public function getAdminLine() {
+ return parent::getAdminLine();
+ }
+
+}
+
+
+/**
+ * Tests for the validation functionality of the farmer plugin
+ *
+ * @group plugin_farmer
+ * @group plugins
+ */
+class getUserLine_plugin_farmer_test extends \DokuWikiTest {
+
+ protected $pluginsEnabled = array('farmer',);
+ private $usersfile;
+
+ public function setUp() {
+ parent::setUp();
+ $this->usersfile = DOKU_CONF . 'users.auth.php';
+ copy($this->usersfile, $this->usersfile . "org");
+ unlink($this->usersfile);
+ }
+
+ public function tearDown() {
+ parent::tearDown();
+ unlink($this->usersfile);
+ copy($this->usersfile . "org", $this->usersfile);
+ unlink($this->usersfile . "org");
+ }
+
+
+ public function test_getUserLine_oneUser () {
+ $helper = new admin_plugin_farmer_new();
+ $usersfileData = "# users.auth.php
+# <?php exit()?>
+# Don't modify the lines above
+#
+# Userfile
+#
+# Format:
+#
+# user:MD5password:Real Name:email:groups,comma,seperated
+#
+# testuser : testpass
+testuser:179ad45c6ce2cb97cf1029e212046e81:Arthur Dent:arthur@example.com:\n";
+ file_put_contents($this->usersfile,$usersfileData);
+
+ $_SERVER['REMOTE_USER'] = 'testuser';
+ $expected_result = 'testuser:179ad45c6ce2cb97cf1029e212046e81:Arthur Dent:arthur@example.com:' . "\n";
+ $actual_result = $helper->getAdminLine();
+
+ $this->assertSame($expected_result, $actual_result);
+ }
+
+ public function test_getUserLine_manyUser () {
+ $helper = new admin_plugin_farmer_new();
+ $usersfileData = "# users.auth.php
+# <?php exit()?>
+# Don't modify the lines above
+#
+# Userfile
+#
+# Format:
+#
+# user:MD5password:Real Name:email:groups,comma,seperated
+#
+# testuser : testpass
+1testuser:179ad45c6ce43897cf1029e212046e81:Arthur Dent:brthur@example.com:admin
+testuser:179ad45c6ce2cb97cf1029e212046e81:Arthur Dent:arthur@example.com:
+2testuser:179ad45c6ce2cb97cf10214712046e81:Arthur inDent:crthur@example.com:admin\n";
+ file_put_contents($this->usersfile,$usersfileData);
+
+ $_SERVER['REMOTE_USER'] = 'testuser';
+ $expected_result = 'testuser:179ad45c6ce2cb97cf1029e212046e81:Arthur Dent:arthur@example.com:' . "\n";
+ $actual_result = $helper->getAdminLine();
+
+ $this->assertSame($expected_result, $actual_result);
+ }
+}
diff --git a/platform/www/lib/plugins/farmer/_test/helper.test.php b/platform/www/lib/plugins/farmer/_test/helper.test.php
new file mode 100644
index 0000000..3fc689b
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/_test/helper.test.php
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * Tests for the validation functionality of the farmer plugin
+ *
+ * @group plugin_farmer
+ * @group plugins
+ */
+class helper_plugin_farmer_test extends DokuWikiTest {
+
+ protected $pluginsEnabled = array('farmer',);
+
+ public function validationProvider() {
+ return array(
+ array('ant', true),
+ array('ant.lion', true),
+ array('ant.lion.cow', true),
+ array('ant-lion', true),
+ array('ant-lion.cow', true),
+ array('4ant', true),
+ array('ant4', true),
+ array('ant44lion', true),
+ array('44', true),
+
+ array('ant.', false),
+ array('.ant', false),
+ array('ant-', false),
+ array('-ant', false),
+ array('ant--lion', false),
+ array('ant..lion', false),
+ array('ant.-lion', false),
+ array('ant/lion', false),
+ array('!ant', false),
+ array('ant lion', false),
+ );
+ }
+
+ /**
+ * @dataProvider validationProvider
+ * @param $input
+ * @param $expect
+ */
+ public function test_validateAnimalName($input, $expect) {
+ /** @var helper_plugin_farmer $helper */
+ $helper = plugin_load('helper', 'farmer');
+ $this->assertEquals($expect, $helper->validateAnimalName($input));
+ }
+
+ public function test_isInPath() {
+ /** @var helper_plugin_farmer $helper */
+ $helper = plugin_load('helper', 'farmer');
+
+ $this->assertTrue($helper->isInPath('/var/www/foo', '/var/www'));
+ $this->assertFalse($helper->isInPath('/var/www/../foo', '/var/www'));
+
+ // same dir should return false, too
+ $this->assertFalse($helper->isInPath('/var/www/foo', '/var/www/foo'));
+ $this->assertFalse($helper->isInPath('/var/www/foo/', '/var/www/foo'));
+ $this->assertFalse($helper->isInPath('/var/www/foo/bar/../', '/var/www/foo'));
+
+ // https://github.com/cosmocode/dokuwiki-plugin-farmer/issues/30
+ $this->assertFalse($helper->isInPath('/var/lib/dokuwiki.animals', '/var/lib/dokuwiki'));
+ }
+}
diff --git a/platform/www/lib/plugins/farmer/action/ajax.php b/platform/www/lib/plugins/farmer/action/ajax.php
new file mode 100644
index 0000000..ac20eae
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/action/ajax.php
@@ -0,0 +1,267 @@
+<?php
+/**
+ * DokuWiki Plugin farmer (Action Component)
+ *
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Michael Große <grosse@cosmocode.de>
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+
+if(!defined('DOKU_INC')) die();
+
+/**
+ * Manage AJAX features
+ */
+class action_plugin_farmer_ajax extends DokuWiki_Action_Plugin {
+
+ /**
+ * plugin should use this method to register its handlers with the DokuWiki's event controller
+ *
+ * @param Doku_Event_Handler $controller DokuWiki's event controller object. Also available as global $EVENT_HANDLER
+ *
+ */
+ public function register(Doku_Event_Handler $controller) {
+ $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, '_ajax_call');
+ }
+
+ /**
+ * handle ajax requests
+ *
+ * @param Doku_Event $event
+ * @param $param
+ */
+ public function _ajax_call(Doku_Event $event, $param) {
+ if(substr($event->data, 0, 13) !== 'plugin_farmer') {
+ return;
+ }
+ //no other ajax call handlers needed
+ $event->stopPropagation();
+ $event->preventDefault();
+
+ if(!auth_isadmin()) die('Only admins allowed');
+
+ if(substr($event->data, 14) === 'getPluginMatrix') {
+ $this->get_plugin_matrix($event, $param);
+ return;
+ }
+ if(substr($event->data, 14) === 'modPlugin') {
+ $this->plugin_mod($event, $param);
+ return;
+ }
+ if(substr($event->data, 14, 10) === 'getPlugins') {
+ $this->get_animal_plugins($event, $param);
+ return;
+ }
+ if(substr($event->data, 14, 10) === 'checkSetup') {
+ $this->check_setup($event, $param);
+ }
+ }
+
+ /**
+ * This function exists in order to provide a positive (i.e. 200) response to an ajax request to a non-existing animal.
+ *
+ * @param Doku_Event $event
+ * @param $param
+ */
+ public function check_setup(Doku_Event $event, $param) {
+ $data = '';
+ $json = new JSON();
+ header('Content-Type: application/json');
+ echo $json->encode($data);
+ }
+
+ public function plugin_mod(Doku_Event $event, $param) {
+ global $INPUT;
+
+ /** @var helper_plugin_farmer $helper */
+ $helper = plugin_load('helper', 'farmer');
+
+ $pname = $INPUT->str('plugin');
+ $animal = $INPUT->str('ani');
+
+
+ $plugins = $helper->getAnimalPluginRealState($animal);
+ if(!isset($plugins[$pname])) die('no such plugin');
+ $plugin = $plugins[$pname];
+
+ // figure out what to toggle to
+ if($plugin['isdefault']) {
+ $new = (int) !$plugin['actual'];
+ } else {
+ $new = -1;
+ }
+ $helper->setPluginState($pname, $animal, $new);
+
+ // show new state
+ $plugins = $helper->getAnimalPluginRealState($animal);
+ $plugin = $plugins[$pname];
+ header('Content-Type: text/html; charset=utf-8');
+ echo $this->plugin_matrix_cell($plugin, $animal);
+ }
+
+ /**
+ * Create a matrix of all animals and plugin states
+ *
+ * @param Doku_Event $event
+ * @param $param
+ */
+ public function get_plugin_matrix(Doku_Event $event, $param) {
+ /** @var helper_plugin_farmer $helper */
+ $helper = plugin_load('helper', 'farmer');
+
+ $animals = $helper->getAllAnimals();
+ $plugins = $helper->getAnimalPluginRealState($animals[0]);
+
+ header('Content-Type: text/html; charset=utf-8');
+
+ echo '<div class="table pluginmatrix">';
+ echo '<table>';
+ echo '<thead>';
+ echo '<tr>';
+ echo '<th></th>';
+ foreach($plugins as $plugin) {
+ echo '<th><div>' . hsc($plugin['name']) . '</div></th>';
+ }
+ echo '</tr>';
+ echo '</thead>';
+
+ echo '<tbody>';
+
+ echo '<tr>';
+ echo '<th>Default</th>';
+ foreach($plugins as $plugin) {
+ echo $this->plugin_matrix_cell($plugin, $this->getLang('plugin_default'), true);
+ }
+ echo '</tr>';
+
+ foreach($animals as $animal) {
+ $plugins = $helper->getAnimalPluginRealState($animal);
+ echo '<tr>';
+ echo '<th>' . hsc($animal) . '</th>';
+ foreach($plugins as $plugin) {
+ echo $this->plugin_matrix_cell($plugin, $animal);
+ }
+ echo '</tr>';
+ }
+ echo '</tbody>';
+ echo '</table>';
+ echo '</div>';
+ }
+
+ /**
+ * create a single cell in the matrix
+ *
+ * @param array $plugin
+ * @param string $animal
+ * @param bool $defaults show the defaults
+ * @return string
+ */
+ protected function plugin_matrix_cell($plugin, $animal, $defaults=false) {
+ if($defaults) {
+ $current = $plugin['default'];
+ $isdefault = true;
+ $td = 'th';
+ } else {
+ $current = $plugin['actual'];
+ $isdefault = $plugin['isdefault'];
+ $td = 'td';
+ }
+
+ if($current) {
+ $class = 'on';
+ $lbl = '✓';
+ } else {
+ $class = 'off';
+ $lbl = '✗';
+ }
+ if($isdefault) $class .= ' default';
+
+
+ $attrs = array(
+ 'class' => $class,
+ 'title' => $animal . ': ' . $plugin['name'],
+ 'data-animal' => $animal,
+ 'data-plugin' => $plugin['name']
+ );
+ $attr = buildAttributes($attrs);
+
+ return "<$td $attr>$lbl</$td>";
+ }
+
+ /**
+ * @param Doku_Event $event
+ * @param $param
+ */
+ public function get_animal_plugins(Doku_Event $event, $param) {
+ $animal = substr($event->data, 25);
+ /** @var helper_plugin_farmer $helper */
+ $helper = plugin_load('helper', 'farmer');
+
+ $plugins = $helper->getAnimalPluginRealState($animal);
+
+ header('Content-Type: text/html; charset=utf-8');
+
+ echo '<table>';
+ echo '<tr>';
+ echo '<th>' . $this->getLang('plugin') . '</th>';
+ echo '<th>' . $this->getLang('plugin_default') . '</th>';
+ echo '<th>' . $this->getLang('plugin_enabled') . '</th>';
+ echo '<th>' . $this->getLang('plugin_disabled') . '</th>';
+ echo '</tr>';
+
+ foreach($plugins as $plugin) {
+ echo '<tr>';
+ echo '<th>' . hsc($plugin['name']) . '</th>';
+
+ echo '<td>';
+ $attr = array();
+ $attr['type'] = 'radio';
+ $attr['name'] = 'bulk_plugins[' . $plugin['name'] . ']';
+ $attr['value'] = '-1';
+ if($plugin['isdefault']) {
+ $attr['checked'] = 'checked';
+ }
+ echo '<label>';
+ echo '<input ' . buildAttributes($attr) . ' />';
+ if($plugin['default']) {
+ echo ' (' . $this->getLang('plugin_on') . ')';
+ } else {
+ echo ' (' . $this->getLang('plugin_off') . ')';
+ }
+ echo '</label>';
+ echo '</td>';
+
+ echo '<td>';
+ $attr = array();
+ $attr['type'] = 'radio';
+ $attr['name'] = 'bulk_plugins[' . $plugin['name'] . ']';
+ $attr['value'] = '1';
+ if(!$plugin['isdefault'] && $plugin['actual']) {
+ $attr['checked'] = 'checked';
+ }
+ echo '<label>';
+ echo '<input ' . buildAttributes($attr) . ' />';
+ echo ' ' . $this->getLang('plugin_on');
+ echo '</label>';
+ echo '</td>';
+
+ echo '<td>';
+ $attr = array();
+ $attr['type'] = 'radio';
+ $attr['name'] = 'bulk_plugins[' . $plugin['name'] . ']';
+ $attr['value'] = '0';
+ if(!$plugin['isdefault'] && !$plugin['actual']) {
+ $attr['checked'] = 'checked';
+ }
+ echo '<label>';
+ echo '<input ' . buildAttributes($attr) . ' />';
+ echo ' ' . $this->getLang('plugin_off');
+ echo '</label>';
+ echo '</td>';
+
+ echo '</tr>';
+ }
+ }
+
+}
+
diff --git a/platform/www/lib/plugins/farmer/action/disable.php b/platform/www/lib/plugins/farmer/action/disable.php
new file mode 100644
index 0000000..bf0c48a
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/action/disable.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * DokuWiki Plugin farmer (Action Component)
+ *
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Michael Große <grosse@cosmocode.de>
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+
+if(!defined('DOKU_INC')) die();
+
+/**
+ * Disable Plugins on install
+ */
+class action_plugin_farmer_disable extends DokuWiki_Action_Plugin {
+
+ /**
+ * plugin should use this method to register its handlers with the DokuWiki's event controller
+ *
+ * @param Doku_Event_Handler $controller DokuWiki's event controller object. Also available as global $EVENT_HANDLER
+ *
+ */
+ public function register(Doku_Event_Handler $controller) {
+ /** @var helper_plugin_farmer $farmer */
+ $farmer = plugin_load('helper', 'farmer');
+ if($farmer->getAnimal()) return;
+
+ if($this->getConf('disable_new_plugins')) {
+ $controller->register_hook('PLUGIN_EXTENSION_CHANGE', 'AFTER', $this, 'handle_install');
+ }
+ }
+
+ /**
+ * handle install of new plugin
+ *
+ * @param Doku_Event $event
+ * @param $param
+ */
+ public function handle_install(Doku_Event $event, $param) {
+ if($event->data['action'] != 'install') return;
+
+ /* @var Doku_Plugin_Controller $plugin_controller */
+ global $plugin_controller;
+ $plugin_controller = new Doku_Plugin_Controller(); // we need to refresh the status
+
+ /** @var helper_plugin_extension_extension $ext */
+ $ext = $event->data['extension'];
+ $disabled = $ext->disable();
+ if($disabled === true) {
+ msg($this->getLang('disable_new_plugins'));
+ } else {
+ msg(hsc($disabled), -1);
+ }
+ }
+}
+
diff --git a/platform/www/lib/plugins/farmer/action/startup.php b/platform/www/lib/plugins/farmer/action/startup.php
new file mode 100644
index 0000000..4b9d38e
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/action/startup.php
@@ -0,0 +1,90 @@
+<?php
+/**
+ * DokuWiki Plugin farmer (Action Component)
+ *
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Michael Große <grosse@cosmocode.de>
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+
+if(!defined('DOKU_INC')) die();
+
+/**
+ * Handles Farm mechanisms on DokuWiki startup
+ */
+class action_plugin_farmer_startup extends DokuWiki_Action_Plugin {
+
+ /** @var helper_plugin_farmer */
+ protected $helper;
+
+ /**
+ * action_plugin_farmer_startup constructor.
+ */
+ public function __construct() {
+ $this->helper = plugin_load('helper', 'farmer');
+ }
+
+ /**
+ * plugin should use this method to register its handlers with the DokuWiki's event controller
+ *
+ * @param Doku_Event_Handler $controller DokuWiki's event controller object. Also available as global $EVENT_HANDLER
+ *
+ */
+ public function register(Doku_Event_Handler $controller) {
+ $controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'before_start');
+ }
+
+ public function before_start(Doku_Event $event, $param) {
+ if($this->helper->wasNotfound()) $this->handleNotFound();
+ }
+
+ /**
+ * Handles the animal not found case
+ *
+ * Will abort the current script unless the farmer is wanted
+ */
+ protected function handleNotFound() {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ global $conf, $lang;
+ $config = $this->helper->getConfig();
+ $show = $config['notfound']['show'];
+ $url = $config['notfound']['url'];
+ if($show == 'farmer') return;
+
+ if($show == '404' || $show == 'list') {
+ http_status(404);
+ $body = $this->locale_xhtml('notfound_' . $show);
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $title = '404';
+ if($show == 'list') {
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $body .= $this->animalList();
+ }
+
+ include __DIR__ . '/../includes/template.php';
+ exit;
+ }
+
+ if($show == 'redirect' && $url) {
+ send_redirect($url);
+ }
+ }
+
+ /**
+ * Retrun a HTML list of animals
+ *
+ * @return string
+ */
+ protected function animalList() {
+ $html = '<ul>';
+ $animals = $this->helper->getAllAnimals();
+ foreach($animals as $animal) {
+ $link = $this->helper->getAnimalURL($animal);
+ $html .= '<li><div class="li"><a href="' . $link . '">' . hsc($animal) . '</a></div></li>';
+ }
+ $html .= '</ul>';
+ return $html;
+ }
+
+}
+
diff --git a/platform/www/lib/plugins/farmer/admin.php b/platform/www/lib/plugins/farmer/admin.php
new file mode 100644
index 0000000..6f00039
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/admin.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * DokuWiki Plugin farmer (Admin Component)
+ *
+ * This is the main admin page. It displays the tabs and then loads the sub components
+ * according to the selected tab
+ *
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Michael Große <grosse@cosmocode.de>
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+class admin_plugin_farmer extends DokuWiki_Admin_Plugin {
+
+ /** @var helper_plugin_farmer */
+ protected $helper;
+ /** @var array The available pages for the current user in the current wiki */
+ protected $pages;
+ /** @var string The currently selected page */
+ protected $page;
+ /** @var DokuWiki_Admin_Plugin the plugin to use for the current page */
+ protected $adminplugin;
+
+ /**
+ * @return bool we're available for managers and admins
+ */
+ public function forAdminOnly() {
+ return false;
+ }
+
+ /**
+ * Initialize current page
+ */
+ public function __construct() {
+ global $INPUT;
+ $this->helper = plugin_load('helper', 'farmer');
+
+ // set available pages depending on user and animal
+ $isanimal = (bool) $this->helper->getAnimal();
+ if($isanimal || !auth_isadmin()) {
+ $this->pages = array(
+ 'info'
+ );
+ } else {
+ if(!$this->helper->checkFarmSetup()) {
+ $this->pages = array(
+ 'setup'
+ );
+ } else {
+ $this->pages = array(
+ 'info',
+ 'config',
+ 'new',
+ 'plugins',
+ 'delete'
+ );
+ }
+ }
+
+ // make sure current page requested is available
+ $this->page = $INPUT->str('sub');
+ if(!in_array($this->page, $this->pages)) {
+ $this->page = $this->pages[0];
+ }
+
+ // load the sub component
+ $this->adminplugin = plugin_load('admin', 'farmer_' . $this->page);
+ if(!$this->adminplugin) nice_die('Something went wrong loading the plugin component for ' . hsc($this->page));
+ }
+
+ /**
+ * handle user request
+ */
+ public function handle() {
+ $this->adminplugin->handle();
+ }
+
+ /**
+ * output appropriate tab
+ */
+ public function html() {
+ global $ID;
+
+ echo '<div id="plugin__farmer_admin">';
+ echo '<h1>' . $this->getLang('menu') . '</h1>';
+
+ echo '<ul class="tabs" id="plugin__farmer_tabs">';
+ foreach($this->pages as $page) {
+ $link = wl($ID, array('do' => 'admin', 'page' => 'farmer', 'sub' => $page));
+ $class = ($page == $this->page) ? 'active' : '';
+
+ echo '<li class="' . $class . '"><a href="' . $link . '">' . $this->getLang('tab_' . $page) . '</a></li>';
+ }
+ echo '</ul>';
+ echo '<div class="panelHeader">';
+ echo $this->locale_xhtml('tab_' . $this->page);
+ echo '</div>';
+ echo '<div class="panelMain">';
+ $this->adminplugin->html();
+ echo '</div>';
+ echo '<div class="panelFooter">';
+ echo $this->locale_xhtml('tab_' . $this->page . '_help');
+ echo '</div>';
+ echo '</div>';
+ }
+
+ /**
+ * @return int
+ */
+ public function getMenuSort() {
+ return 42;
+ }
+
+}
+
diff --git a/platform/www/lib/plugins/farmer/admin.svg b/platform/www/lib/plugins/farmer/admin.svg
new file mode 100644
index 0000000..e774207
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/admin.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10.5 18a.5.5 0 0 1 .5.5.5.5 0 0 1-.5.5.5.5 0 0 1-.5-.5.5.5 0 0 1 .5-.5m3 0a.5.5 0 0 1 .5.5.5.5 0 0 1-.5.5.5.5 0 0 1-.5-.5.5.5 0 0 1 .5-.5M10 11a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m4 0a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m4 7c0 2.21-2.69 4-6 4s-6-1.79-6-4c0-.9.45-1.73 1.2-2.4-.75-1-1.2-2.25-1.2-3.6l.12-1.22c-.54.15-1.19.15-1.72 0-1.02-.28-2.56-1.43-2.33-2.23.23-.8 2.14-.95 3.16-.65.59.17 1.22.6 1.59 1.06l.57-.81C6.79 7.05 7 4 10 3l-.09.14c-.28.44-1 1.83-.24 3.33a6.02 6.02 0 0 1 4.66 0c.76-1.5.04-2.89-.24-3.33L14 3c3 1 3.21 4.05 2.61 5.15l.57.81c.37-.46 1-.89 1.59-1.06 1.02-.3 2.93-.15 3.16.65.23.8-1.31 1.95-2.33 2.23-.53.15-1.18.15-1.72 0L18 12c0 1.35-.45 2.6-1.2 3.6.75.67 1.2 1.5 1.2 2.4m-6-2c-2.21 0-4 .9-4 2s1.79 2 4 2 4-.9 4-2-1.79-2-4-2m0-2c1.12 0 2.17.21 3.07.56.58-.69.93-1.56.93-2.56a4 4 0 0 0-4-4 4 4 0 0 0-4 4c0 1 .35 1.87.93 2.56.9-.35 1.95-.56 3.07-.56m2.09-10.86z"/></svg> \ No newline at end of file
diff --git a/platform/www/lib/plugins/farmer/admin/config.php b/platform/www/lib/plugins/farmer/admin/config.php
new file mode 100644
index 0000000..7d79970
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/admin/config.php
@@ -0,0 +1,126 @@
+<?php
+/**
+ * DokuWiki Plugin farmer (Admin Component)
+ *
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Michael Große <grosse@cosmocode.de>
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+use dokuwiki\Form\Form;
+
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+/**
+ * Configuration Interface for farm.ini
+ */
+class admin_plugin_farmer_config extends DokuWiki_Admin_Plugin {
+
+ /** @var helper_plugin_farmer */
+ protected $helper;
+
+ /**
+ * @return bool admin only!
+ */
+ public function forAdminOnly() {
+ return false;
+ }
+
+ /**
+ * admin_plugin_farmer_config constructor.
+ */
+ public function __construct() {
+ $this->helper = plugin_load('helper', 'farmer');
+ }
+
+ /**
+ * Should carry out any processing required by the plugin.
+ */
+ public function handle() {
+ global $INPUT;
+ global $ID;
+ if(!$INPUT->has('farmconf')) return;
+ if(!checkSecurityToken()) return;
+
+ $farmconf = $this->helper->getConfig();
+ $farmdir = $farmconf['base']['farmdir'];
+ $farmconf = array_merge($farmconf, $INPUT->arr('farmconf'));
+ $farmconf['base']['farmdir'] = $farmdir;
+
+ $farmconf['base']['basedomain'] = trim(trim($farmconf['base']['basedomain'], '.'));
+
+ $ini = DOKU_INC . 'conf/farm.ini';
+ $data = "; Farm config created by the farmer plugin\n";
+ $data .= $this->createIni($farmconf);
+ io_saveFile($ini, $data);
+
+ $self = wl($ID, array('do' => 'admin', 'page' => 'farmer', 'sub' => 'config'), true, '&');
+ send_redirect($self);
+ }
+
+ /**
+ * Render HTML output, e.g. helpful text and a form
+ */
+ public function html() {
+ $farmconf = $this->helper->getConfig();
+
+ $form = new Form(array('method' => 'post'));
+
+ $form->addFieldsetOpen($this->getLang('base'));
+ $form->addHTML('<label><span>' . $this->getLang('farm dir') . '</span>' . DOKU_FARMDIR);
+ $form->addTextInput('farmconf[base][farmhost]', $this->getLang('farm host'))->val($farmconf['base']['farmhost']);
+ $form->addTextInput('farmconf[base][basedomain]', $this->getLang('base domain'))->val($farmconf['base']['basedomain']);
+ $form->addFieldsetClose();
+
+ $form->addFieldsetOpen($this->getLang('conf_inherit'));
+ foreach($farmconf['inherit'] as $key => $val) {
+ $form->setHiddenField("farmconf[inherit][$key]", 0);
+ $chk = $form->addCheckbox("farmconf[inherit][$key]", $this->getLang('conf_inherit_' . $key))->useInput(false);
+ if($val) $chk->attr('checked', 'checked');
+ }
+ $form->addFieldsetClose();
+
+ $options = array(
+ 'farmer' => $this->getLang('conf_notfound_farmer'),
+ '404' => $this->getLang('conf_notfound_404'),
+ 'list' => $this->getLang('conf_notfound_list'),
+ 'redirect' => $this->getLang('conf_notfound_redirect')
+ );
+
+ $form->addFieldsetOpen($this->getLang('conf_notfound'));
+ $form->addDropdown('farmconf[notfound][show]', $options, $this->getLang('conf_notfound'))->val($farmconf['notfound']['show']);
+ $form->addTextInput('farmconf[notfound][url]', $this->getLang('conf_notfound_url'))->val($farmconf['notfound']['url']);
+ $form->addFieldsetClose();
+
+ $form->addButton('save', $this->getLang('save'));
+ echo $form->toHTML();
+ }
+
+ /**
+ * Simple function to create an ini file
+ *
+ * Does no escaping, but should suffice for our use case
+ *
+ * @link http://stackoverflow.com/a/5695202/172068
+ * @param array $data The data to transform
+ * @return string
+ */
+ public function createIni($data) {
+ $res = array();
+ foreach($data as $key => $val) {
+ if(is_array($val)) {
+ $res[] = '';
+ $res[] = "[$key]";
+ foreach($val as $skey => $sval) {
+ $res[] = "$skey = " . (is_numeric($sval) ? $sval : '"' . $sval . '"');
+ }
+ } else {
+ $res[] = "$key = " . (is_numeric($val) ? $val : '"' . $val . '"');
+ }
+ }
+ $res[] = '';
+ return join("\n", $res);
+ }
+}
+
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/farmer/admin/delete.php b/platform/www/lib/plugins/farmer/admin/delete.php
new file mode 100644
index 0000000..d8b3450
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/admin/delete.php
@@ -0,0 +1,95 @@
+<?php
+/**
+ * DokuWiki Plugin farmer (Admin Component)
+ *
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Michael Große <grosse@cosmocode.de>
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+
+// must be run within Dokuwiki
+use dokuwiki\Form\Form;
+
+if(!defined('DOKU_INC')) die();
+
+/**
+ * Information about the farm and the current instance
+ */
+class admin_plugin_farmer_delete extends DokuWiki_Admin_Plugin {
+
+ /** @var helper_plugin_farmer */
+ protected $helper;
+
+ /**
+ * admin_plugin_farmer_info constructor.
+ */
+ public function __construct() {
+ $this->helper = plugin_load('helper', 'farmer');
+ }
+
+ /**
+ * @return bool admin only!
+ */
+ public function forAdminOnly() {
+ return true;
+ }
+
+ /**
+ * Should carry out any processing required by the plugin.
+ */
+ public function handle() {
+ global $INPUT;
+ global $ID;
+ if(!$INPUT->has('delete')) return;
+
+ if($INPUT->filter('trim')->str('delanimal') === '') {
+ msg($this->getLang('delete_noanimal'), -1);
+ return;
+ }
+
+ if($INPUT->str('delanimal') != $INPUT->str('confirm')) {
+ msg($this->getLang('delete_mismatch'), -1);
+ return;
+ }
+
+ $animaldir = DOKU_FARMDIR . $INPUT->str('delanimal');
+
+ if(!$this->helper->isInPath($animaldir, DOKU_FARMDIR) || !is_dir($animaldir)) {
+ msg($this->getLang('delete_invalid'), -1);
+ return;
+ }
+
+ // let's delete it
+ $ok = io_rmdir($animaldir, true);
+ if($ok) {
+ msg($this->getLang('delete_success'), 1);
+ } else {
+ msg($this->getLang('delete_fail'), -1);
+ }
+
+ $link = wl($ID, array('do'=>'admin', 'page'=>'farmer', 'sub' => 'delete'), true, '&');
+ send_redirect($link);
+ }
+
+ /**
+ * Render HTML output, e.g. helpful text and a form
+ */
+ public function html() {
+
+ $form = new Form();
+ $form->addFieldsetOpen($this->getLang('delete_animal'));
+
+ $animals = $this->helper->getAllAnimals();
+ array_unshift($animals, '');
+ $form->addDropdown('delanimal', $animals)->addClass('farmer_chosen_animals');
+ $form->addTextInput('confirm', $this->getLang('delete_confirm'));
+ $form->addButton('delete', $this->getLang('delete'));
+ $form->addFieldsetClose();
+ echo $form->toHTML();
+
+ }
+
+
+}
+
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/farmer/admin/info.php b/platform/www/lib/plugins/farmer/admin/info.php
new file mode 100644
index 0000000..3bf2938
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/admin/info.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * DokuWiki Plugin farmer (Admin Component)
+ *
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Michael Große <grosse@cosmocode.de>
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+/**
+ * Information about the farm and the current instance
+ */
+class admin_plugin_farmer_info extends DokuWiki_Admin_Plugin {
+
+ /** @var helper_plugin_farmer */
+ protected $helper;
+
+ /**
+ * admin_plugin_farmer_info constructor.
+ */
+ public function __construct() {
+ $this->helper = plugin_load('helper', 'farmer');
+ }
+
+ /**
+ * @return bool admin only!
+ */
+ public function forAdminOnly() {
+ return false;
+ }
+
+ /**
+ * Should carry out any processing required by the plugin.
+ */
+ public function handle() {
+ }
+
+ /**
+ * Render HTML output, e.g. helpful text and a form
+ */
+ public function html() {
+ global $conf;
+ global $INPUT;
+
+ $animal = $this->helper->getAnimal();
+ $config = $this->helper->getConfig();
+
+ echo '<table class="inline">';
+
+ $this->line('thisis', $animal ? $this->getLang('thisis.animal') : $this->getLang('thisis.farmer'));
+ if($animal) {
+ $this->line('animal', $animal);
+ }
+ $this->line('confdir', fullpath(DOKU_CONF) . '/');
+ $this->line('savedir', fullpath($conf['savedir']) . '/');
+ $this->line('baseinstall', DOKU_INC);
+ $this->line('farm host', $config['base']['farmhost']);
+ $this->line('farm dir', DOKU_FARMDIR);
+
+ $this->line('animals', $this->animals($INPUT->bool('list')));
+
+ foreach($config['inherit'] as $key => $value) {
+ $this->line('conf_inherit_' . $key, $this->getLang($value ? 'conf_inherit_yes' : 'conf_inherit_no'));
+ }
+
+ $this->line('plugins', join(', ', $this->helper->getAllPlugins(false)));
+
+ echo '</table>';
+ }
+
+ /**
+ * List or count the animals
+ *
+ * @param bool $list
+ * @return string
+ */
+ protected function animals($list) {
+ global $ID;
+
+ $animals = $this->helper->getAllAnimals();
+ $html = '';
+ if(!$list) {
+ $html = count($animals);
+ $self = wl($ID, array('do' => 'admin', 'page' => 'farmer', 'sub' => 'info', 'list' => 1));
+ $html .= ' [<a href="' . $self . '">' . $this->getLang('conf_notfound_list') . '</a>]';
+ return $html;
+ }
+
+ $html .= '<ol>';
+ foreach($animals as $animal) {
+ $link = $this->helper->getAnimalURL($animal);
+ $html .= '<li><div class="li"><a href="' . $link . '">' . $animal . '</a></div></li>';
+ }
+ $html .= '</ol>';
+ return $html;
+ }
+
+ /**
+ * Output a table line
+ *
+ * @param string $langkey
+ * @param string $value
+ */
+ protected function line($langkey, $value) {
+ echo '<tr>';
+ echo '<th>' . $this->getLang($langkey) . '</th>';
+ echo '<td>' . $value . '</td>';
+ echo '</tr>';
+ }
+
+}
+
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/farmer/admin/new.php b/platform/www/lib/plugins/farmer/admin/new.php
new file mode 100644
index 0000000..8cbf94f
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/admin/new.php
@@ -0,0 +1,338 @@
+<?php
+/**
+ * DokuWiki Plugin farmer (Admin Component)
+ *
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Michael Große <grosse@cosmocode.de>
+ */
+
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+class admin_plugin_farmer_new extends DokuWiki_Admin_Plugin {
+
+ /** @var helper_plugin_farmer $helper */
+ protected $helper;
+
+ /**
+ * @return bool true if only access for superuser, false is for superusers and moderators
+ */
+ public function forAdminOnly() {
+ return true;
+ }
+
+ /**
+ * admin_plugin_farmer_new constructor.
+ */
+ public function __construct() {
+ $this->helper = plugin_load('helper', 'farmer');
+ }
+
+ /**
+ * Should carry out any processing required by the plugin.
+ */
+ public function handle() {
+ global $INPUT;
+ global $ID;
+ if(!$INPUT->has('farmer__submit')) return;
+
+ $data = $this->validateAnimalData();
+ if(!$data) return;
+ if($this->createNewAnimal($data['name'], $data['admin'], $data['pass'], $data['template'], $data['aclpolicy'], $data['allowreg'])) {
+ $url = $this->helper->getAnimalURL($data['name']);
+ $link = '<a href="' . $url . '">' . hsc($data['name']) . '</a>';
+
+ msg(sprintf($this->getLang('animal creation success'), $link), 1);
+ $link = wl($ID, array('do' => 'admin', 'page' => 'farmer', 'sub' => 'new'), true, '&');
+ send_redirect($link);
+ }
+ }
+
+ /**
+ * Render HTML output, e.g. helpful text and a form
+ */
+ public function html() {
+ global $lang;
+ $farmconfig = $this->helper->getConfig();
+
+ $form = new \dokuwiki\Form\Form();
+ $form->addClass('plugin_farmer')->id('farmer__create_animal_form');
+
+ $form->addFieldsetOpen($this->getLang('animal configuration'));
+ $form->addTextInput('animalname', $this->getLang('animal'));
+ $form->addFieldsetClose();
+
+ $animals = $this->helper->getAllAnimals();
+ array_unshift($animals, '');
+ $form->addFieldsetOpen($this->getLang('animal template'));
+ $form->addDropdown('animaltemplate', $animals)->addClass('farmer_chosen_animals');
+ $form->addFieldsetClose();
+
+ $form->addFieldsetOpen($lang['i_policy'])->attr('id', 'aclPolicyFieldset');
+ $policyOptions = array('open' => $lang['i_pol0'],'public' => $lang['i_pol1'], 'closed' => $lang['i_pol2']);
+ $form->addDropdown('aclpolicy', $policyOptions)->addClass('acl_chosen');
+ if ($farmconfig['inherit']['main']) {
+ $form->addRadioButton('allowreg',$this->getLang('inherit user registration'))->val('inherit')->attr('checked', 'checked');
+ $form->addRadioButton('allowreg',$this->getLang('enable user registration'))->val('allow');
+ $form->addRadioButton('allowreg',$this->getLang('disable user registration'))->val('disable');
+ } else {
+ $form->addCheckbox('allowreg', $lang['i_allowreg'])->attr('checked', 'checked');
+ }
+
+ $form->addFieldsetClose();
+
+ $form->addFieldsetOpen($this->getLang('animal administrator'));
+ $btn = $form->addRadioButton('adminsetup', $this->getLang('noUsers'))->val('noUsers');
+ if($farmconfig['inherit']['users']) {
+ $btn->attr('checked', 'checked'); // default when inherit available
+ } else {
+ // no user copying when inheriting
+ $form->addRadioButton('adminsetup', $this->getLang('importUsers'))->val('importUsers');
+ $form->addRadioButton('adminsetup', $this->getLang('currentAdmin'))->val('currentAdmin');
+ }
+ $btn = $form->addRadioButton('adminsetup', $this->getLang('newAdmin'))->val('newAdmin');
+ if(!$farmconfig['inherit']['users']) {
+ $btn->attr('checked', 'checked'); // default when inherit not available
+ }
+ $form->addPasswordInput('adminPassword', $this->getLang('admin password'));
+ $form->addFieldsetClose();
+
+ $form->addButton('farmer__submit', $this->getLang('submit'))->attr('type', 'submit')->val('newAnimal');
+ echo $form->toHTML();
+ }
+
+ /**
+ * Validate the data for a new animal
+ *
+ * @return array|bool false on errors, clean data otherwise
+ */
+ protected function validateAnimalData() {
+ global $INPUT;
+
+ $animalname = $INPUT->filter('trim')->str('animalname');
+ $adminsetup = $INPUT->str('adminsetup');
+ $adminpass = $INPUT->filter('trim')->str('adminPassword');
+ $template = $INPUT->filter('trim')->str('animaltemplate');
+ $aclpolicy = $INPUT->filter('trim')->str('aclpolicy');
+ $allowreg = $INPUT->str('allowreg');
+
+ $errors = array();
+
+ if($animalname === '') {
+ $errors[] = $this->getLang('animalname_missing');
+ } elseif(!$this->helper->validateAnimalName($animalname)) {
+ $errors[] = $this->getLang('animalname_invalid');
+ }
+
+ if($adminsetup === 'newAdmin' && $adminpass === '') {
+ $errors[] = $this->getLang('adminPassword_empty');
+ }
+
+ if($animalname !== '' && file_exists(DOKU_FARMDIR . '/' . $animalname)) {
+ $errors[] = $this->getLang('animalname_preexisting');
+ }
+
+ if (!is_dir(DOKU_FARMDIR . $template) && !in_array($aclpolicy,array('open', 'public', 'closed'))) {
+ $errors[] = $this->getLang('aclpolicy missing/bad');
+ }
+
+ if($errors) {
+ foreach($errors as $error) {
+ msg($error, -1);
+ }
+ return false;
+ }
+
+ if(!is_dir(DOKU_FARMDIR . $template)) {
+ $template = '';
+ }
+ if ($template != '') {
+ $aclpolicy = '';
+ }
+
+ return array(
+ 'name' => $animalname,
+ 'admin' => $adminsetup,
+ 'pass' => $adminpass,
+ 'template' => $template,
+ 'aclpolicy' => $aclpolicy,
+ 'allowreg' => $allowreg
+ );
+ }
+
+ /**
+ * Create a new animal
+ *
+ * @param string $name name/title of the animal, will be the directory name for htaccess setup
+ * @param string $adminSetup newAdmin, currentAdmin or importUsers
+ * @param string $adminPassword required if $adminSetup is newAdmin
+ * @param string $template name of animal to copy
+ * @param $aclpolicy
+ * @param $userreg
+ * @return bool true if successful
+ * @throws Exception
+ */
+ protected function createNewAnimal($name, $adminSetup, $adminPassword, $template, $aclpolicy, $userreg) {
+ $animaldir = DOKU_FARMDIR . $name;
+
+ // copy basic template
+ $ok = $this->helper->io_copyDir(__DIR__ . '/../_animal', $animaldir);
+ if(!$ok) {
+ msg($this->getLang('animal creation error'), -1);
+ return false;
+ }
+
+ // copy animal template
+ if($template != '') {
+ foreach(array('conf', 'data/pages', 'data/media', 'data/meta', 'data/media_meta', 'index') as $dir) {
+ $templatedir = DOKU_FARMDIR . $template . '/' . $dir;
+ if(!is_dir($templatedir)) continue;
+ // do not copy changelogs in meta
+ if(substr($dir, -4) == 'meta') {
+ $exclude = '/\.changes$/';
+ } else {
+ $exclude = '';
+ }
+ if(!$this->helper->io_copyDir($templatedir, $animaldir . '/' . $dir, $exclude)) {
+ msg(sprintf($this->getLang('animal template copy error'), $dir), -1);
+ // we go on anyway
+ }
+ }
+ }
+
+ // append title to local config
+ $ok &= io_saveFile($animaldir . '/conf/local.php', "\n" . '$conf[\'title\'] = \'' . $name . '\';' . "\n", true);
+
+ // create a random logo and favicon
+ if(!class_exists('\splitbrain\RingIcon\RingIcon', false)) {
+ require(__DIR__ . '/../3rdparty/RingIcon.php');
+ }
+ if(!class_exists('\chrisbliss18\phpico\PHPIco', false)) {
+ require(__DIR__ . '/../3rdparty/PHPIco.php');
+ }
+ try {
+ if(function_exists('imagecreatetruecolor')) {
+ $logo = $animaldir . '/data/media/wiki/logo.png';
+ if(!file_exists($logo)) {
+ $ringicon = new \splitbrain\RingIcon\RingIcon(64);
+ $ringicon->createImage($animaldir, $logo);
+ }
+
+ $icon = $animaldir . '/data/media/wiki/favicon.ico';
+ if(!file_exists($icon)) {
+ $icongen = new \chrisbliss18\phpico\PHPIco($logo);
+ $icongen->save_ico($icon);
+ }
+ }
+ } catch(\Exception $ignore) {
+ // something went wrong, but we don't care. this is a nice to have feature only
+ }
+
+ // create admin user
+ if($adminSetup === 'newAdmin') {
+ $users = "# <?php exit()?>\n" . $this->makeAdminLine($adminPassword) . "\n";
+ } elseif($adminSetup === 'currentAdmin') {
+ $users = "# <?php exit()?>\n" . $this->getAdminLine() . "\n";
+ } elseif($adminSetup === 'noUsers') {
+ if(file_exists($animaldir . '/conf/users.auth.php')) {
+ // a user file exists already, probably from animal template - don't overwrite
+ $users = '';
+ } else {
+ // create empty user file
+ $users = "# <?php exit()?>\n";
+ }
+ } else {
+ $users = io_readFile(DOKU_CONF . 'users.auth.php');
+ }
+ if($users) {
+ $ok &= io_saveFile($animaldir . '/conf/users.auth.php', $users);
+ }
+
+ if ($aclpolicy != '') {
+ $aclfile = file($animaldir . '/conf/acl.auth.php');
+ $aclfile = array_map('trim', $aclfile);
+ array_pop($aclfile);
+ switch ($aclpolicy) {
+ case 'open':
+ $aclfile[] = "* @ALL 8";
+ break;
+ case 'public':
+ $aclfile[] = "* @ALL 1";
+ $aclfile[] = "* @user 8";
+ break;
+ case 'closed':
+ $aclfile[] = "* @ALL 0";
+ $aclfile[] = "* @user 8";
+ break;
+ default:
+ throw new Exception('Undefined aclpolicy given');
+ }
+ $ok &= io_saveFile($animaldir . '/conf/acl.auth.php', join("\n", $aclfile)."\n");
+
+ global $conf;
+ switch ($userreg) {
+ case 'allow':
+ $disableactions = join(',', array_diff(explode(',', $conf['disableactions']), array('register')));
+ $ok &= io_saveFile($animaldir . '/conf/local.php', "\n" . '$conf[\'disableactions\'] = \''.$disableactions.'\';' . "\n", true);
+ break;
+ case 'disable':
+ $disableactions = join(',', array_merge(explode(',', $conf['disableactions']), array('register')));
+ $ok &= io_saveFile($animaldir . '/conf/local.php', "\n" . '$conf[\'disableactions\'] = \''.$disableactions.'\';' . "\n", true);
+ break;
+ case 'inherit':
+ case true:
+ // nothing needs to be done
+ break;
+ default:
+ $ok &= io_saveFile($animaldir . '/conf/local.php', "\n" . '$conf[\'disableactions\'] = \'register\';' . "\n", true);
+ }
+ }
+
+ // deactivate plugins by default FIXME this should be nicer
+ $deactivatedPluginsList = explode(',', $this->getConf('deactivated plugins'));
+ $deactivatedPluginsList = array_map('trim', $deactivatedPluginsList);
+ $deactivatedPluginsList = array_unique($deactivatedPluginsList);
+ $deactivatedPluginsList = array_filter($deactivatedPluginsList);
+ foreach($deactivatedPluginsList as $plugin) {
+ $this->helper->setPluginState(trim($plugin), $name, 0);
+ }
+
+ return $ok;
+ }
+
+ /**
+ * Creates a new user line
+ *
+ * @param $password
+ * @return string
+ */
+ protected function makeAdminLine($password) {
+ $pass = auth_cryptPassword($password);
+ $line = join(
+ ':', array(
+ 'admin',
+ $pass,
+ 'Administrator',
+ 'admin@example.org',
+ 'admin,user'
+ )
+ );
+ return $line;
+ }
+
+ /**
+ * Copies the current user as new admin line
+ *
+ * @return string
+ */
+ protected function getAdminLine() {
+ $currentAdmin = $_SERVER['REMOTE_USER'];
+ $masterUsers = file_get_contents(DOKU_CONF . 'users.auth.php');
+ $masterUsers = ltrim(strstr($masterUsers, "\n" . $currentAdmin . ":"));
+ $newAdmin = substr($masterUsers, 0, strpos($masterUsers, "\n") + 1);
+ return $newAdmin;
+ }
+
+}
+
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/farmer/admin/plugins.php b/platform/www/lib/plugins/farmer/admin/plugins.php
new file mode 100644
index 0000000..74f0e60
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/admin/plugins.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * DokuWiki Plugin farmer (Admin Component)
+ *
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Michael Große <grosse@cosmocode.de>
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+/**
+ * Manage Animal Plugin settings
+ */
+class admin_plugin_farmer_plugins extends DokuWiki_Admin_Plugin {
+
+ /** @var helper_plugin_farmer $helper */
+ private $helper;
+
+ public function __construct() {
+ $this->helper = plugin_load('helper', 'farmer');
+ }
+
+ /**
+ * handle user request
+ */
+ public function handle() {
+ global $INPUT;
+ global $ID;
+
+ $self = wl($ID, array('do' => 'admin', 'page' => 'farmer', 'sub' => 'plugins'), true, '&');
+
+ if($INPUT->has('bulk_plugin') && $INPUT->has('state')) {
+ $animals = $this->helper->getAllAnimals();
+ $plugin = $INPUT->str('bulk_plugin');
+ foreach($animals as $animal) {
+ $this->helper->setPluginState($plugin, $animal, $INPUT->int('state'));
+ }
+ msg($this->getLang('plugindone'), 1);
+ send_redirect($self);
+ }
+
+ if($INPUT->has('bulk_animal') && $INPUT->has('bulk_plugins')) {
+ $animal = $INPUT->str('bulk_animal');
+ $activePlugins = $INPUT->arr('bulk_plugins');
+ foreach($activePlugins as $plugin => $state) {
+ $this->helper->setPluginState($plugin, $animal, $state);
+ }
+ msg($this->getLang('plugindone'), 1);
+ send_redirect($self);
+ }
+ }
+
+ /**
+ * output appropriate html
+ */
+ public function html() {
+
+ echo $this->locale_xhtml('plugins');
+ $switchForm = new \dokuwiki\Form\Form();
+ $switchForm->addClass('plugin_farmer');
+ $switchForm->addFieldsetOpen($this->getLang('bulkSingleSwitcher'));
+ $switchForm->addRadioButton('bulkSingleSwitch', $this->getLang('bulkEdit'))->id('farmer__bulk')->attr('type', 'radio');
+ $switchForm->addRadioButton('bulkSingleSwitch', $this->getLang('singleEdit'))->id('farmer__single')->attr('type', 'radio');
+ $switchForm->addRadioButton('bulkSingleSwitch', $this->getLang('matrixEdit'))->id('farmer__matrix')->attr('type', 'radio');
+ $switchForm->addFieldsetClose();
+ echo $switchForm->toHTML();
+
+ /** @var helper_plugin_farmer $helper */
+ $helper = plugin_load('helper', 'farmer');
+ $plugins = $helper->getAllPlugins();
+ array_unshift($plugins, '');
+
+ // All Animals at once
+ $bulkForm = new \dokuwiki\Form\Form();
+ $bulkForm->id('farmer__pluginsforall');
+ $bulkForm->addFieldsetOpen($this->getLang('bulkEditForm'));
+ $bulkForm->addDropdown('bulk_plugin', $plugins);
+ $bulkForm->addButton('state', $this->getLang('default'))->attr('value', '-1')->attr('type', 'submit')->attr('disabled', 'disabled');
+ $bulkForm->addButton('state', $this->getLang('activate'))->attr('value', '1')->attr('type', 'submit')->attr('disabled', 'disabled');
+ $bulkForm->addButton('state', $this->getLang('deactivate'))->attr('value', '0')->attr('type', 'submit')->attr('disabled', 'disabled');
+ $bulkForm->addFieldsetClose();
+ echo $bulkForm->toHTML();
+
+ $animals = $helper->getAllAnimals();
+ array_unshift($animals, '');
+
+ // One Animal, all the plugins
+ $singleForm = new \dokuwiki\Form\Form();
+ $singleForm->id('farmer__pluginsforone');
+ $singleForm->addFieldsetOpen($this->getLang('singleEditForm'));
+ $singleForm->addDropdown('bulk_animal', $animals);
+ $singleForm->addTagOpen('div')->addClass('output');
+ $singleForm->addTagClose('div');
+ $singleForm->addButton('save', $this->getLang('save'))->attr('disabled', 'disabled');
+
+ echo $singleForm->toHTML();
+
+
+ echo '<div id="farmer__pluginmatrix"></div>';
+ }
+}
+
diff --git a/platform/www/lib/plugins/farmer/admin/setup.php b/platform/www/lib/plugins/farmer/admin/setup.php
new file mode 100644
index 0000000..f836ae5
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/admin/setup.php
@@ -0,0 +1,151 @@
+<?php
+/**
+ * DokuWiki Plugin farmer (Admin Component)
+ *
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Michael Große <grosse@cosmocode.de>
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+/**
+ * Setup the farm by creating preload.php etc
+ */
+class admin_plugin_farmer_setup extends DokuWiki_Admin_Plugin {
+
+ /** @var helper_plugin_farmer $helper */
+ private $helper;
+
+ /**
+ * @return bool admin only!
+ */
+ public function forAdminOnly() {
+ return true;
+ }
+
+ /**
+ * Should carry out any processing required by the plugin.
+ */
+ public function handle() {
+ global $INPUT;
+ global $ID;
+
+ if(!$INPUT->bool('farmdir')) return;
+ if(!checkSecurityToken()) return;
+
+ $this->helper = plugin_load('helper', 'farmer');
+
+ $farmdir = trim($INPUT->str('farmdir', ''));
+ if($farmdir[0] !== '/') $farmdir = DOKU_INC . $farmdir;
+ $farmdir = fullpath($farmdir);
+
+ $errors = array();
+ if($farmdir === '') {
+ $errors[] = $this->getLang('farmdir_missing');
+ } elseif($this->helper->isInPath($farmdir, DOKU_INC) !== false) {
+ $errors[] = sprintf($this->getLang('farmdir_in_dokuwiki'), hsc($farmdir), hsc(DOKU_INC));
+ } elseif(!io_mkdir_p($farmdir)) {
+ $errors[] = sprintf($this->getLang('farmdir_uncreatable'), hsc($farmdir));
+ } elseif(!is_writeable($farmdir)) {
+ $errors[] = sprintf($this->getLang('farmdir_unwritable'), hsc($farmdir));
+ } elseif(count(scandir($farmdir)) > 2) {
+ $errors[] = sprintf($this->getLang('farmdir_notEmpty'), hsc($farmdir));
+ }
+
+ if($errors) {
+ foreach($errors as $error) {
+ msg($error, -1);
+ }
+ return;
+ }
+
+ // create the files
+ $ok = $this->createPreloadPHP();
+ if($ok && $INPUT->bool('htaccess')) $ok &= $this->createHtaccess();
+ if($ok) $ok &= $this->createFarmIni($farmdir);
+
+ if($ok) {
+ msg($this->getLang('preload creation success'), 1);
+ $link = wl($ID, array('do' => 'admin', 'page' => 'farmer', 'sub' => 'config'), true, '&');
+ send_redirect($link);
+ } else {
+ msg($this->getLang('preload creation error'), -1);
+ }
+ }
+
+ /**
+ * Render HTML output, e.g. helpful text and a form
+ */
+ public function html() {
+ // Is preload.php already enabled?
+ if(file_exists(DOKU_INC . 'inc/preload.php')) {
+ msg($this->getLang('overwrite_preload'), -1);
+ }
+
+ $form = new \dokuwiki\Form\Form();
+ $form->addClass('plugin_farmer');
+ $form->addFieldsetOpen($this->getLang('preloadPHPForm'));
+ $form->addTextInput('farmdir', $this->getLang('farm dir'));
+ $form->addCheckbox('htaccess', $this->getLang('htaccess setup'))->attr('checked', 'checked');
+ $form->addButton('farmer__submit', $this->getLang('submit'))->attr('type', 'submit');
+ $form->addFieldsetClose();
+ echo $form->toHTML();
+
+ }
+
+ /**
+ * Creates the preload that loads our farm controller
+ * @return bool true if saving was successful
+ */
+ protected function createPreloadPHP() {
+ $content = "<?php\n";
+ $content .= "# farm setup by farmer plugin\n";
+ $content .= "if(file_exists(__DIR__ . '/../lib/plugins/farmer/DokuWikiFarmCore.php')) {\n";
+ $content .= " include(__DIR__ . '/../lib/plugins/farmer/DokuWikiFarmCore.php');\n";
+ $content .= "}\n";
+ return io_saveFile(DOKU_INC . 'inc/preload.php', $content);
+ }
+
+ /**
+ * Prepends the needed config to the main .htaccess for htaccess type setups
+ *
+ * @return bool true if saving was successful
+ */
+ protected function createHtaccess() {
+ // load existing or template
+ if(file_exists(DOKU_INC . '.htaccess')) {
+ $old = io_readFile(DOKU_INC . '.htaccess');
+ } elseif(file_exists(DOKU_INC . '.htaccess.dist')) {
+ $old = io_readFile(DOKU_INC . '.htaccess.dist');
+ } else {
+ $old = '';
+ }
+
+ $content = "# Options added for farm setup by farmer plugin:\n";
+ $content .= "RewriteEngine On\n";
+ $content .= 'RewriteRule ^!([^/]+)/(.*) $2?animal=$1 [QSA,DPI]' . "\n";
+ $content .= 'RewriteRule ^!([^/]+)$ ?animal=$1 [QSA,DPI]' . "\n";
+ $content .= 'Options +FollowSymLinks' . "\n";
+ $content .= '# end of farm configuration' . "\n\n";
+ $content .= $old;
+ return io_saveFile(DOKU_INC . '.htaccess', $content);
+ }
+
+ /**
+ * Creates the initial configuration
+ *
+ * @param $animalpath
+ * @return bool true if saving was successful
+ */
+ protected function createFarmIni($animalpath) {
+ $content = "; farm config created by the farmer plugin\n\n";
+ $content .= "[base]\n";
+ $content .= "farmdir = $animalpath\n";
+ $content .= "farmhost = {$_SERVER['HTTP_HOST']}\n";
+ return io_saveFile(DOKU_INC . 'conf/farm.ini', $content);
+ }
+}
+
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/farmer/all.less b/platform/www/lib/plugins/farmer/all.less
new file mode 100644
index 0000000..effff6f
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/all.less
@@ -0,0 +1,13 @@
+@import "css/chosen.less";
+
+.chosen-container-single .chosen-single abbr,
+.chosen-container-single .chosen-single div b,
+.chosen-container-single .chosen-search input[type="text"],
+.chosen-container-multi .chosen-choices li.search-choice .search-choice-close,
+.chosen-rtl .chosen-search input[type="text"] {
+ background-image: url(css/chosen-sprite.png);
+}
+
+@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi), only screen and (min-resolution: 1.5dppx) {
+ background-image: url(css/chosen-sprite.png);
+}
diff --git a/platform/www/lib/plugins/farmer/conf/default.php b/platform/www/lib/plugins/farmer/conf/default.php
new file mode 100644
index 0000000..33e10d4
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/conf/default.php
@@ -0,0 +1,9 @@
+<?php
+/**
+ * Default settings for the farmer plugin
+ *
+ * @author Michael Große <grosse@cosmocode.de>
+ */
+
+$conf['deactivated plugins'] = '';
+$conf['disable_new_plugins'] = 0;
diff --git a/platform/www/lib/plugins/farmer/conf/metadata.php b/platform/www/lib/plugins/farmer/conf/metadata.php
new file mode 100644
index 0000000..9b81338
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/conf/metadata.php
@@ -0,0 +1,9 @@
+<?php
+/**
+ * Options for the farmer plugin
+ *
+ * @author Michael Große <grosse@cosmocode.de>
+ */
+
+$meta['deactivated plugins'] = array('string');
+$meta['disable_new_plugins'] = array('onoff');
diff --git a/platform/www/lib/plugins/farmer/css/chosen-sprite.png b/platform/www/lib/plugins/farmer/css/chosen-sprite.png
new file mode 100644
index 0000000..c57da70
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/css/chosen-sprite.png
Binary files differ
diff --git a/platform/www/lib/plugins/farmer/css/chosen.less b/platform/www/lib/plugins/farmer/css/chosen.less
new file mode 100644
index 0000000..e7ea092
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/css/chosen.less
@@ -0,0 +1,450 @@
+/*!
+Chosen, a Select Box Enhancer for jQuery and Prototype
+by Patrick Filler for Harvest, http://getharvest.com
+
+Version 1.4.2
+Full source at https://github.com/harvesthq/chosen
+Copyright (c) 2011-2015 Harvest http://getharvest.com
+
+MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
+This file is generated by `grunt build`, do not edit it by hand.
+*/
+
+/* @group Base */
+.chosen-container {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+ font-size: 13px;
+ zoom: 1;
+ *display: inline;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+}
+.chosen-container * {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.chosen-container .chosen-drop {
+ position: absolute;
+ top: 100%;
+ left: -9999px;
+ z-index: 1010;
+ width: 100%;
+ border: 1px solid #aaa;
+ border-top: 0;
+ background: #fff;
+ box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15);
+}
+.chosen-container.chosen-with-drop .chosen-drop {
+ left: 0;
+}
+.chosen-container a {
+ cursor: pointer;
+}
+.chosen-container .search-choice .group-name, .chosen-container .chosen-single .group-name {
+ margin-right: 4px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ font-weight: normal;
+ color: #999999;
+}
+.chosen-container .search-choice .group-name:after, .chosen-container .chosen-single .group-name:after {
+ content: ":";
+ padding-left: 2px;
+ vertical-align: top;
+}
+
+/* @end */
+/* @group Single Chosen */
+.chosen-container-single .chosen-single {
+ position: relative;
+ display: block;
+ overflow: hidden;
+ padding: 0 0 0 8px;
+ height: 25px;
+ border: 1px solid #aaa;
+ border-radius: 5px;
+ background-color: #fff;
+ background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #ffffff), color-stop(50%, #f6f6f6), color-stop(52%, #eeeeee), color-stop(100%, #f4f4f4));
+ background: -webkit-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
+ background: -moz-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
+ background: -o-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
+ background: linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
+ background-clip: padding-box;
+ box-shadow: 0 0 3px white inset, 0 1px 1px rgba(0, 0, 0, 0.1);
+ color: #444;
+ text-decoration: none;
+ white-space: nowrap;
+ line-height: 24px;
+}
+.chosen-container-single .chosen-default {
+ color: #999;
+}
+.chosen-container-single .chosen-single span {
+ display: block;
+ overflow: hidden;
+ margin-right: 26px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.chosen-container-single .chosen-single-with-deselect span {
+ margin-right: 38px;
+}
+.chosen-container-single .chosen-single abbr {
+ position: absolute;
+ top: 6px;
+ right: 26px;
+ display: block;
+ width: 12px;
+ height: 12px;
+ background: url('chosen-sprite.png') -42px 1px no-repeat;
+ font-size: 1px;
+}
+.chosen-container-single .chosen-single abbr:hover {
+ background-position: -42px -10px;
+}
+.chosen-container-single.chosen-disabled .chosen-single abbr:hover {
+ background-position: -42px -10px;
+}
+.chosen-container-single .chosen-single div {
+ position: absolute;
+ top: 0;
+ right: 0;
+ display: block;
+ width: 18px;
+ height: 100%;
+}
+.chosen-container-single .chosen-single div b {
+ display: block;
+ width: 100%;
+ height: 100%;
+ background: url('chosen-sprite.png') no-repeat 0px 2px;
+}
+.chosen-container-single .chosen-search {
+ position: relative;
+ z-index: 1010;
+ margin: 0;
+ padding: 3px 4px;
+ white-space: nowrap;
+}
+.chosen-container-single .chosen-search input[type="text"] {
+ margin: 1px 0;
+ padding: 4px 20px 4px 5px;
+ width: 100%;
+ height: auto;
+ outline: 0;
+ border: 1px solid #aaa;
+ background: white url('chosen-sprite.png') no-repeat 100% -20px;
+ background: url('chosen-sprite.png') no-repeat 100% -20px;
+ font-size: 1em;
+ font-family: sans-serif;
+ line-height: normal;
+ border-radius: 0;
+}
+.chosen-container-single .chosen-drop {
+ margin-top: -1px;
+ border-radius: 0 0 4px 4px;
+ background-clip: padding-box;
+}
+.chosen-container-single.chosen-container-single-nosearch .chosen-search {
+ position: absolute;
+ left: -9999px;
+}
+
+/* @end */
+/* @group Results */
+.chosen-container .chosen-results {
+ color: #444;
+ position: relative;
+ overflow-x: hidden;
+ overflow-y: auto;
+ margin: 0 4px 4px 0;
+ padding: 0 0 0 4px;
+ max-height: 240px;
+ -webkit-overflow-scrolling: touch;
+}
+.chosen-container .chosen-results li {
+ display: none;
+ margin: 0;
+ padding: 5px 6px;
+ list-style: none;
+ line-height: 15px;
+ word-wrap: break-word;
+ -webkit-touch-callout: none;
+}
+.chosen-container .chosen-results li.active-result {
+ display: list-item;
+ cursor: pointer;
+}
+.chosen-container .chosen-results li.disabled-result {
+ display: list-item;
+ color: #ccc;
+ cursor: default;
+}
+.chosen-container .chosen-results li.highlighted {
+ background-color: #3875d7;
+ background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc));
+ background-image: -webkit-linear-gradient(#3875d7 20%, #2a62bc 90%);
+ background-image: -moz-linear-gradient(#3875d7 20%, #2a62bc 90%);
+ background-image: -o-linear-gradient(#3875d7 20%, #2a62bc 90%);
+ background-image: linear-gradient(#3875d7 20%, #2a62bc 90%);
+ color: #fff;
+}
+.chosen-container .chosen-results li.no-results {
+ color: #777;
+ display: list-item;
+ background: #f4f4f4;
+}
+.chosen-container .chosen-results li.group-result {
+ display: list-item;
+ font-weight: bold;
+ cursor: default;
+}
+.chosen-container .chosen-results li.group-option {
+ padding-left: 15px;
+}
+.chosen-container .chosen-results li em {
+ font-style: normal;
+ text-decoration: underline;
+}
+
+/* @end */
+/* @group Multi Chosen */
+.chosen-container-multi .chosen-choices {
+ position: relative;
+ overflow: hidden;
+ margin: 0;
+ padding: 0 5px;
+ width: 100%;
+ height: auto !important;
+ height: 1%;
+ border: 1px solid #aaa;
+ background-color: #fff;
+ background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
+ background-image: -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%);
+ background-image: -moz-linear-gradient(#eeeeee 1%, #ffffff 15%);
+ background-image: -o-linear-gradient(#eeeeee 1%, #ffffff 15%);
+ background-image: linear-gradient(#eeeeee 1%, #ffffff 15%);
+ cursor: text;
+}
+.chosen-container-multi .chosen-choices li {
+ float: left;
+ list-style: none;
+}
+.chosen-container-multi .chosen-choices li.search-field {
+ margin: 0;
+ padding: 0;
+ white-space: nowrap;
+}
+.chosen-container-multi .chosen-choices li.search-field input[type="text"] {
+ margin: 1px 0;
+ padding: 0;
+ height: 25px;
+ outline: 0;
+ border: 0 !important;
+ background: transparent !important;
+ box-shadow: none;
+ color: #999;
+ font-size: 100%;
+ font-family: sans-serif;
+ line-height: normal;
+ border-radius: 0;
+}
+.chosen-container-multi .chosen-choices li.search-choice {
+ position: relative;
+ margin: 3px 5px 3px 0;
+ padding: 3px 20px 3px 5px;
+ border: 1px solid #aaa;
+ max-width: 100%;
+ border-radius: 3px;
+ background-color: #eeeeee;
+ background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee));
+ background-image: -webkit-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+ background-image: -moz-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+ background-image: -o-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+ background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+ background-size: 100% 19px;
+ background-repeat: repeat-x;
+ background-clip: padding-box;
+ box-shadow: 0 0 2px white inset, 0 1px 0 rgba(0, 0, 0, 0.05);
+ color: #333;
+ line-height: 13px;
+ cursor: default;
+}
+.chosen-container-multi .chosen-choices li.search-choice span {
+ word-wrap: break-word;
+}
+.chosen-container-multi .chosen-choices li.search-choice .search-choice-close {
+ position: absolute;
+ top: 4px;
+ right: 3px;
+ display: block;
+ width: 12px;
+ height: 12px;
+ background: url('chosen-sprite.png') -42px 1px no-repeat;
+ font-size: 1px;
+}
+.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover {
+ background-position: -42px -10px;
+}
+.chosen-container-multi .chosen-choices li.search-choice-disabled {
+ padding-right: 5px;
+ border: 1px solid #ccc;
+ background-color: #e4e4e4;
+ background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee));
+ background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+ background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+ background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+ background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+ color: #666;
+}
+.chosen-container-multi .chosen-choices li.search-choice-focus {
+ background: #d4d4d4;
+}
+.chosen-container-multi .chosen-choices li.search-choice-focus .search-choice-close {
+ background-position: -42px -10px;
+}
+.chosen-container-multi .chosen-results {
+ margin: 0;
+ padding: 0;
+}
+.chosen-container-multi .chosen-drop .result-selected {
+ display: list-item;
+ color: #ccc;
+ cursor: default;
+}
+
+/* @end */
+/* @group Active */
+.chosen-container-active .chosen-single {
+ border: 1px solid #5897fb;
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
+}
+.chosen-container-active.chosen-with-drop .chosen-single {
+ border: 1px solid #aaa;
+ -moz-border-radius-bottomright: 0;
+ border-bottom-right-radius: 0;
+ -moz-border-radius-bottomleft: 0;
+ border-bottom-left-radius: 0;
+ background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #eeeeee), color-stop(80%, #ffffff));
+ background-image: -webkit-linear-gradient(#eeeeee 20%, #ffffff 80%);
+ background-image: -moz-linear-gradient(#eeeeee 20%, #ffffff 80%);
+ background-image: -o-linear-gradient(#eeeeee 20%, #ffffff 80%);
+ background-image: linear-gradient(#eeeeee 20%, #ffffff 80%);
+ box-shadow: 0 1px 0 #fff inset;
+}
+.chosen-container-active.chosen-with-drop .chosen-single div {
+ border-left: none;
+ background: transparent;
+}
+.chosen-container-active.chosen-with-drop .chosen-single div b {
+ background-position: -18px 2px;
+}
+.chosen-container-active .chosen-choices {
+ border: 1px solid #5897fb;
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
+}
+.chosen-container-active .chosen-choices li.search-field input[type="text"] {
+ color: #222 !important;
+}
+
+/* @end */
+/* @group Disabled Support */
+.chosen-disabled {
+ opacity: 0.5 !important;
+ cursor: default;
+}
+.chosen-disabled .chosen-single {
+ cursor: default;
+}
+.chosen-disabled .chosen-choices .search-choice .search-choice-close {
+ cursor: default;
+}
+
+/* @end */
+/* @group Right to Left */
+.chosen-rtl {
+ text-align: right;
+}
+.chosen-rtl .chosen-single {
+ overflow: visible;
+ padding: 0 8px 0 0;
+}
+.chosen-rtl .chosen-single span {
+ margin-right: 0;
+ margin-left: 26px;
+ direction: rtl;
+}
+.chosen-rtl .chosen-single-with-deselect span {
+ margin-left: 38px;
+}
+.chosen-rtl .chosen-single div {
+ right: auto;
+ left: 3px;
+}
+.chosen-rtl .chosen-single abbr {
+ right: auto;
+ left: 26px;
+}
+.chosen-rtl .chosen-choices li {
+ float: right;
+}
+.chosen-rtl .chosen-choices li.search-field input[type="text"] {
+ direction: rtl;
+}
+.chosen-rtl .chosen-choices li.search-choice {
+ margin: 3px 5px 3px 0;
+ padding: 3px 5px 3px 19px;
+}
+.chosen-rtl .chosen-choices li.search-choice .search-choice-close {
+ right: auto;
+ left: 4px;
+}
+.chosen-rtl.chosen-container-single-nosearch .chosen-search,
+.chosen-rtl .chosen-drop {
+ left: 9999px;
+}
+.chosen-rtl.chosen-container-single .chosen-results {
+ margin: 0 0 4px 4px;
+ padding: 0 4px 0 0;
+}
+.chosen-rtl .chosen-results li.group-option {
+ padding-right: 15px;
+ padding-left: 0;
+}
+.chosen-rtl.chosen-container-active.chosen-with-drop .chosen-single div {
+ border-right: none;
+}
+.chosen-rtl .chosen-search input[type="text"] {
+ padding: 4px 5px 4px 20px;
+ background: white url('chosen-sprite.png') no-repeat -30px -20px;
+ background: url('chosen-sprite.png') no-repeat -30px -20px;
+ direction: rtl;
+}
+.chosen-rtl.chosen-container-single .chosen-single div b {
+ background-position: 6px 2px;
+}
+.chosen-rtl.chosen-container-single.chosen-with-drop .chosen-single div b {
+ background-position: -12px 2px;
+}
+
+/* @end */
+/* @group Retina compatibility */
+@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi), only screen and (min-resolution: 1.5dppx) {
+ .chosen-rtl .chosen-search input[type="text"],
+ .chosen-container-single .chosen-single abbr,
+ .chosen-container-single .chosen-single div b,
+ .chosen-container-single .chosen-search input[type="text"],
+ .chosen-container-multi .chosen-choices .search-choice .search-choice-close,
+ .chosen-container .chosen-results-scroll-down span,
+ .chosen-container .chosen-results-scroll-up span {
+ background-image: url('chosen-sprite@2x.png') !important;
+ background-size: 52px 37px !important;
+ background-repeat: no-repeat !important;
+ }
+}
+/* @end */
diff --git a/platform/www/lib/plugins/farmer/deleted.files b/platform/www/lib/plugins/farmer/deleted.files
new file mode 100644
index 0000000..fea8b5e
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/deleted.files
@@ -0,0 +1,11 @@
+# This is a list of files that were present in previous plugin releases
+# but were removed later. An up to date plugin should not have any of
+# the files installed
+_test/validation.test.php
+action/handleAjax.php
+admin/createAnimal.php
+farm.php
+lang/en/createAnimal.txt
+lang/en/preload.txt
+scripts/plugins.js
+style.css
diff --git a/platform/www/lib/plugins/farmer/helper.php b/platform/www/lib/plugins/farmer/helper.php
new file mode 100644
index 0000000..53e7153
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/helper.php
@@ -0,0 +1,334 @@
+<?php
+/**
+ * DokuWiki Plugin farmer (Helper Component)
+ *
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Michael Große <grosse@cosmocode.de>
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+class helper_plugin_farmer extends DokuWiki_Plugin {
+
+ protected $defaultPluginState = null;
+ protected $animalPluginState = array();
+
+ /**
+ * Returns the name of the current animal if any, false otherwise
+ *
+ * @return string|false
+ */
+ public function getAnimal() {
+ if(!isset($GLOBALS['FARMCORE'])) return false;
+ return $GLOBALS['FARMCORE']->getAnimal();
+ }
+
+ /**
+ * Get the farm config
+ *
+ * @return array
+ */
+ public function getConfig() {
+ if(!isset($GLOBALS['FARMCORE'])) return array();
+ return $GLOBALS['FARMCORE']->getConfig();
+ }
+
+ /**
+ * Was the current animal requested by host?
+ *
+ * @return bool
+ */
+ public function isHostbased() {
+ if(!isset($GLOBALS['FARMCORE'])) return false;
+ return $GLOBALS['FARMCORE']->isHostbased();
+ }
+
+ /**
+ * Was an animal requested that could not be found?
+ *
+ * @return bool
+ */
+ public function wasNotfound() {
+ if(!isset($GLOBALS['FARMCORE'])) return false;
+ return $GLOBALS['FARMCORE']->wasNotfound();
+ }
+
+ /**
+ * Guess the URL for an animal
+ *
+ * @param $animal
+ * @return string
+ */
+ public function getAnimalURL($animal) {
+ $config = $this->getConfig();
+
+ if(strpos($animal, '.') !== false) {
+ return 'http://' . $animal;
+ } elseif($config['base']['basedomain']) {
+ return 'http://' . $animal . '.' . $config['base']['basedomain'];
+ } else {
+ return DOKU_URL . '!' . $animal . '/';
+ }
+ }
+
+ /**
+ * List of all animals, i.e. directories within DOKU_FARMDIR without the template.
+ *
+ * @return array
+ */
+ public function getAllAnimals() {
+ $animals = array();
+ $list = glob(DOKU_FARMDIR . '*/conf/', GLOB_ONLYDIR);
+ foreach($list as $path) {
+ $animal = basename(dirname($path));
+ if($animal == '_animal') continue; // old template
+ $animals[] = $animal;
+ }
+ sort($animals);
+ return $animals;
+ }
+
+ /**
+ * checks wether $path is in under $container
+ *
+ * Also returns false if $path and $container are the same directory
+ *
+ * @param string $path
+ * @param string $container
+ * @return bool
+ */
+ public function isInPath($path, $container) {
+ $path = fullpath($path).'/';
+ $container = fullpath($container).'/';
+ if($path == $container) return false;
+ return (strpos($path, $container) === 0);
+ }
+
+ /**
+ * Check if the farm is correctly configured for this farmer plugin
+ *
+ * @return bool
+ */
+ public function checkFarmSetup() {
+ return defined('DOKU_FARMDIR') && isset($GLOBALS['FARMCORE']);
+ }
+
+ /**
+ * @param string $animalname
+ *
+ * @return bool
+ */
+ public function validateAnimalName($animalname) {
+ return preg_match("/^[a-z0-9]+([\\.\\-][a-z0-9]+)*$/i", $animalname) === 1;
+ }
+
+ /**
+ * Copy a file, or recursively copy a folder and its contents. Adapted for DokuWiki.
+ *
+ * @todo: needs tests
+ *
+ * @author Aidan Lister <aidan@php.net>
+ * @author Michael Große <grosse@cosmocode.de>
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ * @link http://aidanlister.com/2004/04/recursively-copying-directories-in-php/
+ *
+ * @param string $source Source path
+ * @param string $destination Destination path
+ * @param string $exclude Regular expression to exclude files or directories (complete with delimiters)
+ * @return bool Returns TRUE on success, FALSE on failure
+ */
+ function io_copyDir($source, $destination, $exclude = '') {
+ if($exclude && preg_match($exclude, $source)) {
+ return true;
+ }
+
+ if(is_link($source)) {
+ io_lock($destination);
+ $result = symlink(readlink($source), $destination);
+ io_unlock($destination);
+ return $result;
+ }
+
+ if(is_file($source)) {
+ io_lock($destination);
+ $result = copy($source, $destination);
+ io_unlock($destination);
+ return $result;
+ }
+
+ if(!is_dir($destination)) {
+ io_mkdir_p($destination);
+ }
+
+ $dir = @dir($source);
+ if($dir === false) return false;
+ while(false !== ($entry = $dir->read())) {
+ if($entry == '.' || $entry == '..') {
+ continue;
+ }
+
+ // recurse into directories
+ $this->io_copyDir("$source/$entry", "$destination/$entry", $exclude);
+ }
+
+ $dir->close();
+ return true;
+ }
+
+ /**
+ * get a list of all Plugins installed in the farmer wiki, regardless whether they are active or not.
+ *
+ * @param bool $all get all plugins, even disabled ones
+ * @return array
+ */
+ public function getAllPlugins($all = true) {
+
+ /** @var Doku_Plugin_Controller $plugin_controller */
+ global $plugin_controller;
+
+ $plugins = $plugin_controller->getList('', $all);
+
+ // filter out a few plugins
+ $plugins = array_filter(
+ $plugins, function ($item) {
+ if($item == 'farmer') return false;
+ if($item == 'extension') return false;
+ if($item == 'upgrade') return false;
+ if($item == 'testing') return false;
+ return true;
+ }
+ );
+
+ sort($plugins);
+ return $plugins;
+ }
+
+ /**
+ * Get the plugin states configured locally in the given animal
+ *
+ * Response is cached
+ *
+ * @param $animal
+ * @return array
+ */
+ public function getAnimalPluginLocalStates($animal) {
+ if(isset($this->animalPluginState[$animal])) return $this->animalPluginState[$animal];
+
+ $localfile = DOKU_FARMDIR . $animal . '/conf/plugins.local.php';
+ $plugins = array();
+ if(file_exists($localfile)) {
+ include($localfile);
+ }
+
+ $this->animalPluginState[$animal] = $plugins;
+ return $plugins;
+ }
+
+ /**
+ * Return the default state plugins would have in animals
+ *
+ * Response is cached
+ *
+ * @return array
+ */
+ public function getDefaultPluginStates() {
+ if(!is_null($this->defaultPluginState)) return $this->defaultPluginState;
+
+ $farmconf = $this->getConfig();
+ $all = $this->getAllPlugins();
+
+ $plugins = array();
+ foreach($all as $one) {
+ if($farmconf['inherit']['plugins']) {
+ $plugins[$one] = !plugin_isdisabled($one);
+ } else {
+ $plugins[$one] = true; // default state is enabled
+ }
+ }
+
+ ksort($plugins);
+ $this->defaultPluginState = $plugins;
+ return $plugins;
+ }
+
+ /**
+ * Return a structure giving detailed info about the state of all plugins in an animal
+ *
+ * @param $animal
+ * @return array
+ */
+ public function getAnimalPluginRealState($animal) {
+ $info = array();
+
+ $defaults = $this->getDefaultPluginStates();
+ $local = $this->getAnimalPluginLocalStates($animal);
+
+ foreach($defaults as $plugin => $set) {
+ $current = array(
+ 'name' => $plugin,
+ 'default' => $set,
+ 'actual' => $set,
+ 'isdefault' => true
+ );
+
+ if(isset($local[$plugin])) {
+ $current['actual'] = (bool) $local[$plugin];
+ $current['isdefault'] = false;
+ }
+
+ $info[$plugin] = $current;
+ }
+
+ ksort($info);
+ return $info;
+ }
+
+ /**
+ * Set the state of a plugin in an animal
+ *
+ * @param string $plugin
+ * @param string $animal
+ * @param int $state -1 = default, 1 = enabled, 0 = disabled
+ */
+ public function setPluginState($plugin, $animal, $state) {
+ $state = (int) $state;
+
+ $plugins = $this->getAnimalPluginLocalStates($animal);
+ if($state < 0) {
+ if(isset($plugins[$plugin])) unset($plugins[$plugin]);
+ } else {
+ $plugins[$plugin] = $state;
+ }
+
+ $this->writePluginConf($plugins, $animal);
+
+ // clear state cache
+ if(isset($this->animalPluginState[$animal])) unset($this->animalPluginState[$animal]);
+ }
+
+ /**
+ * Write the list of (deactivated) plugins as plugin configuration of an animal to file
+ *
+ * updates the plugin state cache
+ *
+ * @param array $plugins associative array with the key being the plugin name and the value 0 or 1
+ * @param string $animal Directory of the animal within DOKU_FARMDIR
+ */
+ public function writePluginConf($plugins, $animal) {
+ $pluginConf = '<?php' . "\n# plugins enabled and disabled by the farmer plugin\n";
+ foreach($plugins as $plugin => $status) {
+ $pluginConf .= '$plugins[\'' . $plugin . '\'] = ' . $status . ";\n";
+ }
+ io_saveFile(DOKU_FARMDIR . $animal . '/conf/plugins.local.php', $pluginConf);
+ touch(DOKU_FARMDIR . $animal . '/conf/local.php');
+
+ if(function_exists('opcache_invalidate')) {
+ opcache_invalidate(DOKU_FARMDIR . $animal . '/conf/plugins.local.php');
+ opcache_invalidate(DOKU_FARMDIR . $animal . '/conf/local.php');
+ }
+
+ $this->animalPluginState[$animal] = $plugins;
+ }
+}
diff --git a/platform/www/lib/plugins/farmer/includes/config.php b/platform/www/lib/plugins/farmer/includes/config.php
new file mode 100644
index 0000000..cd9aa67
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/includes/config.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * This overrides some values for the animals without having to configure it
+ *
+ * This file is added to the protected cascade for animals only.
+ * You should not edit it!
+ */
+global $FARMCORE;
+$conf['savedir'] = $FARMCORE->getAnimalDataDir();
+$conf['basedir'] = $FARMCORE->getAnimalBaseDir();
+$conf['upgradecheck'] = 0;
+
+
diff --git a/platform/www/lib/plugins/farmer/includes/plugins.php b/platform/www/lib/plugins/farmer/includes/plugins.php
new file mode 100644
index 0000000..cd8d7b2
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/includes/plugins.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * This overrides some values for the animals without having to configure it
+ *
+ * This file is added to the protected cascade for animals only.
+ * You should not edit it!
+ */
+$plugins['extension'] = 0;
+$plugins['upgrade'] = 0;
+$plugins['testing'] = 0;
+$plugins['farmer'] = 1;
+$plugins['farmsync'] = 0;
diff --git a/platform/www/lib/plugins/farmer/includes/template.php b/platform/www/lib/plugins/farmer/includes/template.php
new file mode 100644
index 0000000..1b0075c
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/includes/template.php
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html lang="<?php echo $conf['lang'] ?>" dir="<?php echo $lang['direction'] ?>" class="popup no-js">
+<head>
+ <meta charset="utf-8"/>
+ <title>
+ <?php echo $title ?>
+ </title>
+ <script>(function (H) {
+ H.className = H.className.replace(/\bno-js\b/, 'js')
+ })(document.documentElement)</script>
+ <?php tpl_metaheaders() ?>
+ <meta name="viewport" content="width=device-width,initial-scale=1"/>
+ <?php echo tpl_favicon(array('favicon', 'mobile')) ?>
+ <?php tpl_includeFile('meta.html') ?>
+</head>
+
+<body>
+<!--[if lte IE 8 ]>
+<div id="IE8"><![endif]-->
+<div class="dokuwiki">
+ <div class="page">
+ <?php echo $body ?>
+ </div>
+</div>
+<!--[if lte IE 8 ]></div><![endif]-->
+</body>
+</html>
diff --git a/platform/www/lib/plugins/farmer/lang/de/lang.php b/platform/www/lib/plugins/farmer/lang/de/lang.php
new file mode 100644
index 0000000..b97a850
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/de/lang.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * German language file for farmer plugin
+ *
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+
+// menu entry for admin plugins
+$lang['menu'] = 'Farming';
+
+// tabs
+$lang['tab_setup'] = 'Farm Setup';
+$lang['tab_info'] = 'Info';
+$lang['tab_config'] = 'Konfiguration';
+$lang['tab_plugins'] = 'Plugins verwalten';
+$lang['tab_new'] = 'Neues Animal hinzufügen';
+$lang['tab_delete'] = 'Animal löschen';
+
+// setup
+$lang['preloadPHPForm'] = 'Farm aufsetzen';
+$lang['farm dir'] = 'Animal-Verzeichnis';
+$lang['htaccess setup'] = 'Farm code zu .htaccess hinzufügen?';
+$lang['submit'] = 'Abschicken';
+$lang['farmdir_missing'] = 'Bitte geben Sie das Verzeichnis an in dem die Animals gespeichert werden sollen.';
+$lang['farmdir_in_dokuwiki'] = 'Das Animal-Verzeichnis (%s) muss außerhalb des Farm-DokuWikis (%s) liegen.';
+$lang['farmdir_uncreatable'] = 'Das Animal-Verzeichnis (%s) konnte nicht erzeugt werden. Sind die Dateiberechtigungen korrekt?';
+$lang['farmdir_unwritable'] = 'Bitte stellen Sie sicher, dass der Webserver in das Animal-Verzeichnis (%s) schreiben darf!';
+$lang['farmdir_notEmpty'] = 'Das Animal-Verzeichnis (%s) muss leer sein!';
+$lang['preload creation success'] = 'Die Farm wurde erfolgreich angelegt.';
+$lang['preload creation error'] = 'Es ist ein Fehler beim Aufsetzen der Farm ausfgetreten.';
+$lang['overwrite_preload'] = 'Achtung: Ihre existierende: inc/preload.php wird überschrieben, wenn Sie diesen hier weitermachen!';
+
+// info
+$lang['animal'] = 'Animal Name / Domain';
+$lang['thisis'] = 'Diese Instanz ist';
+$lang['thisis.farmer'] = 'Der Farmer!';
+$lang['thisis.animal'] = 'Ein Animal!';
+$lang['baseinstall'] = 'Farmer Installation';
+$lang['animals'] = 'Animals';
+$lang['confdir'] = 'Konfigurationsverzeichnis dieser Instanz';
+$lang['savedir'] = 'data-Verzeichnis dieser Instanz';
+$lang['plugins'] = 'In dieser Instanz aktivierte Plugins';
+
+// config
+$lang['base'] = 'Grundkonfiguration';
+$lang['farm host'] = 'Farmer Host Name';
+$lang['base domain'] = 'Basis-Domain für Subdomain-Animals';
+$lang['conf_inherit'] = 'Farmer-Einstellungen die von Animals geerbt werden sollen';
+$lang['conf_inherit_main'] = 'Konfigurationseinstellungen';
+$lang['conf_inherit_acronyms'] = 'Abkürzungs-Definitionen';
+$lang['conf_inherit_entities'] = 'Entity-Definitionionen';
+$lang['conf_inherit_interwiki'] = 'Interwiki-Definitionen';
+$lang['conf_inherit_license'] = 'Lizenz-Definitionen';
+$lang['conf_inherit_mime'] = 'MIME-Type-Definitionen';
+$lang['conf_inherit_scheme'] = 'URL-Scheme-Definitionen';
+$lang['conf_inherit_smileys'] = 'Smiley-Definitionen';
+$lang['conf_inherit_wordblock'] = 'Spamfiltereinträge';
+$lang['conf_inherit_userstyle'] = 'Nutzer-Styles';
+$lang['conf_inherit_userscript'] = 'Nutzer-Scripts';
+$lang['conf_inherit_styleini'] = 'Anpassungen an Template-Styles';
+$lang['conf_inherit_users'] = 'Benutzer (nur Plain Auth)';
+$lang['conf_inherit_plugins'] = 'Plugin-Zustand';
+$lang['conf_inherit_yes'] = 'vom Farmer geerbt';
+$lang['conf_inherit_no'] = 'unabhängig vom Farmer';
+$lang['conf_notfound'] = 'Verhalten bei zugriff auf nicht-existierende Animals';
+$lang['conf_notfound_farmer'] = 'Zeige das Farmer-Wiki';
+$lang['conf_notfound_404'] = 'Zeige eine 404-Fehlerseite';
+$lang['conf_notfound_list'] = 'Zeige eine Liste der existierenden Animals';
+$lang['conf_notfound_redirect'] = 'Leite auf untenstehende URL um';
+$lang['conf_notfound_url'] = 'URL auf die umgeleitet werden soll wenn oben ausgewählt';
+$lang['save'] = 'Speichern';
+
+// new
+$lang['animal template'] = 'Bestehendes Animal kopieren';
+$lang['animal creation success'] = 'Das Animal "%s" wurde erfolgreich angelegt.';
+$lang['animal creation error'] = 'Es gab einen Fehler beim Anlegen des Animals.';
+$lang['animal configuration'] = 'Animal Grundkonfiguration';
+$lang['animal administrator'] = 'Animal Administrator';
+$lang['noUsers'] = 'Keine Benutzer erzeugen';
+$lang['importUsers'] = 'Alle Benutzeraccounts des Farmers in das neue Animal kopieren';
+$lang['currentAdmin'] = 'Den aktuellen Benutzer als Admin setzen';
+$lang['newAdmin'] = 'Neuen Benutzer "admin" anlegen';
+$lang['admin password'] = 'Passwort für den neuen Administrator';
+$lang['animalname_missing'] = 'Bitte geben Sie einen Namen für das neue Animal an.';
+$lang['animalname_invalid'] = ' Der Name des Animals darf nur aus Buchstaben und Ziffern sowie aus Bindestrichen und Punkten (nicht am Anfang oder Ende) bestehen.';
+$lang['animalname_preexisting'] = 'Ein Animal mit diesem Namen existiert bereits.';
+$lang['adminPassword_empty'] = 'Das Passwort für den neuen Administrator darf nicht leer sein.';
+$lang['animal template copy error'] = 'Es gab ein Problem beim Kopieren von %s aus dem existierenden Animal in das neue.';
+
+// plugins
+$lang['bulkSingleSwitcher'] = 'Ein einzelnes Animal bearbeiten oder alle aufeinmal?';
+$lang['bulkEdit'] = 'Alle Animals bearbeiten';
+$lang['singleEdit'] = 'Ein einzelnes Animal bearbeiten';
+$lang['bulkEditForm'] = 'Plugins in allen Animals ein- oder ausschalten';
+$lang['activate'] = 'Aktivieren';
+$lang['deactivate'] = 'Deaktivieren';
+$lang['singleEditForm'] = 'Plugins eines spezifischen Animals bearbeiten';
+$lang['plugindone'] = 'Plugin states updated';
+$lang['plugin'] = 'Plugin';
+$lang['plugin_on'] = 'an';
+$lang['plugin_off'] = 'aus';
+$lang['plugin_default'] = 'Voreinstellung';
+$lang['plugin_enabled'] = 'Aktiviert';
+$lang['plugin_disabled'] = 'Deaktiviert';
+$lang['js']['animalSelect'] = 'Wählen Sie ein Animal';
+$lang['js']['pluginSelect'] = 'Wählen Sie ein Plugin';
+
+// delete
+$lang['delete_animal'] = 'Animal zum Löschen auswählen';
+$lang['delete_confirm'] = 'Name des Animals erneut eingeben, um Löschen zu bestätigen';
+$lang['delete'] = 'Animal und alle darin gespeicherten Daten löschen';
+$lang['delete_noanimal'] = 'Bitte wählen sie ein Animal zum Löschen aus';
+$lang['delete_mismatch'] = 'Bestätigung stimmt nicht mit Animalnamen überein. Nicht gelöscht.';
+$lang['delete_invalid'] = 'Invalider Animalname. Nicht gelöscht.';
+$lang['delete_success'] = 'Animal erfolgreich gelöscht.';
+$lang['delete_fail'] = 'Einige Dateien konnten nicht gelöscht werden. Sie sollten diese manuell entfernen.';
+
+//Setup VIM: ex: et ts=4 :
diff --git a/platform/www/lib/plugins/farmer/lang/de/notfound_404.txt b/platform/www/lib/plugins/farmer/lang/de/notfound_404.txt
new file mode 100644
index 0000000..bac18d9
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/de/notfound_404.txt
@@ -0,0 +1,3 @@
+====== 404 Nicht gefunden ======
+
+Die angeforderte Ressource konnte nicht gefunden werden
diff --git a/platform/www/lib/plugins/farmer/lang/de/notfound_list.txt b/platform/www/lib/plugins/farmer/lang/de/notfound_list.txt
new file mode 100644
index 0000000..300ba7f
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/de/notfound_list.txt
@@ -0,0 +1,3 @@
+====== Wiki nicht gefunden ======
+
+Das angeforderte Wiki konnte nicht gefunden werden. Bitte wählen Sie aus der folgenden Liste der vorhandenen Wikis.
diff --git a/platform/www/lib/plugins/farmer/lang/de/settings.php b/platform/www/lib/plugins/farmer/lang/de/settings.php
new file mode 100644
index 0000000..661a3ec
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/de/settings.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * German language file for farmer plugin
+ *
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+
+// keys need to match the config setting name
+$lang['deactivated plugins'] = 'Kommaseparierte Liste an Plugins die in neuen Animals automatisch deaktiviert werden sollen.';
+
+
+
+//Setup VIM: ex: et ts=4 :
diff --git a/platform/www/lib/plugins/farmer/lang/de/tab_config.txt b/platform/www/lib/plugins/farmer/lang/de/tab_config.txt
new file mode 100644
index 0000000..299c979
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/de/tab_config.txt
@@ -0,0 +1 @@
+Hier können die grundlegenden Eigenschaften der Farm konfiguriert werden. Beachten Sie, dass alle Einstellungen hier alle Animals beeinflussen werden.
diff --git a/platform/www/lib/plugins/farmer/lang/de/tab_delete.txt b/platform/www/lib/plugins/farmer/lang/de/tab_delete.txt
new file mode 100644
index 0000000..795487a
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/de/tab_delete.txt
@@ -0,0 +1 @@
+Sie können bestehende Animals hier löschen. Dies löscht **alle Daten, inklusive Seiten und Medieninhalte** des gewählten Animals. **Dies kann nicht rückgängig gemacht werden!**
diff --git a/platform/www/lib/plugins/farmer/lang/de/tab_info.txt b/platform/www/lib/plugins/farmer/lang/de/tab_info.txt
new file mode 100644
index 0000000..11faab9
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/de/tab_info.txt
@@ -0,0 +1 @@
+Dieses Wiki ist Teil eines Farm-Setups. Nähere Details finden Sie unten.
diff --git a/platform/www/lib/plugins/farmer/lang/de/tab_new.txt b/platform/www/lib/plugins/farmer/lang/de/tab_new.txt
new file mode 100644
index 0000000..a62ef02
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/de/tab_new.txt
@@ -0,0 +1 @@
+Hier können Sie ein neues Animal anlegen.
diff --git a/platform/www/lib/plugins/farmer/lang/de/tab_plugins.txt b/platform/www/lib/plugins/farmer/lang/de/tab_plugins.txt
new file mode 100644
index 0000000..8277c98
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/de/tab_plugins.txt
@@ -0,0 +1 @@
+Hier können Sie Plugins für einzelne oder alle Animals ein- oder ausschalten.
diff --git a/platform/www/lib/plugins/farmer/lang/de/tab_setup.txt b/platform/www/lib/plugins/farmer/lang/de/tab_setup.txt
new file mode 100644
index 0000000..e0dc63b
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/de/tab_setup.txt
@@ -0,0 +1 @@
+Ihr Wiki ist noch nicht für Farming mit dem Farmer-Plugin eingerichtet. Bitte nutzen Sie den folgenden Dialog zum Aufsetzen der Farm.
diff --git a/platform/www/lib/plugins/farmer/lang/en/lang.php b/platform/www/lib/plugins/farmer/lang/en/lang.php
new file mode 100644
index 0000000..da49836
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/lang.php
@@ -0,0 +1,128 @@
+<?php
+/**
+ * English language file for farmer plugin
+ *
+ * @author Michael Große <grosse@cosmocode.de>
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+
+// menu entry for admin plugins
+$lang['menu'] = 'Farming';
+
+// tabs
+$lang['tab_setup'] = 'Farm Setup';
+$lang['tab_info'] = 'Info';
+$lang['tab_config'] = 'Configuration';
+$lang['tab_plugins'] = 'Manage Plugins';
+$lang['tab_new'] = 'Add new Animal';
+$lang['tab_delete'] = 'Delete Animal';
+
+// setup
+$lang['preloadPHPForm'] = 'Initialize Farming';
+$lang['farm dir'] = 'Animal directory';
+$lang['htaccess setup'] = 'Add farm code to .htaccess?';
+$lang['submit'] = 'Submit';
+$lang['farmdir_missing'] = 'Please enter a directory where the Animals should be stored.';
+$lang['farmdir_in_dokuwiki'] = 'The Animal directory (%s) must be outside of the Farm dokuwiki (%s).';
+$lang['farmdir_uncreatable'] = 'The Animal directory (%s) could not be created. Are the permissions correct?';
+$lang['farmdir_unwritable'] = 'Please make sure that the webserver has write access in the Animal directory (%s)!';
+$lang['farmdir_notEmpty'] = 'The Animal directory (%s) must be empty.';
+$lang['preload creation success'] = 'Farming has been succesfully initialized.';
+$lang['preload creation error'] = 'There was an error during Farming initialization.';
+$lang['overwrite_preload'] = 'Warning: Your existing inc/preload.php will be overwritten when continuing here!';
+
+// info
+$lang['animal'] = 'Animal Name / Domain';
+$lang['thisis'] = 'Instance is';
+$lang['thisis.farmer'] = 'The farmer!';
+$lang['thisis.animal'] = 'An Animal!';
+$lang['baseinstall'] = 'Farmer Install';
+$lang['animals'] = 'Animals';
+$lang['confdir'] = 'Instance Configuration Directory';
+$lang['savedir'] = 'Instance Data Directory';
+$lang['plugins'] = 'Plugins active in this instance';
+
+// config
+$lang['base'] = 'Base Configuration';
+$lang['farm host'] = 'Farmer Host Name';
+$lang['base domain'] = 'Base Domain for subdomain Animals';
+$lang['conf_inherit'] = 'Farmer Settings Animals should inherit';
+$lang['conf_inherit_main'] = 'Configuration Settings';
+$lang['conf_inherit_acronyms'] = 'Acronym Definitions';
+$lang['conf_inherit_entities'] = 'Entity Definitions';
+$lang['conf_inherit_interwiki'] = 'Interwiki Definitions';
+$lang['conf_inherit_license'] = 'License Definitions';
+$lang['conf_inherit_mime'] = 'MIME Type Definitions';
+$lang['conf_inherit_scheme'] = 'URL Scheme Definitions';
+$lang['conf_inherit_smileys'] = 'Smiley Definitions';
+$lang['conf_inherit_wordblock'] = 'Spam Blacklist Entries';
+$lang['conf_inherit_userstyle'] = 'User Styles';
+$lang['conf_inherit_userscript'] = 'User Scripts';
+$lang['conf_inherit_styleini'] = 'Template style customizations';
+$lang['conf_inherit_users'] = 'Users (Plain Auth only)';
+$lang['conf_inherit_plugins'] = 'Plugin State';
+$lang['conf_inherit_yes'] = 'inherited from farmer';
+$lang['conf_inherit_no'] = 'independent from farmer';
+$lang['conf_notfound'] = 'Behavior on accessing nonexistent Animals';
+$lang['conf_notfound_farmer'] = 'Show the farmer wiki';
+$lang['conf_notfound_404'] = 'Show a 404 error page';
+$lang['conf_notfound_list'] = 'Show a list of available animals';
+$lang['conf_notfound_redirect'] = 'Redirect to the URL below';
+$lang['conf_notfound_url'] = 'URL to redirect to if selected above';
+$lang['save'] = 'Save';
+
+// new
+$lang['animal template'] = 'Copy existing Animal';
+$lang['animal creation success'] = 'The Animal "%s" has been successfully created.';
+$lang['animal creation error'] = 'There was an error while creating the Animal.';
+$lang['animal configuration'] = 'Basic Animal configuration';
+$lang['inherit user registration'] = 'Inherit user registration setting from farmer';
+$lang['enable user registration'] = 'Allow users to register themselves';
+$lang['disable user registration'] = 'Disable user register';
+$lang['animal administrator'] = 'Animal administrator';
+$lang['noUsers'] = 'Do not create any users';
+$lang['importUsers'] = 'Import all users of the Farmer to the new Animal';
+$lang['currentAdmin'] = 'Set the current user as admin';
+$lang['newAdmin'] = 'Create new admin user "admin"';
+$lang['admin password'] = 'Password for the new admin';
+$lang['animalname_missing'] = 'Please enter a name for the new Animal.';
+$lang['animalname_invalid'] = 'The Animal name may only contain alphanumeric characters and dots/hyphens (but not as first or last character).';
+$lang['animalname_preexisting'] = 'An Animal with that name already exists.';
+$lang['adminPassword_empty'] = 'The password for the new admin account must not be empty.';
+$lang['animal template copy error'] = 'There was a problem copying %s from the existing Animal to the new one.';
+$lang['aclpolicy missing/bad'] = 'Please choose an initial ACL policy from the dropdown.';
+
+// plugins
+$lang['bulkSingleSwitcher'] = 'Edit a single Animal or all at once?';
+$lang['bulkEdit'] = 'Bulk edit all Animals';
+$lang['singleEdit'] = 'Edit a single Animal';
+$lang['bulkEditForm'] = 'Activate or deactivate a plugin in all Animals';
+$lang['matrixEdit'] = 'Edit Animal/Plugin matrix';
+$lang['default'] = 'Set to default';
+$lang['activate'] = 'Activate';
+$lang['deactivate'] = 'Deactivate';
+$lang['singleEditForm'] = 'Edit the plugins of a specific Animal';
+$lang['plugindone'] = 'Plugin states updated';
+$lang['plugin'] = 'Plugin';
+$lang['plugin_on'] = 'on';
+$lang['plugin_off'] = 'off';
+$lang['plugin_default'] = 'Default';
+$lang['plugin_enabled'] = 'Enabled';
+$lang['plugin_disabled'] = 'Disabled';
+$lang['js']['animalSelect'] = 'Select an animal';
+$lang['js']['pluginSelect'] = 'Select a plugin';
+$lang['disable_new_plugins'] = 'The plugin has been disabled by default. You can enable it here or in specific animals only.';
+
+
+// delete
+$lang['delete_animal'] = 'Select Animal to delete';
+$lang['delete_confirm'] = 'Please type the Animal name to confirm';
+$lang['delete'] = 'Delete the Animal and all its data';
+
+$lang['delete_noanimal'] = 'Please select an Animal to delete';
+$lang['delete_mismatch'] = 'Confirmation does not match Animal name. Not deleted.';
+$lang['delete_invalid'] = 'Invalid Animal name. Not deleted.';
+$lang['delete_success'] = 'Animal successfully deleted.';
+$lang['delete_fail'] = 'Some files could not be deleted, you should clean up manuallly.';
+
+//Setup VIM: ex: et ts=4 :
diff --git a/platform/www/lib/plugins/farmer/lang/en/notfound_404.txt b/platform/www/lib/plugins/farmer/lang/en/notfound_404.txt
new file mode 100644
index 0000000..b023e79
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/notfound_404.txt
@@ -0,0 +1,3 @@
+====== 404 Not Found ======
+
+The requested resource could not be found.
diff --git a/platform/www/lib/plugins/farmer/lang/en/notfound_list.txt b/platform/www/lib/plugins/farmer/lang/en/notfound_list.txt
new file mode 100644
index 0000000..9e4633a
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/notfound_list.txt
@@ -0,0 +1,3 @@
+====== Wiki Not Found ======
+
+The requested Wiki could not be found. Please refer to the list of available Wikis below.
diff --git a/platform/www/lib/plugins/farmer/lang/en/settings.php b/platform/www/lib/plugins/farmer/lang/en/settings.php
new file mode 100644
index 0000000..0e854ac
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/settings.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * english language file for farmer plugin
+ *
+ * @author Michael Große <grosse@cosmocode.de>
+ */
+
+// keys need to match the config setting name
+$lang['deactivated plugins'] = 'Comma-separated list of plugins which are deactivated by default in new animals.';
+$lang['disable_new_plugins'] = 'Automatically disable plugins after they have been newly installed in the farmer? (only when installed via extension manager)';
+
+
+//Setup VIM: ex: et ts=4 :
diff --git a/platform/www/lib/plugins/farmer/lang/en/tab_config.txt b/platform/www/lib/plugins/farmer/lang/en/tab_config.txt
new file mode 100644
index 0000000..cedf536
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/tab_config.txt
@@ -0,0 +1 @@
+Here the basic behavior of the farm is configured. Please be aware that changing options here will affect all animals.
diff --git a/platform/www/lib/plugins/farmer/lang/en/tab_config_help.txt b/platform/www/lib/plugins/farmer/lang/en/tab_config_help.txt
new file mode 100644
index 0000000..0ebf7c2
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/tab_config_help.txt
@@ -0,0 +1,26 @@
+===== Farm Configuration =====
+
+All settings made here are saved to the Farmer's ''conf/farm.ini''.
+
+==== Base Configuration ====
+
+The **Farmer's host name** was set automatically during the setup, but you can change it here. It
+will be used to detect if a request was made directly to the Farmer when using host based farms. This
+should be a full qualified hostname (''foo.example.com'' instead of just ''foo'').
+
+When using a subdomain wildcard setup you should specify the main domain in the **Base Domain** setting.
+Eg. if you specify ''example.com'' it is assumed an animal named ''foo'' is reachable via ''foo.example.com''.
+The base domain is only appended to animal names not containing any dots.
+
+==== Inheritence ====
+
+Here you can specify what configuration settings made in the farmer should be used as defaults in the animals.
+Animals can still override the Farmer settings in their own configuration files. When inheritance is disabled,
+DokuWiki's default settings are the defaults for all animals as well.
+
+==== Non Existing Animals ====
+
+By default, when accessing a non-existing animal no error message is shown. You can pick between different
+behavior here. Be sure that your Farmer's host name is set up correctly above, before switching away from the
+default.
+
diff --git a/platform/www/lib/plugins/farmer/lang/en/tab_delete.txt b/platform/www/lib/plugins/farmer/lang/en/tab_delete.txt
new file mode 100644
index 0000000..cd7f67c
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/tab_delete.txt
@@ -0,0 +1 @@
+You can delete existing animals here. This deletes **all data, including pages and media files** of the selected animal. **This is irreversible!**
diff --git a/platform/www/lib/plugins/farmer/lang/en/tab_info.txt b/platform/www/lib/plugins/farmer/lang/en/tab_info.txt
new file mode 100644
index 0000000..f3d7a83
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/tab_info.txt
@@ -0,0 +1 @@
+This wiki is part of a farm setup. Check the details below.
diff --git a/platform/www/lib/plugins/farmer/lang/en/tab_new.txt b/platform/www/lib/plugins/farmer/lang/en/tab_new.txt
new file mode 100644
index 0000000..ffe899c
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/tab_new.txt
@@ -0,0 +1 @@
+You can create a new animal here.
diff --git a/platform/www/lib/plugins/farmer/lang/en/tab_new_help.txt b/platform/www/lib/plugins/farmer/lang/en/tab_new_help.txt
new file mode 100644
index 0000000..0445e82
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/tab_new_help.txt
@@ -0,0 +1,31 @@
+===== Animal Creation =====
+
+Animals are the independent subwikis of a Dokuwiki farm. To create a new animal a name has to be assigned.
+
+==== Animal Names ====
+
+For .htaccess based setups this should be a single word. For domain based setups you should provide either a full qualified domain name.
+If you use a wildcard subdomain setup you can also just provide the hostname part if you set a base domain in the configuration.
+
+Examples:
+
+ * .htaccess based: ''foo'' for an animal accessible at ''%%http://example.org/dokuwiki/!foo/%%''
+ * domain based: ''%%www.foo.com%%'' for an animal accessible at ''%%http://www.foo.com/%%''
+ * sub domain based: ''foo'' for an animal accessible at ''%%http://foo.example.com/%%''
+
+The latter two require the appropriate DNS setup!
+
+==== Copy Animal ====
+
+You can select an existing animal to base the new one on. All configuration, page, media and meta data will be copied
+to the new animal. Page and media revisions will not be copied.
+
+The title and logo image will be overwritten to make sure you can distinguish the new from the old wiki.
+
+==== Animal Administrator ====
+
+The Animal will be a fully functional wiki with it's own user base. You will need at least one administrative user
+to configure it. You can copy your current user or all users from the farmer or create a completely new user for the Animal.
+
+You can choose to not create any users. This should only be chosen when inheriting users from the Farmer was enabled in the
+configuration tab or you copied a different animal with existing users.
diff --git a/platform/www/lib/plugins/farmer/lang/en/tab_plugins.txt b/platform/www/lib/plugins/farmer/lang/en/tab_plugins.txt
new file mode 100644
index 0000000..78e8021
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/tab_plugins.txt
@@ -0,0 +1 @@
+You can activate or deactivate either a plugin for all animals in a single bulk operation or you can edit the plugins of a specific animal.
diff --git a/platform/www/lib/plugins/farmer/lang/en/tab_plugins_help.txt b/platform/www/lib/plugins/farmer/lang/en/tab_plugins_help.txt
new file mode 100644
index 0000000..44af5fc
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/tab_plugins_help.txt
@@ -0,0 +1,16 @@
+===== Plugin Management =====
+
+The extension manager is disabled in all Animals. Plugins can only be installed in the Farmer and only the Farmer
+may control what plugins are enabled or disabled in all Animals. This is done through this interface.
+
+A plugin can have three states in an Animal. It can be enabled (on) or disabled (off), or it can have the default state. The
+default means that the state of a Plugin was not explicitly set for an Animal. Normally the default state is on.
+
+When Animals are configured to inherit the Plugin state of the Farmer, a plugin in default state will have the same
+state as in the Farmer. Eg. when you disable a plugin in the Farmer it will disable the plugin for all Animals which
+did not have the state of this plugin explicitly set.
+
+There are three ways to manage plugins: You can either pick a single plugin and set its state to the same value in all animals
+or you can pick a specific animal and configure all the plugin states within that animal only. The third option allows you to
+see and edit the state of all plugins in all animals at once. This option may not be feasible of you have a large amount
+of animals.
diff --git a/platform/www/lib/plugins/farmer/lang/en/tab_setup.txt b/platform/www/lib/plugins/farmer/lang/en/tab_setup.txt
new file mode 100644
index 0000000..19ae730
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/tab_setup.txt
@@ -0,0 +1 @@
+Your Wiki is not set up as a farm managed by the Farmer Plugin, yet. Please use the wizard below to enable farming.
diff --git a/platform/www/lib/plugins/farmer/lang/en/tab_setup_help.txt b/platform/www/lib/plugins/farmer/lang/en/tab_setup_help.txt
new file mode 100644
index 0000000..f81532f
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/en/tab_setup_help.txt
@@ -0,0 +1,37 @@
+===== About Farms =====
+
+Farms allow you to have a single DokuWiki installation (The "Farmer") that powers an arbitrary number of
+other wikis (The "Animals"). You install plugins and templates in the Farmer only and then make them available
+through to the animals. You only need to keep one wiki uptodate and all other wikis just use the same code base.
+
+After completing this setup step your current DokuWiki (the one you're looking at) will be known as the "Farmer".
+
+===== What does this Setup do? =====
+
+This setup wizard will do three things:
+
+ - create a ''inc/preload.php'' file
+ - create a ''conf/farm.ini'' file
+ - optionally append to the ''.htaccess'' file
+
+The ''preload.php'' is a file that is loaded at the very beginning of loading DokuWiki. Here the farm mechanism is
+inititialized. The Farmer plugin will detect if the current request should access an Animal or the Farmer and
+reconfigure everything accordingly.
+
+The ''conf/farm.ini'' contains the basic configuration of the farm setup. Most importantly it will contain the
+location where all the animal's data will be stored.
+
+The ''.htaccess'' modification makes animals accessible through the //bang!// mechanism. (See below)
+
+===== What to fill in? =====
+
+The **Animal Directory** is where a new directory is created for each Animal you create. This directory has to be
+outside your current DokuWiki. You can specify a relative directory like ''../animals''.
+
+Enabling the **.htaccess** support is recommended. This feature requires Apache with mod_rewrite and .htaccess support.
+
+When enabled, your animals will be accessible under the farmer's URL using the //bang!// mechanism. Eg. if your farmer is
+running at ''%%http://www.example.com/dokuwiki/%%'', an animal will be accessible at
+''%%http://www.example.com/dokuwiki/!animal%%''.
+
+If you do not enable this, you will have to configure your Webserver and DNS to access the animals.
diff --git a/platform/www/lib/plugins/farmer/lang/fr/lang.php b/platform/www/lib/plugins/farmer/lang/fr/lang.php
new file mode 100644
index 0000000..8171952
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/lang.php
@@ -0,0 +1,109 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Schplurtz le Déboulonné <schplurtz@laposte.net>
+ * @author ubibene <services.m@benard.info>
+ */
+$lang['menu'] = 'Élevage';
+$lang['tab_setup'] = 'Configuration de la ferme';
+$lang['tab_info'] = 'Info';
+$lang['tab_config'] = 'Configuration';
+$lang['tab_plugins'] = 'Gestion des greffons';
+$lang['tab_new'] = 'Ajouter un animal';
+$lang['tab_delete'] = 'Supprimer un animal';
+$lang['preloadPHPForm'] = 'Initialiser la ferme';
+$lang['farm dir'] = 'Dossier des animaux';
+$lang['htaccess setup'] = 'Ajouter le code d\'élevage au .htaccess ?';
+$lang['submit'] = 'Envoyer';
+$lang['farmdir_missing'] = 'Veuillez entrer un dossier où stocker les animaux.';
+$lang['farmdir_in_dokuwiki'] = 'Le dossier des animaux (%s) doit se trouver hors de la ferme DokuWiki (%s).';
+$lang['farmdir_uncreatable'] = 'Impossible de créer le dossier (%s). Les permissions sont-elles correctes ?';
+$lang['farmdir_unwritable'] = 'Veuillez vous assurer que le serveur web dispose d\'un accès en écriture au dossier des animaux (%s) !';
+$lang['farmdir_notEmpty'] = 'Le dossier des animaux (%s) doit être vide.';
+$lang['preload creation success'] = 'Configuration de la ferme réalisée.';
+$lang['preload creation error'] = 'Il y a eu une erreur lors de l\'initialisation de l\'élevage.';
+$lang['overwrite_preload'] = 'Attention, votre fichier existant inc/preload.php va être écrasé si vous continuez !';
+$lang['animal'] = 'Nom d\'animal / Domaine';
+$lang['thisis'] = 'L\'instance est';
+$lang['thisis.farmer'] = 'Le fermier!';
+$lang['thisis.animal'] = 'Un animal!';
+$lang['baseinstall'] = 'Installation de la ferme';
+$lang['animals'] = 'Animaux';
+$lang['confdir'] = 'Dossier de configuration de l\'instance';
+$lang['savedir'] = 'Dossier des données de l\'instance';
+$lang['plugins'] = 'Greffons actifs dans cette instance';
+$lang['base'] = 'Configuration de base';
+$lang['farm host'] = 'Nom d\'hôte du fermier';
+$lang['base domain'] = 'Domaine de base pour les animaux par sous-domaine';
+$lang['conf_inherit'] = 'Réglage dont les animaux vont hériter';
+$lang['conf_inherit_main'] = 'Options de configuraton';
+$lang['conf_inherit_acronyms'] = 'Définitions des acronymes';
+$lang['conf_inherit_entities'] = 'Définitions des entités';
+$lang['conf_inherit_interwiki'] = 'Liens interwiki';
+$lang['conf_inherit_license'] = 'Licence du contenu';
+$lang['conf_inherit_mime'] = 'Types MIME';
+$lang['conf_inherit_scheme'] = 'Schémas d\'URL';
+$lang['conf_inherit_smileys'] = 'Frimousses';
+$lang['conf_inherit_wordblock'] = 'Liste noire des spammeurs';
+$lang['conf_inherit_userstyle'] = 'Styles utilisateur';
+$lang['conf_inherit_userscript'] = 'Scripts utilisateur';
+$lang['conf_inherit_styleini'] = 'Personnalisations du style du thème ';
+$lang['conf_inherit_users'] = 'utilisateurs (Auth texte seulement)';
+$lang['conf_inherit_plugins'] = 'État des greffons';
+$lang['conf_inherit_yes'] = 'hérité du fermier';
+$lang['conf_inherit_no'] = 'indépendant du fermier';
+$lang['conf_notfound'] = 'Comportement lors d\'un accès à un animal inexistant';
+$lang['conf_notfound_farmer'] = 'Montrer le wiki fermier';
+$lang['conf_notfound_404'] = 'Montrer une page 404';
+$lang['conf_notfound_list'] = 'Montrer la liste des animaux disponibles';
+$lang['conf_notfound_redirect'] = 'Rediriger vers l\'URL ci-dessous';
+$lang['conf_notfound_url'] = 'URL de redirection si sélectionné ci-dessus';
+$lang['save'] = 'Enregistrer';
+$lang['animal template'] = 'Copier un animal existant';
+$lang['animal creation success'] = 'L\'animal "%s" a été créé avec succès.';
+$lang['animal creation error'] = 'Il y a eu une erreur lors de la création de l\'animal.';
+$lang['animal configuration'] = 'Configuration de base de l\'animal';
+$lang['inherit user registration'] = 'Hériter le réglage d\'enregistrement des utilisateurs.';
+$lang['enable user registration'] = 'Autoriser les utilisateurs à s\'enregistrer';
+$lang['disable user registration'] = 'Désactiver l\'enregistrement des utilisateurs';
+$lang['animal administrator'] = 'Administrateur d\'animal';
+$lang['noUsers'] = 'Ne pas créer d\'utilisateur';
+$lang['importUsers'] = 'Exporter les utilisateurs du fermier vers l\'animal';
+$lang['currentAdmin'] = 'Définir l\'utilisateur courant comme admin';
+$lang['newAdmin'] = 'Créer un nouvel administrateur "admin"';
+$lang['admin password'] = 'Mot de passe du nouvel admin';
+$lang['animalname_missing'] = 'Veuillez saisir le nom du nouvel animal.';
+$lang['animalname_invalid'] = 'Le nom de l\'animal ne doit contenir que des caractères alphanumériques et les points et tirets (mais pas en premier ou en dernier).';
+$lang['animalname_preexisting'] = 'Un animal avec ce nom existe déjà.';
+$lang['adminPassword_empty'] = 'Le mot de passe du nouvel administrateur ne peux pas être vide.';
+$lang['animal template copy error'] = 'Il y a eu un problème en copiant %s de l\'animal existant vers le nouveau.';
+$lang['aclpolicy missing/bad'] = 'Veuillez choisir une politique d\'ACL initiale.';
+$lang['bulkSingleSwitcher'] = 'Modifier un seul animal ou tout le troupeau ?';
+$lang['bulkEdit'] = 'Modifier tout le troupeau';
+$lang['singleEdit'] = 'Modifier un seul animal';
+$lang['bulkEditForm'] = 'Activer ou désactiver un greffon sur tout le troupeau.';
+$lang['matrixEdit'] = 'Modifier la matrice Animal/Greffon';
+$lang['default'] = 'Hériter du fermier';
+$lang['activate'] = 'Activer';
+$lang['deactivate'] = 'Désactiver';
+$lang['singleEditForm'] = 'Éditer les greffons d\'un animal particulier';
+$lang['plugindone'] = 'État du greffon mis à jour';
+$lang['plugin'] = 'Greffon';
+$lang['plugin_on'] = 'marche';
+$lang['plugin_off'] = 'arrêt';
+$lang['plugin_default'] = 'Herité';
+$lang['plugin_enabled'] = 'Activé';
+$lang['plugin_disabled'] = 'Désactivé';
+$lang['js']['animalSelect'] = 'Sélectionnez un animal';
+$lang['js']['pluginSelect'] = 'Sélectionnez un greffon';
+$lang['disable_new_plugins'] = 'Le greffon est par défaut désactivé. Vous pouvez l\'activer ici ou pour certains animaux spécifiques seulement.';
+$lang['delete_animal'] = 'Sélectionnez l\'animal à détruire';
+$lang['delete_confirm'] = 'Veuillez taper le nom de l\'animal pour confirmer';
+$lang['delete'] = 'Détruire l\'animal et toutes ses données';
+$lang['delete_noanimal'] = 'Veuillez sélectionner l\'animal à détruire';
+$lang['delete_mismatch'] = 'La confirmation ne correspond pas à l\'animal. Destruction annulée.';
+$lang['delete_invalid'] = 'Nom d\'animal invalide. Destruction annulée';
+$lang['delete_success'] = 'Animal supprimé avec succès.';
+$lang['delete_fail'] = 'Impossible de supprimer certains fichiers. Vous devriez faire le ménage à la main.';
diff --git a/platform/www/lib/plugins/farmer/lang/fr/notfound_404.txt b/platform/www/lib/plugins/farmer/lang/fr/notfound_404.txt
new file mode 100644
index 0000000..5aaa62d
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/notfound_404.txt
@@ -0,0 +1,3 @@
+====== 404 Non trouvé ======
+
+La ressource demandée ne peut être trouvée.
diff --git a/platform/www/lib/plugins/farmer/lang/fr/notfound_list.txt b/platform/www/lib/plugins/farmer/lang/fr/notfound_list.txt
new file mode 100644
index 0000000..3a6acc7
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/notfound_list.txt
@@ -0,0 +1,4 @@
+====== Wiki non trouvé ======
+
+Impossible de trouver le wiki que vous avez demandé. Veuillez
+vous référer à la liste ci-dessous.
diff --git a/platform/www/lib/plugins/farmer/lang/fr/settings.php b/platform/www/lib/plugins/farmer/lang/fr/settings.php
new file mode 100644
index 0000000..ed4465c
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/settings.php
@@ -0,0 +1,9 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Schplurtz le Déboulonné <Schplurtz@laposte.net>
+ */
+$lang['deactivated plugins'] = 'Liste à virgule des greffons qui sont désactivés par défaut dans les nouveaux animaux.';
+$lang['disable_new_plugins'] = 'Désactiver automatiquement les greffons après qu\'il sont installés dans le fermier. Valable seulement pour les greffons installés par le gestionnaire d\'extensions.';
diff --git a/platform/www/lib/plugins/farmer/lang/fr/tab_config.txt b/platform/www/lib/plugins/farmer/lang/fr/tab_config.txt
new file mode 100644
index 0000000..edee83f
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/tab_config.txt
@@ -0,0 +1 @@
+Ici, le comportement de base de la ferme est configurée. Veuillez garder à l'esprit que changer des options ici affecte tous les animaux.
diff --git a/platform/www/lib/plugins/farmer/lang/fr/tab_config_help.txt b/platform/www/lib/plugins/farmer/lang/fr/tab_config_help.txt
new file mode 100644
index 0000000..28790e4
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/tab_config_help.txt
@@ -0,0 +1,37 @@
+===== Configuration de la ferme =====
+
+Tous les réglages faits ici sont enregistrés dans le fichier ''conf/farm.ini'' du fermier.
+
+==== Configuration de base ====
+
+Le réglage de **Nom d'hôte du fermier** a été effectué automatiquement
+pendant l'initialisation, mais on peut le changer ici. Il sera utilisé
+pour déterminer si une requête est dirigée directement vers le fermier,
+lors de l'utilisation d'une ferme par nom. Ce devrait être un FQDN,
+''toto.example.com'' au lieu de simplement ''toto''.
+
+Lors de l'utilisation d'une configuration avec sous domaine
+générique((//wildcard subdomain//)), vous devez spécifier le
+nom principal dans le réglage **Domaine de base pour les animaux
+par sous domaine**. Par exemple, si vous indiquez ''example.com'',
+on part du principe qu'un animal nommé ''toto'' est joignable via
+''toto.example.com''. Le **Domaine de base** est simplement ajouté aux
+noms des animaux ne contenant aucun point.
+
+==== Héritage ====
+
+Vous pouvez indiquer ici quels réglages de configuration réalisés dans
+le fermier devraient être utilisés comme défaut dans les animaux.
+les animaux peuvent toujours écraser ces réglages dans leurs propres
+fichiers de configuration. Lorsque l'héritage est désactivé, les
+valeurs par défaut de DokuWiki sont également les valeurs par défaut
+pour les nouveaux animaux.
+
+==== Animaux non existant ====
+
+Par défaut, lors d'une tentative d'accès à un animal inexistant,
+aucun message d'erreur n'est affiché. Ici, vous pouvez choisir entre
+différents comportements. Assurez vous que le nom d'hôte du fermier
+soit correctement réglé ci-dessus avant de vous écarter des valeurs
+par défaut.
+
diff --git a/platform/www/lib/plugins/farmer/lang/fr/tab_delete.txt b/platform/www/lib/plugins/farmer/lang/fr/tab_delete.txt
new file mode 100644
index 0000000..73fb7ff
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/tab_delete.txt
@@ -0,0 +1 @@
+Vous pouvez détruire les animaux existant ici. Cela détruit **toutes les données, y compris les pages et médias** des animaux sélectionnés. **Ceci est irréversible** !
diff --git a/platform/www/lib/plugins/farmer/lang/fr/tab_info.txt b/platform/www/lib/plugins/farmer/lang/fr/tab_info.txt
new file mode 100644
index 0000000..e1a4ee0
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/tab_info.txt
@@ -0,0 +1 @@
+Ce wiki fait partie d'une ferme. Consultez les détails ci-dessous.
diff --git a/platform/www/lib/plugins/farmer/lang/fr/tab_new.txt b/platform/www/lib/plugins/farmer/lang/fr/tab_new.txt
new file mode 100644
index 0000000..269260d
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/tab_new.txt
@@ -0,0 +1 @@
+Vous pouvez créer un nouvel animal ici.
diff --git a/platform/www/lib/plugins/farmer/lang/fr/tab_new_help.txt b/platform/www/lib/plugins/farmer/lang/fr/tab_new_help.txt
new file mode 100644
index 0000000..7405a3b
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/tab_new_help.txt
@@ -0,0 +1,43 @@
+===== Création d'animaux =====
+
+Les animaux sont des sous-wikis indépendants d'une ferme de DokuWiki. Pour créer un nouvel animal, il faut lui assigner un nom.
+
+==== Les noms d'animaux ====
+
+Pour les fermes basées sur la réécriture par fichier .htaccess
+cela devrait être un seul mot.
+Pour les configurations basées sur les noms de domaine vous devriez indiquer
+un nom de domaine totalement qualifié (FQDN).
+Pour les fermes à base de sous domaine générique((//wildcard subdomain//
+en bon anglais)), un nom d'hôte suffit, à condition
+d'indiquer également un domaine de base.
+
+Exemples:
+
+ * basé sur .htaccess : ''toto'' pour un animal accessible à ''%%http://example.org/dokuwiki/!toto/%%''
+ * basé sur le domaine : ''%%www.toto.com%%'' pour un animal accessible à ''%%http://www.toto.com/%%''
+ * basé sur le sous domaine : ''toto'' pour un animal accessible à ''%%http://toto.example.com/%%''
+
+Les deux derniers nécessitent un réglage du DNS approprié !
+
+==== Copie d'animal ====
+
+Vous pouvez sélectionner un animal existant comme base d'un
+nouvel animal. Toute la configuration, toutes les pages et fichiers
+médias, ainsi que les méta données seront copiés vers le nouvel
+animal. L'historique des pages et médias ne sera pas copié.
+
+Le titre et l'image de logo seront modifiés de manière à être certain
+que vous pourrez distinguer la nouvelle copie de l'ancien.
+
+==== Administrateur de l'animal ====
+
+L'animal sera un wiki complètement fonctionnel, avec sa propre base
+d'utilisateurs. Vous aurez besoin d'au moins un administrateur pour le
+gérer. Vous pouvez copier l'utilisateur courant, tous les utilisateurs
+du fermier, ou créer un tout nouvel utilisateur pour l'animal.
+
+Vous pouvez choisir de ne pas créer d'utilisateur. Vous ne devriez
+choisir cette possibilité que si l'héritage d'utilisateurs du fermier
+est activé dans l'onglet de configuration, ou si vous avez copié un
+animal déjà muni d'utilisateurs.
diff --git a/platform/www/lib/plugins/farmer/lang/fr/tab_plugins.txt b/platform/www/lib/plugins/farmer/lang/fr/tab_plugins.txt
new file mode 100644
index 0000000..f7c49e5
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/tab_plugins.txt
@@ -0,0 +1 @@
+Vous pouvez activer ou désactiver soit un même greffon pour tous les animaux en une seule opération de masse, soit les greffons d'un animal particulier.
diff --git a/platform/www/lib/plugins/farmer/lang/fr/tab_plugins_help.txt b/platform/www/lib/plugins/farmer/lang/fr/tab_plugins_help.txt
new file mode 100644
index 0000000..179ab63
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/tab_plugins_help.txt
@@ -0,0 +1,22 @@
+===== Gestion des greffons =====
+
+Le gestionnaire d'extensions est désactivé dans tous les animaux. On peut
+uniquement installer les thèmes et greffons dans le fermier.
+Seul le fermier peut contrôler quels greffons
+sont activés dans les animaux. La présente interface permet d'effectuer
+ces réglages.
+
+Un greffon peut avoir trois états dans un animal. Il peut être activé, ou désactivé. Il peut également avoir l'état par défaut. Cette dernière option signifie que l'état du greffon n'est pas explicitement choisi pour un animal. Habituellement, l'état par défaut est <<activé>>.
+
+Lorsque les animaux sont configurés pour hériter l'état du fermier, un
+greffon dans l'état par défaut aura le même état que dans le fermier.
+C'est à dire que désactiver un greffon dans le fermier le désactivera
+aussi dans tous les animaux pour lesquels l'état du greffon n'a pas été
+explicitement spécifié. Si vous l'activez à nouveau dans le fermier,
+le greffon s'activera de la même manière dans tous les animaux
+concernés.
+
+Il existe trois manières de gérer les greffons :
+ - Choisir un greffon et fixer son état à la même valeur dans tous les animaux,
+ - Choisir un animal particulier et gérer l'état de chacun de ses greffons.
+ - Voir et éditer l'état de tous les greffons dans tous les animaux d'un seul coup. Cette option pourrait ne pas être praticable si vous avez un grand nombre d'animaux.
diff --git a/platform/www/lib/plugins/farmer/lang/fr/tab_setup.txt b/platform/www/lib/plugins/farmer/lang/fr/tab_setup.txt
new file mode 100644
index 0000000..f6dbdb3
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/tab_setup.txt
@@ -0,0 +1 @@
+Votre Wiki est pas configuré pour l'élevage avec le greffon //farmer//. Veuillez utiliser la boîte de dialogue suivante pour la mise en place de la ferme.
diff --git a/platform/www/lib/plugins/farmer/lang/fr/tab_setup_help.txt b/platform/www/lib/plugins/farmer/lang/fr/tab_setup_help.txt
new file mode 100644
index 0000000..66a3ccc
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/fr/tab_setup_help.txt
@@ -0,0 +1,52 @@
+===== À propos de l'élevage =====
+
+L'élevage est une technique qui permet, à partir d'une unique
+installation de DokuWiki, connue comme le <<fermier>>, de propulser
+un nombre quelconque d'autres wikis appelés les animaux. Vous installez les
+greffons et thèmes uniquement dans le fermier, et les rendez disponibles
+à votre guise dans des animaux. Il suffit de mettre à jour le wiki principal et
+tous les autres wikis, qui partagent la même base de code, sont également mis
+à jour.
+
+Après avoir complété cette étape de configuration, votre wiki actuel,
+celui que vous lisez en ce moment même, sera connu comme le <<fermier>>.
+
+===== Que fait cette initialisation ? =====
+
+Cet assistant de configuration fera trois choses :
+
+ - Créer un fichier ''inc/preload.php'',
+ - créer un fichier ''conf/farm.ini''
+ - facultativement, ajouter un fichier ''.htaccess''.
+
+''preload.php'' est un fichier qui est chargé au tout début du chargement de DokuWiki.
+Là, le mécanisme de ferme est initialisé. Le greffon //farmer// détectera si la requête
+doit être adressée à un animal ou au fermier, et reconfigurera l'ensemble de manière
+appropriée.
+
+''conf/farm.ini'' contient les configurations de base du système de ferme. En particulier,
+ce fichier contient l'emplacement où les données des animaux seront
+enregistrées.
+
+La modification du fichier ''.htaccess'' permet de rendre accessible les animaux via
+le mécanisme ''!bang'' (voir ci-dessous).
+
+===== Que remplir ? =====
+
+Le **Dossier des animaux** est le dossier où un nouveau dossier est créé pour
+chaque nouvel animal. Ce dossier **doit** se trouver en dehors de l'arborescence
+de votre DokuWiki actuel. Vous pouvez utiliser un dossier relatif, tel que
+''../animaux'' ou un chemin absolu.
+
+Il est recommandé d'activer l'utilisation du fichier ''.htaccess''. Cette fonctionnalité
+nécessite un serveur [[https://httpd.apache.org/|Apache]] avec le module
+mod_rewrite et la prise en charge des fichiers .htaccess.
+
+Lorsque vous activez le .htaccess, les animaux sont accessibles sous l'URL du
+wiki fermier en utilisant le suffixe //!bang//. Par exemple, si votre fermier
+est accessible à l'URL
+''%%http://www.example.com/dokuwiki/%%'', l'animal toto sera accessible à
+l'URL ''%%http://www.example.com/dokuwiki/!toto%%''.
+
+Si vous n'activez pas ce mécanisme, vous devrez configurer votre serveur web
+et votre DNS pour pouvoir accéder aux animaux.
diff --git a/platform/www/lib/plugins/farmer/lang/ja/lang.php b/platform/www/lib/plugins/farmer/lang/ja/lang.php
new file mode 100644
index 0000000..f837a3a
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/lang.php
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Hideaki SAWADA <chuno@live.jp>
+ */
+$lang['menu'] = '牧場設定';
+$lang['tab_setup'] = '牧場設定';
+$lang['tab_info'] = '情報';
+$lang['tab_config'] = '設定';
+$lang['tab_plugins'] = 'プラグイン管理';
+$lang['tab_new'] = '新しい動物の追加';
+$lang['tab_delete'] = '動物の削除';
+$lang['preloadPHPForm'] = '牧場の初期化';
+$lang['farm dir'] = '動物用ディレクトリ';
+$lang['htaccess setup'] = '.htaccess に牧場用のコードを追加しますか?';
+$lang['submit'] = '実行';
+$lang['farmdir_missing'] = '動物を保存するディレクトリを入力してください。';
+$lang['farmdir_in_dokuwiki'] = '動物用ディレクトリは牧場 dokuwiki の外にある必要があります。';
+$lang['farmdir_uncreatable'] = '動物用ディレクトリを作成できませんでした。権限は適切ですか?';
+$lang['farmdir_unwritable'] = 'Web サーバが動物用ディレクトリに書き込み権を持っていることを確認してください!';
+$lang['farmdir_notEmpty'] = '動物用ディレクトリは空でなければなりません。';
+$lang['preload creation success'] = '牧場は正常に初期化されました。';
+$lang['preload creation error'] = '牧場の初期化中にエラーが発生しました。';
+$lang['overwrite_preload'] = '警告:続行すると、既存の inc/preload.php が上書きされます!';
+$lang['animal'] = '動物名・ドメイン';
+$lang['thisis'] = 'インスタンスは';
+$lang['thisis.farmer'] = '牧場主です!';
+$lang['thisis.animal'] = '動物です!';
+$lang['baseinstall'] = '牧場主のインストール先';
+$lang['animals'] = '動物';
+$lang['confdir'] = 'インスタンスの設定ディレクトリ';
+$lang['savedir'] = 'インスタンスのデータディレクトリ';
+$lang['plugins'] = 'このインスタンスで有効なプラグイン';
+$lang['base'] = '基本設定';
+$lang['farm host'] = '牧場主ホスト名';
+$lang['base domain'] = '動物サブドメイン用のベースドメイン';
+$lang['conf_inherit'] = '動物が継承する牧場主設定';
+$lang['conf_inherit_main'] = 'DokuWiki 設定';
+$lang['conf_inherit_acronyms'] = '略字と頭字語';
+$lang['conf_inherit_entities'] = '記号への変換';
+$lang['conf_inherit_interwiki'] = 'InterWiki リンク';
+$lang['conf_inherit_license'] = 'ライセンス';
+$lang['conf_inherit_mime'] = 'MIME の設定';
+$lang['conf_inherit_scheme'] = 'URL スキーム';
+$lang['conf_inherit_smileys'] = 'スマイリー';
+$lang['conf_inherit_wordblock'] = 'ブラックリスト';
+$lang['conf_inherit_userstyle'] = 'ユーザースタイル';
+$lang['conf_inherit_users'] = 'ユーザー(テキスト認証の場合のみ)';
+$lang['conf_inherit_plugins'] = 'プラグインの状態';
+$lang['conf_inherit_yes'] = '牧場主から継承';
+$lang['conf_inherit_no'] = '牧場主から独立';
+$lang['conf_notfound'] = '実在しない動物へのアクセス時の動作';
+$lang['conf_notfound_farmer'] = '牧場主を表示';
+$lang['conf_notfound_404'] = '404 エラーページを表示';
+$lang['conf_notfound_list'] = '利用可能な動物一覧を表示';
+$lang['conf_notfound_redirect'] = '以下の URL へ転送';
+$lang['conf_notfound_url'] = '上記選択した場合、転送先の URL';
+$lang['save'] = '保存';
+$lang['animal template'] = '既存の動物をコピーする';
+$lang['animal creation success'] = '動物 "%s" は正常に作成されました。';
+$lang['animal creation error'] = '動物の作成中にエラーが発生しました。';
+$lang['animal configuration'] = '基本的な動物設定';
+$lang['inherit user registration'] = '牧場主からユーザー登録設定を継承する';
+$lang['enable user registration'] = '自分でユーザー登録することを許可する';
+$lang['disable user registration'] = 'ユーザー登録を無効化する';
+$lang['animal administrator'] = '動物の管理者';
+$lang['noUsers'] = 'ユーザーを作成しない';
+$lang['importUsers'] = '牧場主の全てのユーザーを新しい動物に入力する';
+$lang['currentAdmin'] = '現在のユーザーを admin として設定する';
+$lang['newAdmin'] = '新しい管理者ユーザー "admin" を作成する';
+$lang['admin password'] = '新しい管理者のパスワード';
+$lang['animalname_missing'] = '新しい動物の名前を入力してください。';
+$lang['animalname_invalid'] = '動物の名前には、英数字とドット・ハイフン(最初または最後の文字以外)のみを使用できます。';
+$lang['animalname_preexisting'] = 'その名前の動物はすでに存在しています。';
+$lang['adminPassword_empty'] = '新しい管理者アカウントのパスワードは空ではいけません。';
+$lang['animal template copy error'] = '既存の動物から %s をコピーする際に問題が発生しました。';
+$lang['aclpolicy missing/bad'] = 'ドロップダウンから最初の ACL ポリシーを選択してください。';
+$lang['bulkSingleSwitcher'] = '特定の動物を設定しますか?全動物を一括設定しますか?';
+$lang['bulkEdit'] = '全動物を一括設定する';
+$lang['singleEdit'] = '特定の動物を設定する';
+$lang['bulkEditForm'] = '特定のプラグインを全動物一括で設定する';
+$lang['matrixEdit'] = '一覧(動物×プラグイン)で設定する';
+$lang['default'] = 'デフォルト値を設定';
+$lang['activate'] = '有効化';
+$lang['deactivate'] = '無効化';
+$lang['singleEditForm'] = '特定の動物のプラグインを設定する';
+$lang['plugindone'] = 'プラグインの状態は更新されました';
+$lang['plugin'] = 'プラグイン';
+$lang['plugin_on'] = '有効';
+$lang['plugin_off'] = '無効';
+$lang['plugin_default'] = 'デフォルト値';
+$lang['plugin_enabled'] = '個別に有効化';
+$lang['plugin_disabled'] = '個別に無効化';
+$lang['js']['animalSelect'] = '動物を選択する';
+$lang['js']['pluginSelect'] = 'プラグインを選択する';
+$lang['disable_new_plugins'] = 'プラグインはデフォルトで無効になっています。デフォルト値を有効にするか特定の動物に対して有効にすることができます。';
+$lang['delete_animal'] = '選択した動物の削除';
+$lang['delete_confirm'] = '確認のために動物の名前を入力してください';
+$lang['delete'] = '動物とそのすべてのデータを削除します';
+$lang['delete_noanimal'] = '削除する動物を選択してください';
+$lang['delete_mismatch'] = '確認入力は動物の名前と一致しません。 削除されません。';
+$lang['delete_invalid'] = '無効な動物の名前です。 削除されません。';
+$lang['delete_success'] = '動物は正常に削除されました。';
+$lang['delete_fail'] = '一部のファイルを削除できなかったため、手動できれいにする必要があります。';
diff --git a/platform/www/lib/plugins/farmer/lang/ja/notfound_404.txt b/platform/www/lib/plugins/farmer/lang/ja/notfound_404.txt
new file mode 100644
index 0000000..3f575d6
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/notfound_404.txt
@@ -0,0 +1,3 @@
+====== 404 ありません ======
+
+要求されたリソースがありません。
diff --git a/platform/www/lib/plugins/farmer/lang/ja/notfound_list.txt b/platform/www/lib/plugins/farmer/lang/ja/notfound_list.txt
new file mode 100644
index 0000000..f3e633c
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/notfound_list.txt
@@ -0,0 +1,3 @@
+====== Wiki がありません ======
+
+要求された Wiki がありません。以下の利用可能な Wiki の一覧を参照してください。
diff --git a/platform/www/lib/plugins/farmer/lang/ja/settings.php b/platform/www/lib/plugins/farmer/lang/ja/settings.php
new file mode 100644
index 0000000..dd9b6a6
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/settings.php
@@ -0,0 +1,9 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Hideaki SAWADA <chuno@live.jp>
+ */
+$lang['deactivated plugins'] = '新しい動物を作成した場合、デフォルトで無効とするプラグインのカンマ区切り一覧。';
+$lang['disable_new_plugins'] = '牧場にプラグインを新規にインストールした後、プラグインを自動的に無効化しますか?(拡張機能管理でインストールした場合のみ)';
diff --git a/platform/www/lib/plugins/farmer/lang/ja/tab_config.txt b/platform/www/lib/plugins/farmer/lang/ja/tab_config.txt
new file mode 100644
index 0000000..4d3619b
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/tab_config.txt
@@ -0,0 +1 @@
+牧場の基本的な動作を設定します。 ここのオプションを変更すると、全ての動物に影響が及ぶのでご注意ください。 \ No newline at end of file
diff --git a/platform/www/lib/plugins/farmer/lang/ja/tab_config_help.txt b/platform/www/lib/plugins/farmer/lang/ja/tab_config_help.txt
new file mode 100644
index 0000000..5e9e4b8
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/tab_config_help.txt
@@ -0,0 +1,25 @@
+===== 牧場設定 =====
+
+ここで入力した設定内容はすべて牧場主の ''conf/farm.ini'' に保存されます。
+
+==== 基本設定 ====
+
+**牧場主ホスト名**は、設定時に自動的に設定されますが、ここで変更できます。
+ホスト方式牧場を使用する場合、牧場主に直接要求されたかどうかの検出に使用します。
+これは完全修飾ホスト名でなければなりません。(''foo'' のみではなく ''foo.example.com'')
+
+サブドメインのワイルドカード設定を使用する場合、**ベースドメイン**設定でメインドメインを指定する必要があります。
+例えば ''example.com'' を指定した場合、''foo'' という名の動物は ''foo.example.com'' 経由で届く想定します。
+ベースドメインにはドットを含まない動物名だけが付加されます。
+
+==== 継承 ====
+
+ここでは、牧場主上で作成したどの設定を動物内でデフォルトとして使用するかを指定できます。
+動物は、独自の設定ファイルで牧場主の設定を上書きすることもできます。
+継承が無効になっている場合、DokuWiki のデフォルト設定が、すべての動物のデフォルトです。
+
+==== 実在しない動物 ====
+
+デフォルトでは、実在しない動物へのアクセス時にエラーメッセージを表示しません。
+ここで異なる動作を選ぶことができます。
+デフォルトから切替える前に、牧場主ホスト名が上記に正しく設定されていることを確認して下さい。
diff --git a/platform/www/lib/plugins/farmer/lang/ja/tab_delete.txt b/platform/www/lib/plugins/farmer/lang/ja/tab_delete.txt
new file mode 100644
index 0000000..bde0596
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/tab_delete.txt
@@ -0,0 +1 @@
+既存の動物を削除できます。 選択した動物の**ページやメディアファイルを含む全てのデータ**を削除します。 **元に戻せないので注意して下さい!** \ No newline at end of file
diff --git a/platform/www/lib/plugins/farmer/lang/ja/tab_info.txt b/platform/www/lib/plugins/farmer/lang/ja/tab_info.txt
new file mode 100644
index 0000000..78ea6c7
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/tab_info.txt
@@ -0,0 +1 @@
+この Wiki は、牧場設定の一部分です。 以下の詳細を確認してください。 \ No newline at end of file
diff --git a/platform/www/lib/plugins/farmer/lang/ja/tab_new.txt b/platform/www/lib/plugins/farmer/lang/ja/tab_new.txt
new file mode 100644
index 0000000..78d5975
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/tab_new.txt
@@ -0,0 +1 @@
+新しい動物を作成できます。 \ No newline at end of file
diff --git a/platform/www/lib/plugins/farmer/lang/ja/tab_new_help.txt b/platform/www/lib/plugins/farmer/lang/ja/tab_new_help.txt
new file mode 100644
index 0000000..9287e1f
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/tab_new_help.txt
@@ -0,0 +1,38 @@
+===== 動物の作成 =====
+
+動物は、Dokuwiki 牧場の独立したサブ wiki です。
+新しい動物を作成するには名前を割り当てなければなりません。
+
+==== 動物名 ====
+
+.htaccess 方式の設定の場合、動物名は一つの単語でなければなりません。
+ドメイン方式の設定の場合、完全修飾ドメイン名を提供する必要があります。
+ワイルドカードサブドメインの設定を使用している場合、ベースドメインが設定済みであれば、単にホスト名部分を提供するだけです。
+
+例:
+
+ * .htaccess 方式:''%%http://example.org/dokuwiki/!foo/%%'' にアクセス可能な動物用の ''foo''
+ * ドメイン方式:''%%http://www.foo.com/%%'' にアクセス可能な動物用の ''%%www.foo.com%%''
+ * サブドメイン方式: ''%%http://foo.example.com/%%'' にアクセス可能な動物用の ''foo''
+
+後の二つは、適切な DNS 設定が必要です!
+
+==== 動物のコピー ====
+
+新しい動物の基礎にするために既存の動物を選択することができます。
+すべての設定、ページ、メディア、メタデータが新しい動物にコピーされます。
+ページやメディアの履歴はコピーされません。
+
+タイトルとロゴイメージは上書きして、コピー元と区別できることを確認してください。
+
+==== 動物の管理者 ====
+
+動物は独自のユーザー基準で完全な機能の wiki になります。
+ユーザーを設定するために少なくとも1つの管理ユーザーが必要になります。
+牧場主から現在のユーザーまたはすべてのユーザーをコピーしたり、動物のために完全に新しいユーザーを作成できます。
+
+ユーザーを作成しないことも選択できます。
+設定タブで牧場主からユーザーの継承を有効にした場合、既存のユーザーを別の動物からコピーした場合のみこれを選択すべきです。
+
+/lang/en/tab_plugins.txt
+一括操作で全ての動物に対するプラグインの有効化・無効化や、特定の動物に対するプラグインの編集ができます。
diff --git a/platform/www/lib/plugins/farmer/lang/ja/tab_plugins.txt b/platform/www/lib/plugins/farmer/lang/ja/tab_plugins.txt
new file mode 100644
index 0000000..ee4acd5
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/tab_plugins.txt
@@ -0,0 +1 @@
+一度の操作で全ての動物のプラグインを有効または無効にすることや、個々の動物のプラグインを編集することができます。 \ No newline at end of file
diff --git a/platform/www/lib/plugins/farmer/lang/ja/tab_plugins_help.txt b/platform/www/lib/plugins/farmer/lang/ja/tab_plugins_help.txt
new file mode 100644
index 0000000..fe4aa72
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/tab_plugins_help.txt
@@ -0,0 +1,17 @@
+===== プラグイン管理 =====
+
+拡張機能管理は、すべての動物の中で無効になっています。
+プラグインは牧場主にのみインストールすることができ、牧場主だけがすべての動物の中でどのプラグインを有効にするか無効にするかを制御できます。
+この画面を使ってこの制御を行います。
+
+各プラグインは動物毎に三つの状態を指定できます。
+有効、無効、デフォルト状態です。
+デフォルトは動物に対してプラグインの状態を明示的に設定していないことを意味します。
+通常はデフォルトの状態は有効になっています。
+
+動物が牧場主のプラグインの状態を継承するように設定した場合、デフォルト状態のプラグインは牧場主と同じ状態になります。
+例えば、牧場主のプラグインを無効にした場合、このプラグインの状態を明示的に設定していなかったすべての動物内でプラグインを無効にします。
+
+プラグイン管理には二種類の方法があります:
+ * 一つのプラグインを選択し、すべての動物に対して同じ状態を設定する。
+ * 特定の動物を選び、その動物内のみに対するすべてのプラグインの状態を設定する。
diff --git a/platform/www/lib/plugins/farmer/lang/ja/tab_setup.txt b/platform/www/lib/plugins/farmer/lang/ja/tab_setup.txt
new file mode 100644
index 0000000..a5cf09c
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/tab_setup.txt
@@ -0,0 +1 @@
+この Wiki は牧場主プラグインの牧場設定をされていません。以下の入力画面で牧場設定をして下さい。 \ No newline at end of file
diff --git a/platform/www/lib/plugins/farmer/lang/ja/tab_setup_help.txt b/platform/www/lib/plugins/farmer/lang/ja/tab_setup_help.txt
new file mode 100644
index 0000000..d2cd61f
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/ja/tab_setup_help.txt
@@ -0,0 +1,38 @@
+===== 牧場について =====
+
+牧場は複数の他の wiki(「動物」 "Animals")を動かす単一の DokuWiki インストール(「牧場主」 "Farmer")を使えるようにします。
+プラグインとテンプレートは牧場主にだけインストールすれば、動物もそれらを利用できるようになります。
+一つの wiki だけを最新状態に保つ必要があり、他のすべての wiki は同じコードベースを使用するだけになります。
+
+この設定手順を完了した後、現在の DokuWiki(あなたが見ている DokuWiki)が、「牧場主」として認識されるようになります。
+
+===== この設定は何をしますか? =====
+
+この設定ウィザードでは、以下の三つを行います:
+
+ - ''inc/preload.php'' ファイルの作成
+ - ''conf/farm.ini'' ファイルの作成
+ - 必要に応じて ''.htaccess'' ファイルに追加
+
+''preload.php'' は DokuWiki 読込み時の最初に読み込まれるファイルです。
+ここで牧場機能が初期化されます。
+現在の要求が動物か牧場主をアクセスし、それに応じて全てを再構成する必要がある場合、牧場主プラグインを検出します。
+
+''conf/farm.ini'' には牧場の基本的な設定が含まれています。
+最も重要なことは、すべての動物データが格納される場所が含まれていることです。
+
+''.htaccess'' を変更することで //バン !// 機能を使って動物にアクセスできるようになります。(下記参照)
+
+===== 入力方法? =====
+
+**動物用のディレクトリ**は、各動物用に新しいディレクトリを作成する場所です。
+このディレクトリは、現在の DokuWiki の外でなければなりません。
+''../animals'' のような相対的なディレクトリを指定できます。
+
+**.htaccess** 対応を有効にすることを推奨します。
+この機能は、Apache の mod_rewrite と .htaccess 対応が必要です。
+
+有効にすると、動物は //バン !// 機能を使って牧場主の URL の下でアクセスできるようになります。
+例えば、''%%http://www.example.com/dokuwiki/%%'' で牧場主が実行されている場合、''%%http://www.example.com/dokuwiki/!animal%%'' で動物にアクセスできるようになります。
+
+このオプションを有効にしない場合、動物にアクセスするには、Web サーバーや DNS を設定するが必要があります。
diff --git a/platform/www/lib/plugins/farmer/lang/nl/lang.php b/platform/www/lib/plugins/farmer/lang/nl/lang.php
new file mode 100644
index 0000000..cef0c84
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/nl/lang.php
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Harriet Neitz <harrietneitz@gmail.com>
+ */
+$lang['tab_info'] = 'Info';
+$lang['tab_config'] = 'Configuratie';
+$lang['tab_plugins'] = 'Beheer plugins';
+$lang['tab_new'] = 'Voeg nieuw dier toe';
+$lang['tab_delete'] = 'Verwijder dier';
+$lang['farmdir_in_dokuwiki'] = 'De dier directory (%s) moet buiten de Boerderij dokuwiki (%s) staan.';
+$lang['farmdir_unwritable'] = 'Controleer dat de webserver schrijf-toegang heeft tot de dier directory (%s)!';
+$lang['overwrite_preload'] = 'Waarschuwing: Je bestaande inc/preload.php wordt overschreven wanneer je hier doorgaat!';
+$lang['conf_notfound_404'] = 'Toon een 404 fout pagina';
+$lang['conf_notfound_list'] = 'Toon een lijst van bestaande dieren';
+$lang['conf_notfound_redirect'] = 'Redirect naar onderstaande URL';
+$lang['save'] = 'Opslaan';
+$lang['animal template'] = 'Kopieer bestaand dier';
diff --git a/platform/www/lib/plugins/farmer/lang/pl/lang.php b/platform/www/lib/plugins/farmer/lang/pl/lang.php
new file mode 100644
index 0000000..375d919
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/lang/pl/lang.php
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Bartek S <sadupl@gmail.com>
+ */
+$lang['menu'] = 'Farma';
+$lang['tab_setup'] = 'Ustawienia Farmy';
+$lang['tab_info'] = 'Informacje';
+$lang['tab_config'] = 'Konfiguracja';
+$lang['tab_plugins'] = 'Zarządzaj pluginami';
+$lang['tab_new'] = 'Dodaj nowe zwierzę';
+$lang['tab_delete'] = 'Usuń zwierzę';
+$lang['preloadPHPForm'] = 'Zainicjuj Farmę';
+$lang['farm dir'] = 'Katalog zwierząt';
+$lang['htaccess setup'] = 'Dodać kod farmy do .htaccess?';
+$lang['submit'] = 'Zatwierdź';
+$lang['farmdir_missing'] = 'Proszę podać katalog gdzie Zwierzęta powinny być przechowywane.';
+$lang['farmdir_in_dokuwiki'] = 'Katalog Zwierząt (%s) musi być poza Farmą dokuwiki (%s).';
+$lang['farmdir_uncreatable'] = 'Katalog Zwierząt (%s) nie został stworzony. Czy uprawnienia są prawidłowe?';
+$lang['farmdir_unwritable'] = 'Proszę się upenić, że webserver posiada prawa zapisu do katalogu Zwierząt.';
+$lang['farmdir_notEmpty'] = 'Katalog Zwierząt (%s) musi być pusty.';
+$lang['preload creation success'] = 'Farma została zainicjowana pomyślnie.';
+$lang['preload creation error'] = 'Wystąpił błąd podczas inicjowania Farmy.';
+$lang['overwrite_preload'] = 'Uwaga: Dotychczasowy plik inc/preload.php będzie zastąpiony podczas kontynuowania!';
+$lang['animal'] = 'Imię Zwierzęta / Domeny';
+$lang['thisis'] = 'Instancja to';
+$lang['thisis.farmer'] = 'Farmer!';
+$lang['thisis.animal'] = 'Zwierzę!';
+$lang['baseinstall'] = 'Instalacja Farmera';
+$lang['animals'] = 'Zwierzęta';
+$lang['confdir'] = 'Katalog konfiguracji instancji';
+$lang['savedir'] = 'Katalog danych instancji';
+$lang['plugins'] = 'Aktywne pluginy tej instancji';
+$lang['base'] = 'Konfiguracja Bazy';
+$lang['farm host'] = 'Host Name Farmera';
+$lang['base domain'] = 'Domena podstawowa dla subdomeny Zwierzęta';
+$lang['conf_inherit'] = 'Zwierzęta powinny dziedziczyć ustawienia farmera';
+$lang['conf_inherit_main'] = 'Ustawienia konfiguracji';
+$lang['conf_inherit_acronyms'] = 'Definicje akronimów';
+$lang['conf_inherit_entities'] = 'Definicje jednostek';
+$lang['conf_inherit_interwiki'] = 'Definicje Interwiki';
+$lang['conf_inherit_license'] = 'Definicje licencji';
+$lang['conf_inherit_smileys'] = 'Definicje uśmieszków';
+$lang['conf_inherit_wordblock'] = 'Wpisy SPAM na czarnej liście';
+$lang['conf_inherit_userstyle'] = 'Style użytkownika';
+$lang['conf_inherit_userscript'] = 'Skrypty użytkownika';
+$lang['conf_inherit_styleini'] = 'Dostosowanie stylu szablonu';
+$lang['conf_inherit_users'] = 'Użytkownicy (tylko zwykłe uwierzytelnianie)';
+$lang['conf_inherit_plugins'] = 'Stan wtyczki';
+$lang['conf_inherit_yes'] = 'odziedziczony po farmerze';
+$lang['conf_inherit_no'] = 'niezależny od farmera';
+$lang['conf_notfound'] = 'Zachowanie podczas uzyskiwania dostępu do nieistniejących zwierząt';
+$lang['conf_notfound_farmer'] = 'Pokaż wiki farmera';
+$lang['conf_notfound_404'] = 'Pokaż stronę błędu 404';
+$lang['conf_notfound_list'] = 'Pokaż listę dostępnych zwierząt';
+$lang['conf_notfound_redirect'] = 'Przekieruj na poniższy adres URL';
+$lang['conf_notfound_url'] = 'Adres URL do przekierowania, jeśli wybrano powyżej';
+$lang['save'] = 'Zapisz';
+$lang['animal template'] = 'Kopiuj istniejące Zwierzę';
+$lang['animal creation success'] = 'Zwierzę "%s" zostało pomyślnie utworzone.';
+$lang['animal creation error'] = 'Wystąpił błąd podczas tworzenia zwierzęcia.';
+$lang['animal configuration'] = 'Podstawowa konfiguracja Zwierząt';
+$lang['inherit user registration'] = 'Dziedzicz ustawienia rejestracji użytkownika od farmera';
+$lang['enable user registration'] = 'Pozwól użytkownikom się zarejestrować';
+$lang['disable user registration'] = 'Wyłącz rejestrację użytkowników';
+$lang['animal administrator'] = 'Administrator zwięrząt';
+$lang['noUsers'] = 'Nie twórz żadnych użytkowników';
+$lang['importUsers'] = 'Zaimportuj wszystkich użytkowników Farmera do nowego zwierzęcia';
+$lang['currentAdmin'] = 'Ustaw bieżącego użytkownika jako admin';
+$lang['newAdmin'] = 'Utwórz nowego administratora „admin”';
+$lang['admin password'] = 'Hasło dla nowego administratora';
+$lang['animalname_missing'] = 'Wprowadź nazwę nowego zwierzęcia.';
+$lang['animalname_preexisting'] = 'Zwierzę o tej nazwie już istnieje.';
+$lang['adminPassword_empty'] = 'Hasło do nowego konta administratora nie może być puste.';
+$lang['bulkSingleSwitcher'] = 'Edytować jedno Zwierzę czy wszystkie naraz?';
+$lang['bulkEdit'] = 'Zbiorcza edycja wszystkich Zwierząt';
+$lang['singleEdit'] = 'Edytuj jedno Zwierzę';
+$lang['bulkEditForm'] = 'Aktywuj lub dezaktywuj wtyczkę we wszystkich Zwierzętach';
+$lang['default'] = 'Ustaw na domyślny';
+$lang['activate'] = 'Aktywuj';
+$lang['deactivate'] = 'Dezaktywuj';
+$lang['singleEditForm'] = 'Edytuj wtyczki określonego Zwierzęcia';
+$lang['plugindone'] = 'Stany wtyczek zaktualizowane';
+$lang['plugin'] = 'Plugin';
+$lang['plugin_on'] = 'on
+(it means \'włączone\', but in PL we use also ON/OFF)';
+$lang['plugin_off'] = 'off
+(it means \'wyłączone\', but in PL we use also ON/OFF)';
+$lang['plugin_default'] = 'Domyślne';
+$lang['plugin_enabled'] = 'Włączone';
+$lang['plugin_disabled'] = 'Wyłączone';
+$lang['js']['animalSelect'] = 'Wybierz zwierzę';
+$lang['js']['pluginSelect'] = 'Wybierz plugin';
+$lang['delete_animal'] = 'Wybierz Zwierzę do usunięcia';
+$lang['delete_confirm'] = 'Wpisz nazwę Zwierzęcia, aby potwierdzić';
+$lang['delete'] = 'Usuń Zwierzę i wszystkie jego dane';
+$lang['delete_noanimal'] = 'Proszę wybrać Zwierzę do usunięcia';
+$lang['delete_mismatch'] = 'Potwierdzenie nie pasuje do nazwy Zwierzęcia. Nie usunięte.';
+$lang['delete_invalid'] = 'Nieprawidłowa nazwa Zwierzęcia. Nie usunięte';
+$lang['delete_success'] = 'Zwierzę zostało pomyślnie usunięte.';
diff --git a/platform/www/lib/plugins/farmer/plugin.info.txt b/platform/www/lib/plugins/farmer/plugin.info.txt
new file mode 100644
index 0000000..2a26566
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/plugin.info.txt
@@ -0,0 +1,7 @@
+base farmer
+author Michael Große, Andreas Gohr
+email dokuwiki@cosmocode.de
+date 2021-01-08
+name farmer plugin
+desc A plugin to help with creating and administring wiki farm animals
+url https://dokuwiki.org/plugin:farmer
diff --git a/platform/www/lib/plugins/farmer/script.js b/platform/www/lib/plugins/farmer/script.js
new file mode 100644
index 0000000..d5cea10
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/script.js
@@ -0,0 +1,2 @@
+/* DOKUWIKI:include_once script/jquery.chosen.js */
+/* DOKUWIKI:include script/plugins.js */
diff --git a/platform/www/lib/plugins/farmer/script/jquery.chosen.js b/platform/www/lib/plugins/farmer/script/jquery.chosen.js
new file mode 100644
index 0000000..929a9ca
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/script/jquery.chosen.js
@@ -0,0 +1,1257 @@
+/*!
+Chosen, a Select Box Enhancer for jQuery and Prototype
+by Patrick Filler for Harvest, http://getharvest.com
+
+Version 1.4.2
+Full source at https://github.com/harvesthq/chosen
+Copyright (c) 2011-2015 Harvest http://getharvest.com
+
+MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
+This file is generated by `grunt build`, do not edit it by hand.
+*/
+
+(function() {
+ var $, AbstractChosen, Chosen, SelectParser, _ref,
+ __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ SelectParser = (function() {
+ function SelectParser() {
+ this.options_index = 0;
+ this.parsed = [];
+ }
+
+ SelectParser.prototype.add_node = function(child) {
+ if (child.nodeName.toUpperCase() === "OPTGROUP") {
+ return this.add_group(child);
+ } else {
+ return this.add_option(child);
+ }
+ };
+
+ SelectParser.prototype.add_group = function(group) {
+ var group_position, option, _i, _len, _ref, _results;
+ group_position = this.parsed.length;
+ this.parsed.push({
+ array_index: group_position,
+ group: true,
+ label: this.escapeExpression(group.label),
+ title: group.title ? group.title : void 0,
+ children: 0,
+ disabled: group.disabled,
+ classes: group.className
+ });
+ _ref = group.childNodes;
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ option = _ref[_i];
+ _results.push(this.add_option(option, group_position, group.disabled));
+ }
+ return _results;
+ };
+
+ SelectParser.prototype.add_option = function(option, group_position, group_disabled) {
+ if (option.nodeName.toUpperCase() === "OPTION") {
+ if (option.text !== "") {
+ if (group_position != null) {
+ this.parsed[group_position].children += 1;
+ }
+ this.parsed.push({
+ array_index: this.parsed.length,
+ options_index: this.options_index,
+ value: option.value,
+ text: option.text,
+ html: option.innerHTML,
+ title: option.title ? option.title : void 0,
+ selected: option.selected,
+ disabled: group_disabled === true ? group_disabled : option.disabled,
+ group_array_index: group_position,
+ group_label: group_position != null ? this.parsed[group_position].label : null,
+ classes: option.className,
+ style: option.style.cssText
+ });
+ } else {
+ this.parsed.push({
+ array_index: this.parsed.length,
+ options_index: this.options_index,
+ empty: true
+ });
+ }
+ return this.options_index += 1;
+ }
+ };
+
+ SelectParser.prototype.escapeExpression = function(text) {
+ var map, unsafe_chars;
+ if ((text == null) || text === false) {
+ return "";
+ }
+ if (!/[\&\<\>\"\'\`]/.test(text)) {
+ return text;
+ }
+ map = {
+ "<": "&lt;",
+ ">": "&gt;",
+ '"': "&quot;",
+ "'": "&#x27;",
+ "`": "&#x60;"
+ };
+ unsafe_chars = /&(?!\w+;)|[\<\>\"\'\`]/g;
+ return text.replace(unsafe_chars, function(chr) {
+ return map[chr] || "&amp;";
+ });
+ };
+
+ return SelectParser;
+
+ })();
+
+ SelectParser.select_to_array = function(select) {
+ var child, parser, _i, _len, _ref;
+ parser = new SelectParser();
+ _ref = select.childNodes;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ child = _ref[_i];
+ parser.add_node(child);
+ }
+ return parser.parsed;
+ };
+
+ AbstractChosen = (function() {
+ function AbstractChosen(form_field, options) {
+ this.form_field = form_field;
+ this.options = options != null ? options : {};
+ if (!AbstractChosen.browser_is_supported()) {
+ return;
+ }
+ this.is_multiple = this.form_field.multiple;
+ this.set_default_text();
+ this.set_default_values();
+ this.setup();
+ this.set_up_html();
+ this.register_observers();
+ this.on_ready();
+ }
+
+ AbstractChosen.prototype.set_default_values = function() {
+ var _this = this;
+ this.click_test_action = function(evt) {
+ return _this.test_active_click(evt);
+ };
+ this.activate_action = function(evt) {
+ return _this.activate_field(evt);
+ };
+ this.active_field = false;
+ this.mouse_on_container = false;
+ this.results_showing = false;
+ this.result_highlighted = null;
+ this.allow_single_deselect = (this.options.allow_single_deselect != null) && (this.form_field.options[0] != null) && this.form_field.options[0].text === "" ? this.options.allow_single_deselect : false;
+ this.disable_search_threshold = this.options.disable_search_threshold || 0;
+ this.disable_search = this.options.disable_search || false;
+ this.enable_split_word_search = this.options.enable_split_word_search != null ? this.options.enable_split_word_search : true;
+ this.group_search = this.options.group_search != null ? this.options.group_search : true;
+ this.search_contains = this.options.search_contains || false;
+ this.single_backstroke_delete = this.options.single_backstroke_delete != null ? this.options.single_backstroke_delete : true;
+ this.max_selected_options = this.options.max_selected_options || Infinity;
+ this.inherit_select_classes = this.options.inherit_select_classes || false;
+ this.display_selected_options = this.options.display_selected_options != null ? this.options.display_selected_options : true;
+ this.display_disabled_options = this.options.display_disabled_options != null ? this.options.display_disabled_options : true;
+ return this.include_group_label_in_selected = this.options.include_group_label_in_selected || false;
+ };
+
+ AbstractChosen.prototype.set_default_text = function() {
+ if (this.form_field.getAttribute("data-placeholder")) {
+ this.default_text = this.form_field.getAttribute("data-placeholder");
+ } else if (this.is_multiple) {
+ this.default_text = this.options.placeholder_text_multiple || this.options.placeholder_text || AbstractChosen.default_multiple_text;
+ } else {
+ this.default_text = this.options.placeholder_text_single || this.options.placeholder_text || AbstractChosen.default_single_text;
+ }
+ return this.results_none_found = this.form_field.getAttribute("data-no_results_text") || this.options.no_results_text || AbstractChosen.default_no_result_text;
+ };
+
+ AbstractChosen.prototype.choice_label = function(item) {
+ if (this.include_group_label_in_selected && (item.group_label != null)) {
+ return "<b class='group-name'>" + item.group_label + "</b>" + item.html;
+ } else {
+ return item.html;
+ }
+ };
+
+ AbstractChosen.prototype.mouse_enter = function() {
+ return this.mouse_on_container = true;
+ };
+
+ AbstractChosen.prototype.mouse_leave = function() {
+ return this.mouse_on_container = false;
+ };
+
+ AbstractChosen.prototype.input_focus = function(evt) {
+ var _this = this;
+ if (this.is_multiple) {
+ if (!this.active_field) {
+ return setTimeout((function() {
+ return _this.container_mousedown();
+ }), 50);
+ }
+ } else {
+ if (!this.active_field) {
+ return this.activate_field();
+ }
+ }
+ };
+
+ AbstractChosen.prototype.input_blur = function(evt) {
+ var _this = this;
+ if (!this.mouse_on_container) {
+ this.active_field = false;
+ return setTimeout((function() {
+ return _this.blur_test();
+ }), 100);
+ }
+ };
+
+ AbstractChosen.prototype.results_option_build = function(options) {
+ var content, data, _i, _len, _ref;
+ content = '';
+ _ref = this.results_data;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ data = _ref[_i];
+ if (data.group) {
+ content += this.result_add_group(data);
+ } else {
+ content += this.result_add_option(data);
+ }
+ if (options != null ? options.first : void 0) {
+ if (data.selected && this.is_multiple) {
+ this.choice_build(data);
+ } else if (data.selected && !this.is_multiple) {
+ this.single_set_selected_text(this.choice_label(data));
+ }
+ }
+ }
+ return content;
+ };
+
+ AbstractChosen.prototype.result_add_option = function(option) {
+ var classes, option_el;
+ if (!option.search_match) {
+ return '';
+ }
+ if (!this.include_option_in_results(option)) {
+ return '';
+ }
+ classes = [];
+ if (!option.disabled && !(option.selected && this.is_multiple)) {
+ classes.push("active-result");
+ }
+ if (option.disabled && !(option.selected && this.is_multiple)) {
+ classes.push("disabled-result");
+ }
+ if (option.selected) {
+ classes.push("result-selected");
+ }
+ if (option.group_array_index != null) {
+ classes.push("group-option");
+ }
+ if (option.classes !== "") {
+ classes.push(option.classes);
+ }
+ option_el = document.createElement("li");
+ option_el.className = classes.join(" ");
+ option_el.style.cssText = option.style;
+ option_el.setAttribute("data-option-array-index", option.array_index);
+ option_el.innerHTML = option.search_text;
+ if (option.title) {
+ option_el.title = option.title;
+ }
+ return this.outerHTML(option_el);
+ };
+
+ AbstractChosen.prototype.result_add_group = function(group) {
+ var classes, group_el;
+ if (!(group.search_match || group.group_match)) {
+ return '';
+ }
+ if (!(group.active_options > 0)) {
+ return '';
+ }
+ classes = [];
+ classes.push("group-result");
+ if (group.classes) {
+ classes.push(group.classes);
+ }
+ group_el = document.createElement("li");
+ group_el.className = classes.join(" ");
+ group_el.innerHTML = group.search_text;
+ if (group.title) {
+ group_el.title = group.title;
+ }
+ return this.outerHTML(group_el);
+ };
+
+ AbstractChosen.prototype.results_update_field = function() {
+ this.set_default_text();
+ if (!this.is_multiple) {
+ this.results_reset_cleanup();
+ }
+ this.result_clear_highlight();
+ this.results_build();
+ if (this.results_showing) {
+ return this.winnow_results();
+ }
+ };
+
+ AbstractChosen.prototype.reset_single_select_options = function() {
+ var result, _i, _len, _ref, _results;
+ _ref = this.results_data;
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ result = _ref[_i];
+ if (result.selected) {
+ _results.push(result.selected = false);
+ } else {
+ _results.push(void 0);
+ }
+ }
+ return _results;
+ };
+
+ AbstractChosen.prototype.results_toggle = function() {
+ if (this.results_showing) {
+ return this.results_hide();
+ } else {
+ return this.results_show();
+ }
+ };
+
+ AbstractChosen.prototype.results_search = function(evt) {
+ if (this.results_showing) {
+ return this.winnow_results();
+ } else {
+ return this.results_show();
+ }
+ };
+
+ AbstractChosen.prototype.winnow_results = function() {
+ var escapedSearchText, option, regex, results, results_group, searchText, startpos, text, zregex, _i, _len, _ref;
+ this.no_results_clear();
+ results = 0;
+ searchText = this.get_search_text();
+ escapedSearchText = searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+ zregex = new RegExp(escapedSearchText, 'i');
+ regex = this.get_search_regex(escapedSearchText);
+ _ref = this.results_data;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ option = _ref[_i];
+ option.search_match = false;
+ results_group = null;
+ if (this.include_option_in_results(option)) {
+ if (option.group) {
+ option.group_match = false;
+ option.active_options = 0;
+ }
+ if ((option.group_array_index != null) && this.results_data[option.group_array_index]) {
+ results_group = this.results_data[option.group_array_index];
+ if (results_group.active_options === 0 && results_group.search_match) {
+ results += 1;
+ }
+ results_group.active_options += 1;
+ }
+ option.search_text = option.group ? option.label : option.html;
+ if (!(option.group && !this.group_search)) {
+ option.search_match = this.search_string_match(option.search_text, regex);
+ if (option.search_match && !option.group) {
+ results += 1;
+ }
+ if (option.search_match) {
+ if (searchText.length) {
+ startpos = option.search_text.search(zregex);
+ text = option.search_text.substr(0, startpos + searchText.length) + '</em>' + option.search_text.substr(startpos + searchText.length);
+ option.search_text = text.substr(0, startpos) + '<em>' + text.substr(startpos);
+ }
+ if (results_group != null) {
+ results_group.group_match = true;
+ }
+ } else if ((option.group_array_index != null) && this.results_data[option.group_array_index].search_match) {
+ option.search_match = true;
+ }
+ }
+ }
+ }
+ this.result_clear_highlight();
+ if (results < 1 && searchText.length) {
+ this.update_results_content("");
+ return this.no_results(searchText);
+ } else {
+ this.update_results_content(this.results_option_build());
+ return this.winnow_results_set_highlight();
+ }
+ };
+
+ AbstractChosen.prototype.get_search_regex = function(escaped_search_string) {
+ var regex_anchor;
+ regex_anchor = this.search_contains ? "" : "^";
+ return new RegExp(regex_anchor + escaped_search_string, 'i');
+ };
+
+ AbstractChosen.prototype.search_string_match = function(search_string, regex) {
+ var part, parts, _i, _len;
+ if (regex.test(search_string)) {
+ return true;
+ } else if (this.enable_split_word_search && (search_string.indexOf(" ") >= 0 || search_string.indexOf("[") === 0)) {
+ parts = search_string.replace(/\[|\]/g, "").split(" ");
+ if (parts.length) {
+ for (_i = 0, _len = parts.length; _i < _len; _i++) {
+ part = parts[_i];
+ if (regex.test(part)) {
+ return true;
+ }
+ }
+ }
+ }
+ };
+
+ AbstractChosen.prototype.choices_count = function() {
+ var option, _i, _len, _ref;
+ if (this.selected_option_count != null) {
+ return this.selected_option_count;
+ }
+ this.selected_option_count = 0;
+ _ref = this.form_field.options;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ option = _ref[_i];
+ if (option.selected) {
+ this.selected_option_count += 1;
+ }
+ }
+ return this.selected_option_count;
+ };
+
+ AbstractChosen.prototype.choices_click = function(evt) {
+ evt.preventDefault();
+ if (!(this.results_showing || this.is_disabled)) {
+ return this.results_show();
+ }
+ };
+
+ AbstractChosen.prototype.keyup_checker = function(evt) {
+ var stroke, _ref;
+ stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
+ this.search_field_scale();
+ switch (stroke) {
+ case 8:
+ if (this.is_multiple && this.backstroke_length < 1 && this.choices_count() > 0) {
+ return this.keydown_backstroke();
+ } else if (!this.pending_backstroke) {
+ this.result_clear_highlight();
+ return this.results_search();
+ }
+ break;
+ case 13:
+ evt.preventDefault();
+ if (this.results_showing) {
+ return this.result_select(evt);
+ }
+ break;
+ case 27:
+ if (this.results_showing) {
+ this.results_hide();
+ }
+ return true;
+ case 9:
+ case 38:
+ case 40:
+ case 16:
+ case 91:
+ case 17:
+ break;
+ default:
+ return this.results_search();
+ }
+ };
+
+ AbstractChosen.prototype.clipboard_event_checker = function(evt) {
+ var _this = this;
+ return setTimeout((function() {
+ return _this.results_search();
+ }), 50);
+ };
+
+ AbstractChosen.prototype.container_width = function() {
+ if (this.options.width != null) {
+ return this.options.width;
+ } else {
+ return "" + this.form_field.offsetWidth + "px";
+ }
+ };
+
+ AbstractChosen.prototype.include_option_in_results = function(option) {
+ if (this.is_multiple && (!this.display_selected_options && option.selected)) {
+ return false;
+ }
+ if (!this.display_disabled_options && option.disabled) {
+ return false;
+ }
+ if (option.empty) {
+ return false;
+ }
+ return true;
+ };
+
+ AbstractChosen.prototype.search_results_touchstart = function(evt) {
+ this.touch_started = true;
+ return this.search_results_mouseover(evt);
+ };
+
+ AbstractChosen.prototype.search_results_touchmove = function(evt) {
+ this.touch_started = false;
+ return this.search_results_mouseout(evt);
+ };
+
+ AbstractChosen.prototype.search_results_touchend = function(evt) {
+ if (this.touch_started) {
+ return this.search_results_mouseup(evt);
+ }
+ };
+
+ AbstractChosen.prototype.outerHTML = function(element) {
+ var tmp;
+ if (element.outerHTML) {
+ return element.outerHTML;
+ }
+ tmp = document.createElement("div");
+ tmp.appendChild(element);
+ return tmp.innerHTML;
+ };
+
+ AbstractChosen.browser_is_supported = function() {
+ if (window.navigator.appName === "Microsoft Internet Explorer") {
+ return document.documentMode >= 8;
+ }
+ if (/iP(od|hone)/i.test(window.navigator.userAgent)) {
+ return false;
+ }
+ if (/Android/i.test(window.navigator.userAgent)) {
+ if (/Mobile/i.test(window.navigator.userAgent)) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ AbstractChosen.default_multiple_text = "Select Some Options";
+
+ AbstractChosen.default_single_text = "Select an Option";
+
+ AbstractChosen.default_no_result_text = "No results match";
+
+ return AbstractChosen;
+
+ })();
+
+ $ = jQuery;
+
+ $.fn.extend({
+ chosen: function(options) {
+ if (!AbstractChosen.browser_is_supported()) {
+ return this;
+ }
+ return this.each(function(input_field) {
+ var $this, chosen;
+ $this = $(this);
+ chosen = $this.data('chosen');
+ if (options === 'destroy' && chosen instanceof Chosen) {
+ chosen.destroy();
+ } else if (!(chosen instanceof Chosen)) {
+ $this.data('chosen', new Chosen(this, options));
+ }
+ });
+ }
+ });
+
+ Chosen = (function(_super) {
+ __extends(Chosen, _super);
+
+ function Chosen() {
+ _ref = Chosen.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ Chosen.prototype.setup = function() {
+ this.form_field_jq = $(this.form_field);
+ this.current_selectedIndex = this.form_field.selectedIndex;
+ return this.is_rtl = this.form_field_jq.hasClass("chosen-rtl");
+ };
+
+ Chosen.prototype.set_up_html = function() {
+ var container_classes, container_props;
+ container_classes = ["chosen-container"];
+ container_classes.push("chosen-container-" + (this.is_multiple ? "multi" : "single"));
+ if (this.inherit_select_classes && this.form_field.className) {
+ container_classes.push(this.form_field.className);
+ }
+ if (this.is_rtl) {
+ container_classes.push("chosen-rtl");
+ }
+ container_props = {
+ 'class': container_classes.join(' '),
+ 'style': "width: " + (this.container_width()) + ";",
+ 'title': this.form_field.title
+ };
+ if (this.form_field.id.length) {
+ container_props.id = this.form_field.id.replace(/[^\w]/g, '_') + "_chosen";
+ }
+ this.container = $("<div />", container_props);
+ if (this.is_multiple) {
+ this.container.html('<ul class="chosen-choices"><li class="search-field"><input type="text" value="' + this.default_text + '" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chosen-drop"><ul class="chosen-results"></ul></div>');
+ } else {
+ this.container.html('<a class="chosen-single chosen-default" tabindex="-1"><span>' + this.default_text + '</span><div><b></b></div></a><div class="chosen-drop"><div class="chosen-search"><input type="text" autocomplete="off" /></div><ul class="chosen-results"></ul></div>');
+ }
+ this.form_field_jq.hide().after(this.container);
+ this.dropdown = this.container.find('div.chosen-drop').first();
+ this.search_field = this.container.find('input').first();
+ this.search_results = this.container.find('ul.chosen-results').first();
+ this.search_field_scale();
+ this.search_no_results = this.container.find('li.no-results').first();
+ if (this.is_multiple) {
+ this.search_choices = this.container.find('ul.chosen-choices').first();
+ this.search_container = this.container.find('li.search-field').first();
+ } else {
+ this.search_container = this.container.find('div.chosen-search').first();
+ this.selected_item = this.container.find('.chosen-single').first();
+ }
+ this.results_build();
+ this.set_tab_index();
+ return this.set_label_behavior();
+ };
+
+ Chosen.prototype.on_ready = function() {
+ return this.form_field_jq.trigger("chosen:ready", {
+ chosen: this
+ });
+ };
+
+ Chosen.prototype.register_observers = function() {
+ var _this = this;
+ this.container.bind('touchstart.chosen', function(evt) {
+ _this.container_mousedown(evt);
+ return evt.preventDefault();
+ });
+ this.container.bind('touchend.chosen', function(evt) {
+ _this.container_mouseup(evt);
+ return evt.preventDefault();
+ });
+ this.container.bind('mousedown.chosen', function(evt) {
+ _this.container_mousedown(evt);
+ });
+ this.container.bind('mouseup.chosen', function(evt) {
+ _this.container_mouseup(evt);
+ });
+ this.container.bind('mouseenter.chosen', function(evt) {
+ _this.mouse_enter(evt);
+ });
+ this.container.bind('mouseleave.chosen', function(evt) {
+ _this.mouse_leave(evt);
+ });
+ this.search_results.bind('mouseup.chosen', function(evt) {
+ _this.search_results_mouseup(evt);
+ });
+ this.search_results.bind('mouseover.chosen', function(evt) {
+ _this.search_results_mouseover(evt);
+ });
+ this.search_results.bind('mouseout.chosen', function(evt) {
+ _this.search_results_mouseout(evt);
+ });
+ this.search_results.bind('mousewheel.chosen DOMMouseScroll.chosen', function(evt) {
+ _this.search_results_mousewheel(evt);
+ });
+ this.search_results.bind('touchstart.chosen', function(evt) {
+ _this.search_results_touchstart(evt);
+ });
+ this.search_results.bind('touchmove.chosen', function(evt) {
+ _this.search_results_touchmove(evt);
+ });
+ this.search_results.bind('touchend.chosen', function(evt) {
+ _this.search_results_touchend(evt);
+ });
+ this.form_field_jq.bind("chosen:updated.chosen", function(evt) {
+ _this.results_update_field(evt);
+ });
+ this.form_field_jq.bind("chosen:activate.chosen", function(evt) {
+ _this.activate_field(evt);
+ });
+ this.form_field_jq.bind("chosen:open.chosen", function(evt) {
+ _this.container_mousedown(evt);
+ });
+ this.form_field_jq.bind("chosen:close.chosen", function(evt) {
+ _this.input_blur(evt);
+ });
+ this.search_field.bind('blur.chosen', function(evt) {
+ _this.input_blur(evt);
+ });
+ this.search_field.bind('keyup.chosen', function(evt) {
+ _this.keyup_checker(evt);
+ });
+ this.search_field.bind('keydown.chosen', function(evt) {
+ _this.keydown_checker(evt);
+ });
+ this.search_field.bind('focus.chosen', function(evt) {
+ _this.input_focus(evt);
+ });
+ this.search_field.bind('cut.chosen', function(evt) {
+ _this.clipboard_event_checker(evt);
+ });
+ this.search_field.bind('paste.chosen', function(evt) {
+ _this.clipboard_event_checker(evt);
+ });
+ if (this.is_multiple) {
+ return this.search_choices.bind('click.chosen', function(evt) {
+ _this.choices_click(evt);
+ });
+ } else {
+ return this.container.bind('click.chosen', function(evt) {
+ evt.preventDefault();
+ });
+ }
+ };
+
+ Chosen.prototype.destroy = function() {
+ $(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action);
+ if (this.search_field[0].tabIndex) {
+ this.form_field_jq[0].tabIndex = this.search_field[0].tabIndex;
+ }
+ this.container.remove();
+ this.form_field_jq.removeData('chosen');
+ return this.form_field_jq.show();
+ };
+
+ Chosen.prototype.search_field_disabled = function() {
+ this.is_disabled = this.form_field_jq[0].disabled;
+ if (this.is_disabled) {
+ this.container.addClass('chosen-disabled');
+ this.search_field[0].disabled = true;
+ if (!this.is_multiple) {
+ this.selected_item.unbind("focus.chosen", this.activate_action);
+ }
+ return this.close_field();
+ } else {
+ this.container.removeClass('chosen-disabled');
+ this.search_field[0].disabled = false;
+ if (!this.is_multiple) {
+ return this.selected_item.bind("focus.chosen", this.activate_action);
+ }
+ }
+ };
+
+ Chosen.prototype.container_mousedown = function(evt) {
+ if (!this.is_disabled) {
+ if (evt && evt.type === "mousedown" && !this.results_showing) {
+ evt.preventDefault();
+ }
+ if (!((evt != null) && ($(evt.target)).hasClass("search-choice-close"))) {
+ if (!this.active_field) {
+ if (this.is_multiple) {
+ this.search_field.val("");
+ }
+ $(this.container[0].ownerDocument).bind('click.chosen', this.click_test_action);
+ this.results_show();
+ } else if (!this.is_multiple && evt && (($(evt.target)[0] === this.selected_item[0]) || $(evt.target).parents("a.chosen-single").length)) {
+ evt.preventDefault();
+ this.results_toggle();
+ }
+ return this.activate_field();
+ }
+ }
+ };
+
+ Chosen.prototype.container_mouseup = function(evt) {
+ if (evt.target.nodeName === "ABBR" && !this.is_disabled) {
+ return this.results_reset(evt);
+ }
+ };
+
+ Chosen.prototype.search_results_mousewheel = function(evt) {
+ var delta;
+ if (evt.originalEvent) {
+ delta = evt.originalEvent.deltaY || -evt.originalEvent.wheelDelta || evt.originalEvent.detail;
+ }
+ if (delta != null) {
+ evt.preventDefault();
+ if (evt.type === 'DOMMouseScroll') {
+ delta = delta * 40;
+ }
+ return this.search_results.scrollTop(delta + this.search_results.scrollTop());
+ }
+ };
+
+ Chosen.prototype.blur_test = function(evt) {
+ if (!this.active_field && this.container.hasClass("chosen-container-active")) {
+ return this.close_field();
+ }
+ };
+
+ Chosen.prototype.close_field = function() {
+ $(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action);
+ this.active_field = false;
+ this.results_hide();
+ this.container.removeClass("chosen-container-active");
+ this.clear_backstroke();
+ this.show_search_field_default();
+ return this.search_field_scale();
+ };
+
+ Chosen.prototype.activate_field = function() {
+ this.container.addClass("chosen-container-active");
+ this.active_field = true;
+ this.search_field.val(this.search_field.val());
+ return this.search_field.focus();
+ };
+
+ Chosen.prototype.test_active_click = function(evt) {
+ var active_container;
+ active_container = $(evt.target).closest('.chosen-container');
+ if (active_container.length && this.container[0] === active_container[0]) {
+ return this.active_field = true;
+ } else {
+ return this.close_field();
+ }
+ };
+
+ Chosen.prototype.results_build = function() {
+ this.parsing = true;
+ this.selected_option_count = null;
+ this.results_data = SelectParser.select_to_array(this.form_field);
+ if (this.is_multiple) {
+ this.search_choices.find("li.search-choice").remove();
+ } else if (!this.is_multiple) {
+ this.single_set_selected_text();
+ if (this.disable_search || this.form_field.options.length <= this.disable_search_threshold) {
+ this.search_field[0].readOnly = true;
+ this.container.addClass("chosen-container-single-nosearch");
+ } else {
+ this.search_field[0].readOnly = false;
+ this.container.removeClass("chosen-container-single-nosearch");
+ }
+ }
+ this.update_results_content(this.results_option_build({
+ first: true
+ }));
+ this.search_field_disabled();
+ this.show_search_field_default();
+ this.search_field_scale();
+ return this.parsing = false;
+ };
+
+ Chosen.prototype.result_do_highlight = function(el) {
+ var high_bottom, high_top, maxHeight, visible_bottom, visible_top;
+ if (el.length) {
+ this.result_clear_highlight();
+ this.result_highlight = el;
+ this.result_highlight.addClass("highlighted");
+ maxHeight = parseInt(this.search_results.css("maxHeight"), 10);
+ visible_top = this.search_results.scrollTop();
+ visible_bottom = maxHeight + visible_top;
+ high_top = this.result_highlight.position().top + this.search_results.scrollTop();
+ high_bottom = high_top + this.result_highlight.outerHeight();
+ if (high_bottom >= visible_bottom) {
+ return this.search_results.scrollTop((high_bottom - maxHeight) > 0 ? high_bottom - maxHeight : 0);
+ } else if (high_top < visible_top) {
+ return this.search_results.scrollTop(high_top);
+ }
+ }
+ };
+
+ Chosen.prototype.result_clear_highlight = function() {
+ if (this.result_highlight) {
+ this.result_highlight.removeClass("highlighted");
+ }
+ return this.result_highlight = null;
+ };
+
+ Chosen.prototype.results_show = function() {
+ if (this.is_multiple && this.max_selected_options <= this.choices_count()) {
+ this.form_field_jq.trigger("chosen:maxselected", {
+ chosen: this
+ });
+ return false;
+ }
+ this.container.addClass("chosen-with-drop");
+ this.results_showing = true;
+ this.search_field.focus();
+ this.search_field.val(this.search_field.val());
+ this.winnow_results();
+ return this.form_field_jq.trigger("chosen:showing_dropdown", {
+ chosen: this
+ });
+ };
+
+ Chosen.prototype.update_results_content = function(content) {
+ return this.search_results.html(content);
+ };
+
+ Chosen.prototype.results_hide = function() {
+ if (this.results_showing) {
+ this.result_clear_highlight();
+ this.container.removeClass("chosen-with-drop");
+ this.form_field_jq.trigger("chosen:hiding_dropdown", {
+ chosen: this
+ });
+ }
+ return this.results_showing = false;
+ };
+
+ Chosen.prototype.set_tab_index = function(el) {
+ var ti;
+ if (this.form_field.tabIndex) {
+ ti = this.form_field.tabIndex;
+ this.form_field.tabIndex = -1;
+ return this.search_field[0].tabIndex = ti;
+ }
+ };
+
+ Chosen.prototype.set_label_behavior = function() {
+ var _this = this;
+ this.form_field_label = this.form_field_jq.parents("label");
+ if (!this.form_field_label.length && this.form_field.id.length) {
+ this.form_field_label = $("label[for='" + this.form_field.id + "']");
+ }
+ if (this.form_field_label.length > 0) {
+ return this.form_field_label.bind('click.chosen', function(evt) {
+ if (_this.is_multiple) {
+ return _this.container_mousedown(evt);
+ } else {
+ return _this.activate_field();
+ }
+ });
+ }
+ };
+
+ Chosen.prototype.show_search_field_default = function() {
+ if (this.is_multiple && this.choices_count() < 1 && !this.active_field) {
+ this.search_field.val(this.default_text);
+ return this.search_field.addClass("default");
+ } else {
+ this.search_field.val("");
+ return this.search_field.removeClass("default");
+ }
+ };
+
+ Chosen.prototype.search_results_mouseup = function(evt) {
+ var target;
+ target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first();
+ if (target.length) {
+ this.result_highlight = target;
+ this.result_select(evt);
+ return this.search_field.focus();
+ }
+ };
+
+ Chosen.prototype.search_results_mouseover = function(evt) {
+ var target;
+ target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first();
+ if (target) {
+ return this.result_do_highlight(target);
+ }
+ };
+
+ Chosen.prototype.search_results_mouseout = function(evt) {
+ if ($(evt.target).hasClass("active-result" || $(evt.target).parents('.active-result').first())) {
+ return this.result_clear_highlight();
+ }
+ };
+
+ Chosen.prototype.choice_build = function(item) {
+ var choice, close_link,
+ _this = this;
+ choice = $('<li />', {
+ "class": "search-choice"
+ }).html("<span>" + (this.choice_label(item)) + "</span>");
+ if (item.disabled) {
+ choice.addClass('search-choice-disabled');
+ } else {
+ close_link = $('<a />', {
+ "class": 'search-choice-close',
+ 'data-option-array-index': item.array_index
+ });
+ close_link.bind('click.chosen', function(evt) {
+ return _this.choice_destroy_link_click(evt);
+ });
+ choice.append(close_link);
+ }
+ return this.search_container.before(choice);
+ };
+
+ Chosen.prototype.choice_destroy_link_click = function(evt) {
+ evt.preventDefault();
+ evt.stopPropagation();
+ if (!this.is_disabled) {
+ return this.choice_destroy($(evt.target));
+ }
+ };
+
+ Chosen.prototype.choice_destroy = function(link) {
+ if (this.result_deselect(link[0].getAttribute("data-option-array-index"))) {
+ this.show_search_field_default();
+ if (this.is_multiple && this.choices_count() > 0 && this.search_field.val().length < 1) {
+ this.results_hide();
+ }
+ link.parents('li').first().remove();
+ return this.search_field_scale();
+ }
+ };
+
+ Chosen.prototype.results_reset = function() {
+ this.reset_single_select_options();
+ this.form_field.options[0].selected = true;
+ this.single_set_selected_text();
+ this.show_search_field_default();
+ this.results_reset_cleanup();
+ this.form_field_jq.trigger("change");
+ if (this.active_field) {
+ return this.results_hide();
+ }
+ };
+
+ Chosen.prototype.results_reset_cleanup = function() {
+ this.current_selectedIndex = this.form_field.selectedIndex;
+ return this.selected_item.find("abbr").remove();
+ };
+
+ Chosen.prototype.result_select = function(evt) {
+ var high, item;
+ if (this.result_highlight) {
+ high = this.result_highlight;
+ this.result_clear_highlight();
+ if (this.is_multiple && this.max_selected_options <= this.choices_count()) {
+ this.form_field_jq.trigger("chosen:maxselected", {
+ chosen: this
+ });
+ return false;
+ }
+ if (this.is_multiple) {
+ high.removeClass("active-result");
+ } else {
+ this.reset_single_select_options();
+ }
+ high.addClass("result-selected");
+ item = this.results_data[high[0].getAttribute("data-option-array-index")];
+ item.selected = true;
+ this.form_field.options[item.options_index].selected = true;
+ this.selected_option_count = null;
+ if (this.is_multiple) {
+ this.choice_build(item);
+ } else {
+ this.single_set_selected_text(this.choice_label(item));
+ }
+ if (!((evt.metaKey || evt.ctrlKey) && this.is_multiple)) {
+ this.results_hide();
+ }
+ this.search_field.val("");
+ if (this.is_multiple || this.form_field.selectedIndex !== this.current_selectedIndex) {
+ this.form_field_jq.trigger("change", {
+ 'selected': this.form_field.options[item.options_index].value
+ });
+ }
+ this.current_selectedIndex = this.form_field.selectedIndex;
+ evt.preventDefault();
+ return this.search_field_scale();
+ }
+ };
+
+ Chosen.prototype.single_set_selected_text = function(text) {
+ if (text == null) {
+ text = this.default_text;
+ }
+ if (text === this.default_text) {
+ this.selected_item.addClass("chosen-default");
+ } else {
+ this.single_deselect_control_build();
+ this.selected_item.removeClass("chosen-default");
+ }
+ return this.selected_item.find("span").html(text);
+ };
+
+ Chosen.prototype.result_deselect = function(pos) {
+ var result_data;
+ result_data = this.results_data[pos];
+ if (!this.form_field.options[result_data.options_index].disabled) {
+ result_data.selected = false;
+ this.form_field.options[result_data.options_index].selected = false;
+ this.selected_option_count = null;
+ this.result_clear_highlight();
+ if (this.results_showing) {
+ this.winnow_results();
+ }
+ this.form_field_jq.trigger("change", {
+ deselected: this.form_field.options[result_data.options_index].value
+ });
+ this.search_field_scale();
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+ Chosen.prototype.single_deselect_control_build = function() {
+ if (!this.allow_single_deselect) {
+ return;
+ }
+ if (!this.selected_item.find("abbr").length) {
+ this.selected_item.find("span").first().after("<abbr class=\"search-choice-close\"></abbr>");
+ }
+ return this.selected_item.addClass("chosen-single-with-deselect");
+ };
+
+ Chosen.prototype.get_search_text = function() {
+ return $('<div/>').text($.trim(this.search_field.val())).html();
+ };
+
+ Chosen.prototype.winnow_results_set_highlight = function() {
+ var do_high, selected_results;
+ selected_results = !this.is_multiple ? this.search_results.find(".result-selected.active-result") : [];
+ do_high = selected_results.length ? selected_results.first() : this.search_results.find(".active-result").first();
+ if (do_high != null) {
+ return this.result_do_highlight(do_high);
+ }
+ };
+
+ Chosen.prototype.no_results = function(terms) {
+ var no_results_html;
+ no_results_html = $('<li class="no-results">' + this.results_none_found + ' "<span></span>"</li>');
+ no_results_html.find("span").first().html(terms);
+ this.search_results.append(no_results_html);
+ return this.form_field_jq.trigger("chosen:no_results", {
+ chosen: this
+ });
+ };
+
+ Chosen.prototype.no_results_clear = function() {
+ return this.search_results.find(".no-results").remove();
+ };
+
+ Chosen.prototype.keydown_arrow = function() {
+ var next_sib;
+ if (this.results_showing && this.result_highlight) {
+ next_sib = this.result_highlight.nextAll("li.active-result").first();
+ if (next_sib) {
+ return this.result_do_highlight(next_sib);
+ }
+ } else {
+ return this.results_show();
+ }
+ };
+
+ Chosen.prototype.keyup_arrow = function() {
+ var prev_sibs;
+ if (!this.results_showing && !this.is_multiple) {
+ return this.results_show();
+ } else if (this.result_highlight) {
+ prev_sibs = this.result_highlight.prevAll("li.active-result");
+ if (prev_sibs.length) {
+ return this.result_do_highlight(prev_sibs.first());
+ } else {
+ if (this.choices_count() > 0) {
+ this.results_hide();
+ }
+ return this.result_clear_highlight();
+ }
+ }
+ };
+
+ Chosen.prototype.keydown_backstroke = function() {
+ var next_available_destroy;
+ if (this.pending_backstroke) {
+ this.choice_destroy(this.pending_backstroke.find("a").first());
+ return this.clear_backstroke();
+ } else {
+ next_available_destroy = this.search_container.siblings("li.search-choice").last();
+ if (next_available_destroy.length && !next_available_destroy.hasClass("search-choice-disabled")) {
+ this.pending_backstroke = next_available_destroy;
+ if (this.single_backstroke_delete) {
+ return this.keydown_backstroke();
+ } else {
+ return this.pending_backstroke.addClass("search-choice-focus");
+ }
+ }
+ }
+ };
+
+ Chosen.prototype.clear_backstroke = function() {
+ if (this.pending_backstroke) {
+ this.pending_backstroke.removeClass("search-choice-focus");
+ }
+ return this.pending_backstroke = null;
+ };
+
+ Chosen.prototype.keydown_checker = function(evt) {
+ var stroke, _ref1;
+ stroke = (_ref1 = evt.which) != null ? _ref1 : evt.keyCode;
+ this.search_field_scale();
+ if (stroke !== 8 && this.pending_backstroke) {
+ this.clear_backstroke();
+ }
+ switch (stroke) {
+ case 8:
+ this.backstroke_length = this.search_field.val().length;
+ break;
+ case 9:
+ if (this.results_showing && !this.is_multiple) {
+ this.result_select(evt);
+ }
+ this.mouse_on_container = false;
+ break;
+ case 13:
+ if (this.results_showing) {
+ evt.preventDefault();
+ }
+ break;
+ case 32:
+ if (this.disable_search) {
+ evt.preventDefault();
+ }
+ break;
+ case 38:
+ evt.preventDefault();
+ this.keyup_arrow();
+ break;
+ case 40:
+ evt.preventDefault();
+ this.keydown_arrow();
+ break;
+ }
+ };
+
+ Chosen.prototype.search_field_scale = function() {
+ var div, f_width, h, style, style_block, styles, w, _i, _len;
+ if (this.is_multiple) {
+ h = 0;
+ w = 0;
+ style_block = "position:absolute; left: -1000px; top: -1000px; display:none;";
+ styles = ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height', 'text-transform', 'letter-spacing'];
+ for (_i = 0, _len = styles.length; _i < _len; _i++) {
+ style = styles[_i];
+ style_block += style + ":" + this.search_field.css(style) + ";";
+ }
+ div = $('<div />', {
+ 'style': style_block
+ });
+ div.text(this.search_field.val());
+ $('body').append(div);
+ w = div.width() + 25;
+ div.remove();
+ f_width = this.container.outerWidth();
+ if (w > f_width - 10) {
+ w = f_width - 10;
+ }
+ return this.search_field.css({
+ 'width': w + 'px'
+ });
+ }
+ };
+
+ return Chosen;
+
+ })(AbstractChosen);
+
+}).call(this);
diff --git a/platform/www/lib/plugins/farmer/script/plugins.js b/platform/www/lib/plugins/farmer/script/plugins.js
new file mode 100644
index 0000000..f092b39
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/script/plugins.js
@@ -0,0 +1,149 @@
+/**
+ * DokuWiki Plugin farmer (JS for plugin management)
+ *
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Michael Große <grosse@cosmocode.de>
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ */
+(function () {
+ 'use strict';
+
+ jQuery(function () {
+ // general animal select
+ var $animalSelect = jQuery('select.farmer_chosen_animals');
+ $animalSelect.chosen({
+ width: '100%',
+ search_contains: true,
+ allow_single_deselect: true,
+ "placeholder_text_single": LANG.plugins.farmer.animalSelect
+ });
+
+ jQuery('select.acl_chosen').chosen({
+ disable_search: true,
+ width: '100%'
+ });
+
+
+ // Plugin Management for all Animals
+ var $formAllAnimals = jQuery('#farmer__pluginsforall');
+ $formAllAnimals.find('select')
+ .change(function () {
+ $formAllAnimals.find('button').prop('disabled', false);
+ })
+ .chosen({
+ width: '100%',
+ search_contains: true,
+ "placeholder_text_single": LANG.plugins.farmer.pluginSelect
+ })
+ ;
+
+ // Plugin Management for single Animals
+ var $formSingleAnimal = jQuery('#farmer__pluginsforone');
+ $formSingleAnimal.find('select')
+ .change(function () {
+ var animal = jQuery(this).val();
+ $formSingleAnimal.find('button').prop('disabled', true);
+ jQuery.post(
+ DOKU_BASE + 'lib/exe/ajax.php',
+ {
+ call: 'plugin_farmer_getPlugins_' + animal
+ },
+ function (data) {
+ $formSingleAnimal.find('div.output').html(data);
+ $formSingleAnimal.find('button').prop('disabled', false);
+ },
+ 'html'
+ )}
+ )
+ .chosen({
+ width: '100%',
+ search_contains: true,
+ "placeholder_text_single": LANG.plugins.farmer.animalSelect
+ })
+ ;
+
+ /**
+ * Handle clicks on the matrix
+ */
+ var $formPluginMatrix = jQuery('#farmer__pluginmatrix').hide();
+ $formPluginMatrix.on('click', 'td', function () {
+ var $td = jQuery(this);
+ $td.html('⌛').css('background-color','transparent');
+ jQuery.post(
+ DOKU_BASE + 'lib/exe/ajax.php',
+ {
+ call: 'plugin_farmer_modPlugin',
+ plugin: $td.data('plugin'),
+ ani: $td.data('animal')
+ },
+ function (data) {
+ $td.replaceWith(data);
+ },
+ 'html'
+ );
+ });
+
+ /**
+ * show the matrix interface
+ */
+ function showMatrix() {
+ jQuery.post(
+ DOKU_BASE + 'lib/exe/ajax.php',
+ {
+ call: 'plugin_farmer_getPluginMatrix'
+ },
+ function (data) {
+ $formPluginMatrix.html(data);
+ $formPluginMatrix.show();
+ },
+ 'html'
+ )
+ }
+
+ // make sure there's enough space for the dropdown
+ $animalSelect.on('chosen:showing_dropdown', function (evt, params) {
+ jQuery(evt.target).parent('fieldset').animate({
+ "padding-bottom": '20em'
+ }, 400);
+ }).on('chosen:hiding_dropdown', function (evt, params) {
+ jQuery(evt.target).parent('fieldset').animate({
+ "padding-bottom": '7px'
+ }, 400);
+ });
+
+ var $aclPolicyFieldset = jQuery('#aclPolicyFieldset');
+ if ($aclPolicyFieldset.length) {
+ $animalSelect.on('change', function (evt, params) {
+ var $this = jQuery(this);
+ if ($this.val() === '') {
+ $aclPolicyFieldset.slideDown();
+ } else {
+ $aclPolicyFieldset.slideUp();
+ }
+ });
+ }
+
+
+
+
+ jQuery("input[name=bulkSingleSwitch]:radio").change(function () {
+ if (jQuery('#farmer__bulk').prop("checked")) {
+ $formAllAnimals.show();
+ $formSingleAnimal.hide();
+ $formPluginMatrix.hide();
+ } else if (jQuery('#farmer__single').prop("checked")) {
+ $formAllAnimals.hide();
+ $formSingleAnimal.show();
+ $formPluginMatrix.hide();
+ } else {
+ $formAllAnimals.hide();
+ $formSingleAnimal.hide();
+ showMatrix();
+ }
+ });
+ jQuery('#farmer__bulk').click();
+
+
+ });
+
+})();
diff --git a/platform/www/lib/plugins/farmer/style.less b/platform/www/lib/plugins/farmer/style.less
new file mode 100644
index 0000000..905078c
--- /dev/null
+++ b/platform/www/lib/plugins/farmer/style.less
@@ -0,0 +1,104 @@
+#plugin__farmer_admin {
+
+ .panelHeader {
+ background-color: #eee;
+ margin: 0;
+ padding: 10px 10px 8px;
+ overflow: hidden;
+ border-right: 1px solid @ini_border;
+ border-left: 1px solid @ini_border;
+ }
+
+ .panelMain,
+ .panelFooter {
+ padding: 1em;
+ border-right: 1px solid @ini_border;
+ border-left: 1px solid @ini_border;
+ }
+
+ .panelFooter {
+ border-bottom: 1px solid @ini_border;
+ }
+
+ form {
+ display: block;
+ text-align: center;
+
+ fieldset {
+ width: 80%;
+ padding: 1em;
+ }
+
+ label {
+ text-align: left;
+ display: block;
+ margin-bottom: 0.5em;
+
+ &:hover {
+ background-color: @ini_background_alt;
+ }
+
+ span {
+ display: inline-block;
+ width: 40%;
+ }
+ }
+
+ .chosen-container {
+ margin-bottom: 0.5em;
+ }
+
+ button {
+ margin: 1em;
+ }
+ }
+
+ .pluginmatrix {
+ width: 80%;
+ margin: 1em auto;
+
+ table {
+ thead th {
+ position: relative;
+ height: 8em;
+ vertical-align: bottom;
+ overflow: visible;
+ background-color: transparent;
+ border: none;
+
+ div {
+ transform-origin: bottom left;
+ transform: rotate(-60deg);
+ position: absolute;
+ left: 1em;
+ bottom: 0;
+ z-index: 5;
+ }
+ }
+
+ tbody {
+ position: relative;
+
+ td {
+ cursor: pointer;
+ }
+
+ th.off,
+ td.off {
+ background-color: #c33;
+ }
+
+ th.on,
+ td.on {
+ background-color: #3c3;
+ }
+
+ th.default,
+ td.default {
+ opacity: 0.5;
+ }
+ }
+ }
+ }
+
+}