diff --git a/root/develop/generate_migrations_data.php b/root/develop/generate_migrations_data.php
new file mode 100644
index 00000000..6f15362b
--- /dev/null
+++ b/root/develop/generate_migrations_data.php
@@ -0,0 +1,261 @@
+table_prefix . \'groups');
+$php_ex = substr(strrchr(__FILE__, '.'), 1);
+
+$config_entry = $portal_config_entry = $db_data = array();
+$root_path = '../'; // one directory down
+
+function set_config($name, $val)
+{
+ global $config_entry;
+
+ if (isset($config_entry[$name]))
+ {
+ trigger_error('Duplicate entry: ' . $name);
+ }
+
+ if (is_string($val))
+ {
+ $val = "'$val'";
+ }
+
+ if (empty($val))
+ {
+ $val = "''";
+ }
+
+ $config_entry[$name] = $val;
+}
+
+function set_portal_config($name, $val)
+{
+ global $portal_config_entry;
+
+ if (isset($portal_config_entry[$name]))
+ {
+ trigger_error('Duplicate entry: ' . $name);
+ }
+
+ if (is_string($val))
+ {
+ $val = "'$val'";
+ }
+
+ if (empty($val))
+ {
+ $val = "''";
+ }
+
+ $portal_config_entry[$name] = $val;
+}
+
+$db = new db($db_data);
+board3_get_install_data($db, $root_path, $php_ex, $db_data);
+
+echo 'set_config entries for migrations:
';
+foreach ($config_entry as $name => $val)
+{
+ echo 'array(\'config.add\', array(\'' . $name . '\', ' . $val . ')),
';
+}
+echo '';
+
+echo '
set_portal_config entries for migrations:
';
+foreach ($portal_config_entry as $name => $val)
+{
+ echo 'set_portal_config(\'' . $name . '\', ' . $val . '));
';
+}
+echo '';
+
+echo '
database entries:
';
+echo $db_data . '
';
+
+/**
+* This function will install the basic set of portal modules
+*
+* only set $purge_modules to false if you already know that the table is empty
+* set $u_action to where the user should be redirected after this
+* note that already existing data won't be deleted from the config and portal_config
+* just to make sure we don't overwrite anything, the IDs won't be reset
+* !! this function should usually only be executed once upon installing the portal !!
+* DO NOT set $purge_modules to false unless you want to auto-add all modules again after deleting them (i.e. if your database was corrupted)
+*/
+function board3_get_install_data($db, $root_path, $php_ex, &$db_data)
+{
+ $directory = $root_path . 'portal/modules/';
+ $db_data = '$board3_sql_query = array(
';
+
+ /*
+ * this is a list of the basic modules that will be installed
+ * module_name => array(module_column, module_order)
+ */
+ $modules_ary = array(
+ // left column
+ 'portal_main_menu' => array(1, 1),
+ 'portal_stylechanger' => array(1, 2),
+ 'portal_birthday_list' => array(1, 3),
+ 'portal_clock' => array(1, 4),
+ 'portal_search' => array(1, 5),
+ 'portal_attachments' => array(1, 6),
+ 'portal_topposters' => array(1, 7),
+ 'portal_latest_members' => array(1, 8),
+ 'portal_link_us' => array(1, 9),
+
+ // center column
+ 'portal_welcome' => array(2, 1),
+ 'portal_recent' => array(2, 2),
+ 'portal_announcements' => array(2, 3),
+ 'portal_news' => array(2, 4),
+ 'portal_poll' => array(2, 5),
+ 'portal_whois_online' => array(2, 6),
+
+ // right column
+ 'portal_user_menu' => array(3, 1),
+ 'portal_statistics' => array(3, 2),
+ 'portal_calendar' => array(3, 3),
+ 'portal_leaders' => array(3, 4),
+ 'portal_latest_bots' => array(3, 5),
+ 'portal_links' => array(3, 6),
+ );
+
+ foreach ($modules_ary as $module_name => $module_data)
+ {
+ $class_name = $module_name . '_module';
+ if (!class_exists($class_name))
+ {
+ include($directory . $module_name . '.' . $php_ex);
+ }
+ if (!class_exists($class_name))
+ {
+ trigger_error('Class not found', E_USER_ERROR);
+ }
+
+ $c_class = new $class_name();
+
+ $sql_ary = array(
+ 'module_classname' => substr($module_name, 7),
+ 'module_column' => $module_data[0],
+ 'module_order' => $module_data[1],
+ 'module_name' => $c_class->name,
+ 'module_image_src' => $c_class->image_src,
+ 'module_group_ids' => '',
+ 'module_image_width' => 16,
+ 'module_image_height' => 16,
+ 'module_status' => B3_MODULE_ENABLED,
+ );
+ $sql = 'INSERT INTO \' . $this->table_prefix . \'portal_modules ' . $db->sql_build_array('INSERT', $sql_ary);
+ $db->sql_query($sql);
+
+ $data1 = array();
+ $data2 = array();
+ $db_data .= 'array(
';
+ foreach ($sql_ary as $key => $val)
+ {
+ $key = (is_string($key)) ? '\'' . $key . '\'' : $key;
+ $val = (is_string($val)) ? '\'' . $val . '\'' : $val;
+ $db_data .= ' ' . $key . ' => ' . $val . ',
';
+ }
+ $db_data .= '),
';
+
+ $c_class->install($db->sql_id());
+ }
+}
+
+class db
+{
+ // start at 0
+ private $id = 0;
+
+ private $int_pointer = 0;
+
+ private $sql_ary = array();
+
+ private $sql_in_set = array();
+
+ private $data = array();
+
+ public function __construct(&$data)
+ {
+ $this->data = &$data;
+ }
+ public function sql_id()
+ {
+ return $this->id;
+ }
+
+ public function sql_query($sql)
+ {
+ if (strpos($sql, 'INSERT') !== false)
+ {
+ //$this->data[] = $sql;
+ }
+ $this->id++;
+ $this->sql_ary[$this->id] = $sql;
+ return $this->id;
+ }
+
+ public function sql_build_array($type, $ary)
+ {
+ $data1 = array();
+ $data2 = array();
+ foreach ($ary as $key => $val)
+ {
+ $data1[] = $key;
+ $data2[] = (is_string($val)) ? '\'' . $val . '\'' : $val;
+ }
+ return '(' . implode(', ', $data1) . ') VALUES (' . implode(', ', $data2) . ');';
+ }
+
+ public function sql_in_set($data1, $data2, $bool = -1)
+ {
+ $this->sql_in_set[$this->id + 1] = array($data1, $data2);
+ return '\' . $db->sql_in_set('. $data1 . ', array(' . implode(',', $data2) . (($bool !== -1) ? '), ' . $bool : '') . '))';
+ }
+
+ public function sql_fetchrow($id)
+ {
+ if (isset($this->sql_ary[$id]))
+ {
+ preg_match_all('/SELECT+[a-z0-9A-Z,_ ]+FROM/', $this->sql_ary[$id], $match);
+ if (!empty($match))
+ {
+ // cut "SELECT " and " FROM"
+ $match = substr($match[0][0], 7, strlen($match[0][0]) - 5 - 7);
+ $match = str_replace(', ', ',', $match);
+ $match = explode(',', $match);
+ if (isset($this->sql_in_set[$id][1][$this->int_pointer]))
+ {
+ $ret = array();
+ foreach ($match as $key)
+ {
+ if ($key == $this->sql_in_set[$id][0])
+ {
+ $ret[$key] = $this->sql_in_set[$id][1][$this->int_pointer];
+ }
+ else
+ {
+ $ret[$key] = "{foobar.{$key}.{$this->sql_in_set[$id][1][$this->int_pointer]}}";
+ }
+ }
+ $this->int_pointer++;;
+ return $ret;
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+}