From: <nn...@us...> - 2010-10-15 18:43:35
|
Revision: 3781 http://tora.svn.sourceforge.net/tora/?rev=3781&view=rev Author: nneul Date: 2010-10-15 18:43:28 +0000 (Fri, 15 Oct 2010) Log Message: ----------- patch from andreas for shared oracle plan table support Modified Paths: -------------- trunk/tora/src/toanalyze.cpp trunk/tora/src/toconf.h trunk/tora/src/toconfiguration.cpp trunk/tora/src/toconfiguration.h trunk/tora/src/tooracleconnection.cpp trunk/tora/src/tooracleconnection_trotl.cpp trunk/tora/src/tooraclesettingui.ui trunk/tora/src/toresultplan.cpp Modified: trunk/tora/src/toanalyze.cpp =================================================================== --- trunk/tora/src/toanalyze.cpp 2010-10-15 09:49:17 UTC (rev 3780) +++ trunk/tora/src/toanalyze.cpp 2010-10-15 18:43:28 UTC (rev 3781) @@ -398,7 +398,7 @@ try { Plans->query(toSQL::string(SQLListPlans, connection).arg( - toConfigurationSingle::Instance().planTable())); + toConfigurationSingle::Instance().planTable(connection.user()))); } TOCATCH; Modified: trunk/tora/src/toconf.h =================================================================== --- trunk/tora/src/toconf.h 2010-10-15 09:49:17 UTC (rev 3780) +++ trunk/tora/src/toconf.h 2010-10-15 18:43:28 UTC (rev 3781) @@ -124,6 +124,7 @@ #define DEFAULT_MAX_CONTENT 100 #define CONF_KEEP_PLANS "KeepPlans" // default: false #define CONF_VSQL_PLANS "VSqlPlans" // default: true +#define CONF_SHARED_PLAN "SharedPlan" // default: false #define CONF_RESTORE_SESSION "RestoreSession" #define CONF_DEFAULT_SESSION "DefaultSession" #define DEFAULT_SESSION ".tora.tse" Modified: trunk/tora/src/toconfiguration.cpp =================================================================== --- trunk/tora/src/toconfiguration.cpp 2010-10-15 09:49:17 UTC (rev 3780) +++ trunk/tora/src/toconfiguration.cpp 2010-10-15 18:43:28 UTC (rev 3781) @@ -114,6 +114,7 @@ int m_maxContent; bool m_keepPlans; bool m_vsqlPlans; + bool m_sharedPlan; bool m_restoreSession; QString m_defaultSession; int m_defaultFormat; @@ -359,6 +360,7 @@ m_maxContent = s.value(CONF_MAX_CONTENT, DEFAULT_MAX_CONTENT).toInt(); m_keepPlans = s.value(CONF_KEEP_PLANS, false).toBool(); m_vsqlPlans = s.value(CONF_VSQL_PLANS, true).toBool(); + m_sharedPlan = s.value(CONF_SHARED_PLAN, false).toBool(); m_restoreSession = s.value(CONF_RESTORE_SESSION, false).toBool(); m_defaultSession = s.value(CONF_DEFAULT_SESSION, getSpecialDir() + DEFAULT_SESSION).toString(); // FIXME! @@ -589,6 +591,7 @@ s.setValue(CONF_MAX_CONTENT, m_maxContent); s.setValue(CONF_KEEP_PLANS, m_keepPlans); s.setValue(CONF_VSQL_PLANS, m_vsqlPlans); + s.setValue(CONF_SHARED_PLAN, m_sharedPlan); s.setValue(CONF_RESTORE_SESSION, m_restoreSession); s.setValue(CONF_DEFAULT_SESSION, m_defaultSession); s.setValue(CONF_DEFAULT_FORMAT, m_defaultFormat); @@ -1072,9 +1075,12 @@ p->m_maxColDisp = v; } -QString toConfiguration::planTable() +QString toConfiguration::planTable(QString schema) { - return p->m_planTable; + if(p->m_sharedPlan || p->m_planTable.contains('.') || schema.isNull()) + return p->m_planTable; + + return schema + '.' + p->m_planTable; } void toConfiguration::setPlanTable(const QString & v) { @@ -1449,6 +1455,15 @@ p->m_vsqlPlans = v; } +bool toConfiguration::sharedPlan() +{ + return p->m_sharedPlan; +} +void toConfiguration::setSharedPlan(bool v) +{ + p->m_sharedPlan = v; +} + bool toConfiguration::restoreSession() { return p->m_restoreSession; Modified: trunk/tora/src/toconfiguration.h =================================================================== --- trunk/tora/src/toconfiguration.h 2010-10-15 09:49:17 UTC (rev 3780) +++ trunk/tora/src/toconfiguration.h 2010-10-15 18:43:28 UTC (rev 3781) @@ -88,7 +88,7 @@ int maxColDisp(); void setMaxColDisp(int v); - QString planTable(); + QString planTable(QString schema); void setPlanTable(const QString & v); QString planCheckpoint(); @@ -213,6 +213,9 @@ bool vsqlPlans(); void setVsqlPlans(bool v); + bool sharedPlan(); + void setSharedPlan(bool v); + bool restoreSession(); void setRestoreSession(bool v); Modified: trunk/tora/src/tooracleconnection.cpp =================================================================== --- trunk/tora/src/tooracleconnection.cpp 2010-10-15 09:49:17 UTC (rev 3780) +++ trunk/tora/src/tooracleconnection.cpp 2010-10-15 18:43:28 UTC (rev 3781) @@ -1411,10 +1411,11 @@ setupUi(this); DefaultDate->setText(toConfigurationSingle::Instance().dateFormat()); CheckPoint->setText(toConfigurationSingle::Instance().planCheckpoint()); - ExplainPlan->setText(toConfigurationSingle::Instance().planTable()); + ExplainPlan->setText(toConfigurationSingle::Instance().planTable(NULL)); OpenCursors->setValue(toConfigurationSingle::Instance().openCursors()); KeepPlans->setChecked(toConfigurationSingle::Instance().keepPlans()); VsqlPlans->setChecked(toConfigurationSingle::Instance().vsqlPlans()); + SharedPlan->setChecked(toConfigurationSingle::Instance().sharedPlan()); int len = toConfigurationSingle::Instance().maxLong(); if (len >= 0) { @@ -1437,6 +1438,7 @@ { toConfigurationSingle::Instance().setKeepPlans(KeepPlans->isChecked()); toConfigurationSingle::Instance().setVsqlPlans(VsqlPlans->isChecked()); + toConfigurationSingle::Instance().setSharedPlan(SharedPlan->isChecked()); toConfigurationSingle::Instance().setDateFormat(DefaultDate->text()); // try to change NLS for already running sessions Modified: trunk/tora/src/tooracleconnection_trotl.cpp =================================================================== --- trunk/tora/src/tooracleconnection_trotl.cpp 2010-10-15 09:49:17 UTC (rev 3780) +++ trunk/tora/src/tooracleconnection_trotl.cpp 2010-10-15 18:43:28 UTC (rev 3781) @@ -1784,10 +1784,11 @@ setupUi(this); DefaultDate->setText(toConfigurationSingle::Instance().dateFormat()); CheckPoint->setText(toConfigurationSingle::Instance().planCheckpoint()); - ExplainPlan->setText(toConfigurationSingle::Instance().planTable()); + ExplainPlan->setText(toConfigurationSingle::Instance().planTable(NULL)); OpenCursors->setValue(toConfigurationSingle::Instance().openCursors()); KeepPlans->setChecked(toConfigurationSingle::Instance().keepPlans()); VsqlPlans->setChecked(toConfigurationSingle::Instance().vsqlPlans()); + SharedPlan->setChecked(toConfigurationSingle::Instance().sharedPlan()); int len = toConfigurationSingle::Instance().maxLong(); if (len >= 0) { @@ -1812,6 +1813,7 @@ { toConfigurationSingle::Instance().setKeepPlans(KeepPlans->isChecked()); toConfigurationSingle::Instance().setVsqlPlans(VsqlPlans->isChecked()); + toConfigurationSingle::Instance().setSharedPlan(SharedPlan->isChecked()); toConfigurationSingle::Instance().setDateFormat(DefaultDate->text()); // try to change NLS for already running sessions Modified: trunk/tora/src/tooraclesettingui.ui =================================================================== --- trunk/tora/src/tooraclesettingui.ui 2010-10-15 09:49:17 UTC (rev 3780) +++ trunk/tora/src/tooraclesettingui.ui 2010-10-15 18:43:28 UTC (rev 3781) @@ -1,230 +1,263 @@ -<ui version="4.0" stdsetdef="1" > - <author></author> - <comment></comment> - <exportmacro></exportmacro> - <class>toOracleSettingUI</class> - <widget class="QWidget" name="toOracleSettingUI" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>361</width> - <height>287</height> - </rect> - </property> - <property name="windowTitle" > - <string>Form1</string> - </property> - <layout class="QGridLayout" > - <property name="margin" > - <number>11</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item row="1" column="0" > - <widget class="QLabel" name="TextLabel6_2_2_2" > - <property name="text" > - <string>&Default date format</string> - </property> - <property name="buddy" > - <cstring>DefaultDate</cstring> - </property> - <property name="toolTip" > - <string>The default dateformat to use when querying the database.</string> - </property> - <property name="wordWrap" > - <bool>false</bool> - </property> - </widget> - </item> - <item row="0" column="0" > - <widget class="QLabel" name="TextLabel6_2_3" > - <property name="text" > - <string>&Checkpoint name</string> - </property> - <property name="buddy" > - <cstring>CheckPoint</cstring> - </property> - <property name="toolTip" > - <string>The name of the checkpoint used when needed to rollback work.</string> - </property> - <property name="wordWrap" > - <bool>false</bool> - </property> - </widget> - </item> - <item rowspan="1" row="1" column="1" colspan="2" > - <widget class="QLineEdit" name="DefaultDate" /> - </item> - <item rowspan="1" row="0" column="1" colspan="2" > - <widget class="QLineEdit" name="CheckPoint" /> - </item> - <item row="3" column="0" > - <widget class="QLabel" name="TextLabel6_3_2" > - <property name="text" > - <string>&Max long and LOB data length</string> - </property> - <property name="buddy" > - <cstring>ExplainPlan</cstring> - </property> - <property name="toolTip" > - <string>Max length to read from LOB or LONG data fields. LONG:s can not be specified unlimited but will be defaulted to 33000 if unlimited.</string> - </property> - <property name="wordWrap" > - <bool>false</bool> - </property> - </widget> - </item> - <item row="3" column="2" > - <widget class="QCheckBox" name="Unlimited" > - <property name="text" > - <string>Unlimited</string> - </property> - <property name="checked" > - <bool>true</bool> - </property> - </widget> - </item> - <item row="3" column="1" > - <widget class="QLineEdit" name="MaxLong" > - <property name="enabled" > - <bool>false</bool> - </property> - </widget> - </item> - <item row="6" column="2" > - <spacer name="Spacer6" > - <property name="sizeHint" > - <size> - <width>20</width> - <height>20</height> - </size> - </property> - <property name="sizeType" > - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="orientation" > - <enum>Qt::Vertical</enum> - </property> - </spacer> - </item> - <item rowspan="1" row="5" column="0" colspan="1" > - <spacer name="Spacer2_2" > - <property name="sizeHint" > - <size> - <width>20</width> - <height>20</height> - </size> - </property> - <property name="sizeType" > - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="orientation" > - <enum>Qt::Horizontal</enum> - </property> - </spacer> - </item> - <item row="5" column="1" > - <widget class="QPushButton" name="CreatePlanTable" > - <property name="enabled" > - <bool>false</bool> - </property> - <property name="sizePolicy" > - <sizepolicy> - <hsizetype>0</hsizetype> - <vsizetype>0</vsizetype> - </sizepolicy> - </property> - <property name="text" > - <string>Create Table</string> - </property> - </widget> - </item> - <item row="5" column="2" > - <widget class="QCheckBox" name="VsqlPlans" > - <property name="text" > - <string>&V$SQL_PLAN</string> - </property> - <property name="toolTip" > - <string>Use V$SQL_PLAN when possible.</string> - </property> - </widget> - </item> - <item row="4" column="0" > - <widget class="QLabel" name="TextLabel6_3" > - <property name="text" > - <string>&Explain plan table</string> - </property> - <property name="buddy" > - <cstring>ExplainPlan</cstring> - </property> - <property name="toolTip" > - <string>Name of the table to put explain plan output in.</string> - </property> - <property name="wordWrap" > - <bool>false</bool> - </property> - </widget> - </item> - <item row="4" column="1" > - <widget class="QLineEdit" name="ExplainPlan" /> - </item> - <item row="4" column="2" > - <widget class="QCheckBox" name="KeepPlans" > - <property name="text" > - <string>&Keep plans</string> - </property> - <property name="toolTip" > - <string>Keep records for the plan explanations in the plan table.</string> - </property> - </widget> - </item> - <item row="2" column="2" > - <widget class="QSpinBox" name="OpenCursors" > - <property name="minimum" > - <number>1</number> - </property> - </widget> - </item> - <item rowspan="1" row="2" column="0" colspan="2" > - <widget class="QLabel" name="TextLabel1" > - <property name="text" > - <string>Maximum cursors to keep open</string> - </property> - <property name="buddy" > - <cstring>OpenCursors</cstring> - </property> - <property name="wordWrap" > - <bool>false</bool> - </property> - </widget> - </item> - </layout> - </widget> - <tabstops> - <tabstop>CheckPoint</tabstop> - <tabstop>DefaultDate</tabstop> - <tabstop>OpenCursors</tabstop> - <tabstop>MaxLong</tabstop> - <tabstop>Unlimited</tabstop> - <tabstop>ExplainPlan</tabstop> - <tabstop>KeepPlans</tabstop> - <tabstop>CreatePlanTable</tabstop> - <tabstop>VsqlPlans</tabstop> - </tabstops> - <connections> - <connection> - <sender>CreatePlanTable</sender> - <signal>clicked()</signal> - <receiver>toOracleSettingUI</receiver> - <slot>createPlanTable()</slot> - </connection> - <connection> - <sender>Unlimited</sender> - <signal>toggled(bool)</signal> - <receiver>MaxLong</receiver> - <slot>setDisabled(bool)</slot> - </connection> - </connections> +<ui version="4.0" > + <class>toOracleSettingUI</class> + <widget class="QWidget" name="toOracleSettingUI" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>631</width> + <height>288</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form1</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="7" column="2" > + <spacer name="Spacer6" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType" > + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="5" column="0" > + <spacer name="Spacer2_2" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType" > + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="TextLabel6_2_2_2" > + <property name="toolTip" > + <string>The default dateformat to use when querying the database.</string> + </property> + <property name="text" > + <string>&Default date format</string> + </property> + <property name="wordWrap" > + <bool>false</bool> + </property> + <property name="buddy" > + <cstring>DefaultDate</cstring> + </property> + </widget> + </item> + <item row="0" column="0" > + <widget class="QLabel" name="TextLabel6_2_3" > + <property name="toolTip" > + <string>The name of the checkpoint used when needed to rollback work.</string> + </property> + <property name="text" > + <string>&Checkpoint name</string> + </property> + <property name="wordWrap" > + <bool>false</bool> + </property> + <property name="buddy" > + <cstring>CheckPoint</cstring> + </property> + </widget> + </item> + <item row="1" column="1" colspan="2" > + <widget class="QLineEdit" name="DefaultDate" /> + </item> + <item row="0" column="1" colspan="2" > + <widget class="QLineEdit" name="CheckPoint" /> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="TextLabel6_3_2" > + <property name="toolTip" > + <string>Max length to read from LOB or LONG data fields. LONG:s can not be specified unlimited but will be defaulted to 33000 if unlimited.</string> + </property> + <property name="text" > + <string>&Max long and LOB data length</string> + </property> + <property name="wordWrap" > + <bool>false</bool> + </property> + <property name="buddy" > + <cstring>ExplainPlan</cstring> + </property> + </widget> + </item> + <item row="3" column="2" > + <widget class="QCheckBox" name="Unlimited" > + <property name="text" > + <string>Unlimited</string> + </property> + <property name="checked" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="3" column="1" > + <widget class="QLineEdit" name="MaxLong" > + <property name="enabled" > + <bool>false</bool> + </property> + </widget> + </item> + <item row="5" column="1" > + <widget class="QPushButton" name="CreatePlanTable" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Create Table</string> + </property> + </widget> + </item> + <item row="5" column="2" > + <widget class="QCheckBox" name="VsqlPlans" > + <property name="toolTip" > + <string>Use V$SQL_PLAN when possible.</string> + </property> + <property name="text" > + <string>use &V$SQL_PLAN</string> + </property> + </widget> + </item> + <item row="4" column="0" > + <widget class="QLabel" name="TextLabel6_3" > + <property name="toolTip" > + <string>Name of the table to put explain plan output in.</string> + </property> + <property name="text" > + <string>&Explain plan table</string> + </property> + <property name="wordWrap" > + <bool>false</bool> + </property> + <property name="buddy" > + <cstring>ExplainPlan</cstring> + </property> + </widget> + </item> + <item row="4" column="1" > + <widget class="QLineEdit" name="ExplainPlan" /> + </item> + <item row="4" column="2" > + <widget class="QCheckBox" name="KeepPlans" > + <property name="toolTip" > + <string>Keep records for the plan explanations in the plan table.</string> + </property> + <property name="text" > + <string>&Keep plans</string> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="TextLabel1" > + <property name="text" > + <string>Maximum cursors to keep open</string> + </property> + <property name="wordWrap" > + <bool>false</bool> + </property> + <property name="buddy" > + <cstring>OpenCursors</cstring> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QSpinBox" name="OpenCursors" > + <property name="minimum" > + <number>1</number> + </property> + </widget> + </item> + <item row="6" column="2" > + <widget class="QCheckBox" name="SharedPlan" > + <property name="enabled" > + <bool>true</bool> + </property> + <property name="text" > + <string>shared PLAN_TABLE</string> + </property> + <property name="checked" > + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>CheckPoint</tabstop> + <tabstop>DefaultDate</tabstop> + <tabstop>MaxLong</tabstop> + <tabstop>Unlimited</tabstop> + <tabstop>ExplainPlan</tabstop> + <tabstop>KeepPlans</tabstop> + <tabstop>CreatePlanTable</tabstop> + <tabstop>VsqlPlans</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>CreatePlanTable</sender> + <signal>clicked()</signal> + <receiver>toOracleSettingUI</receiver> + <slot>createPlanTable()</slot> + <hints> + <hint type="sourcelabel" > + <x>436</x> + <y>214</y> + </hint> + <hint type="destinationlabel" > + <x>20</x> + <y>20</y> + </hint> + </hints> + </connection> + <connection> + <sender>Unlimited</sender> + <signal>toggled(bool)</signal> + <receiver>MaxLong</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel" > + <x>563</x> + <y>142</y> + </hint> + <hint type="destinationlabel" > + <x>436</x> + <y>144</y> + </hint> + </hints> + </connection> + </connections> + <slots> + <signal>signal1()</signal> + </slots> </ui> Modified: trunk/tora/src/toresultplan.cpp =================================================================== --- trunk/tora/src/toresultplan.cpp 2010-10-15 09:49:17 UTC (rev 3780) +++ trunk/tora/src/toresultplan.cpp 2010-10-15 18:43:28 UTC (rev 3781) @@ -163,7 +163,7 @@ Ident = QString::fromLatin1("TOra ") + QString::number((int)time(NULL) + rand()); - QString planTable(toConfigurationSingle::Instance().planTable()); + QString planTable(toConfigurationSingle::Instance().planTable(conn.user())); QString sql = toShift(Statements); if (sql.isNull()) @@ -174,8 +174,8 @@ if (sql.length() > 0 && sql.at(sql.length() - 1).toLatin1() == ';') sql = sql.mid(0, sql.length() - 1); - QString explain = QString::fromLatin1("EXPLAIN PLAN SET STATEMENT_ID = '%1' INTO %2.%3 FOR %4"). - arg(Ident).arg(conn.user()).arg(planTable).arg(toSQLStripSpecifier(sql)); + QString explain = QString::fromLatin1("EXPLAIN PLAN SET STATEMENT_ID = '%1' INTO %2 FOR %3"). + arg(Ident).arg(planTable).arg(toSQLStripSpecifier(sql)); if (!User.isNull() && User != conn.user().toUpper()) { @@ -204,7 +204,7 @@ toSQL::string(SQLViewPlan, conn). // arg(toConfigurationSingle::Instance().planTable()). // Since EXPLAIN PLAN is always to conn.user() plan_table - arg(conn.user()+QString(".")+toConfigurationSingle::Instance().planTable()). + arg(explain). arg(Ident), par); Reading = true; } @@ -304,7 +304,7 @@ clear(); - QString planTable(toConfigurationSingle::Instance().planTable()); + QString planTable(toConfigurationSingle::Instance().planTable(connection().user())); Statements.clear(); if (sql.startsWith(QString::fromLatin1("SAVED:"))) @@ -372,7 +372,7 @@ // arg(toConfigurationSingle::Instance().planTable()). // Since EXPLAIN PLAN is always to conn.user() plan_table // and current_schema can be different - arg(conn.user()+QString(".")+toConfigurationSingle::Instance().planTable()). + arg(toConfigurationSingle::Instance().planTable(conn.user())). arg(Ident), par); Reading = true; } @@ -484,19 +484,28 @@ { if (str.startsWith(QString::fromLatin1("ORA-02404"))) { - QString planTable(toConfigurationSingle::Instance().planTable()); - int ret = TOMessageBox::warning(this, - tr("Plan table doesn't exist"), - tr("Specified plan table %1 didn't exist.\n" - "Should TOra try to create it?").arg(planTable), - tr("&Yes"), tr("&No"), QString::null, 0, 1); - if (ret == 0) - { - connection().execute(toSQL::string(toSQL::TOSQL_CREATEPLAN, - connection()).arg(planTable)); - QString t = sql(); - setSQL(QString::null); - query(t, params()); + QString planTable(toConfigurationSingle::Instance().planTable(connection().user())); + + // if shared plan table does not exist, do not try to create it + if(toConfigurationSingle::Instance().sharedPlan()) { + TOMessageBox::warning(this, + tr("Plan table doesn't exist"), + tr("Specified plan table %1 doesn't exist.").arg(planTable), + tr("&OK")); + } else { + int ret = TOMessageBox::warning(this, + tr("Plan table doesn't exist"), + tr("Specified plan table %1 doesn't exist.\n" + "Should TOra try to create it?").arg(planTable), + tr("&Yes"), tr("&No"), QString::null, 0, 1); + if (ret == 0) + { + connection().execute(toSQL::string(toSQL::TOSQL_CREATEPLAN, + connection()).arg(planTable)); + QString t = sql(); + setSQL(QString::null); + query(t, params()); + } } } else This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |