DRC: Add an optional mode to report all track errors

Fixes: lp:1754442
* https://bugs.launchpad.net/kicad/+bug/1754442
This commit is contained in:
Jon Evans 2018-03-19 22:54:16 -04:00
parent 73408f3f21
commit c78171d01f
7 changed files with 271 additions and 88 deletions

View File

@ -220,6 +220,7 @@ void DIALOG_DRC_CONTROL::OnStartdrcClick( wxCommandEvent& event )
m_cbRefillZones->GetValue(),
m_cbCourtyardOverlap->GetValue(),
m_cbCourtyardMissing->GetValue(),
m_cbReportAllTrackErrors->GetValue(),
reportName, make_report );
DelDRCMarkers();
@ -294,6 +295,7 @@ void DIALOG_DRC_CONTROL::OnListUnconnectedClick( wxCommandEvent& event )
m_cbRefillZones->GetValue(),
m_cbCourtyardOverlap->GetValue(),
m_cbCourtyardMissing->GetValue(),
m_cbReportAllTrackErrors->GetValue(),
reportName, make_report );
DelDRCMarkers();

View File

@ -1,8 +1,8 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Feb 9 2018)
// C++ code generated with wxFormBuilder (version Nov 30 2016)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "dialog_drclistbox.h"
@ -108,6 +108,11 @@ DIALOG_DRC_CONTROL_BASE::DIALOG_DRC_CONTROL_BASE( wxWindow* parent, wxWindowID i
m_cbRefillZones = new wxCheckBox( this, wxID_ANY, _("Refill all zones before performing DRC"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerOptSettings->Add( m_cbRefillZones, 0, wxLEFT|wxRIGHT, 5 );
m_cbReportAllTrackErrors = new wxCheckBox( this, wxID_ANY, _("Report all errors for tracks (slower)"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbReportAllTrackErrors->SetToolTip( _("If selected, all DRC violations for tracks will be reported. This can be slow for complicated designs.\n\nIf unselected, only the first DRC violation will be reported for each track connection.") );
bSizerOptSettings->Add( m_cbReportAllTrackErrors, 0, wxALL, 5 );
m_cbCourtyardOverlap = new wxCheckBox( this, wxID_ANY, _("Check footprint courtyard overlap"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerOptSettings->Add( m_cbCourtyardOverlap, 0, wxLEFT|wxRIGHT, 5 );

View File

@ -14,7 +14,6 @@
<property name="file">dialog_drc_base</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="indent_with_spaces"></property>
<property name="internationalize">1</property>
<property name="name">dialog_drc_base</property>
<property name="namespace"></property>
@ -1284,6 +1283,94 @@
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Report all errors for tracks (slower)</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_cbReportAllTrackErrors</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip">If selected, all DRC violations for tracks will be reported. This can be slow for complicated designs.&#x0A;&#x0A;If unselected, only the first DRC violation will be reported for each track connection.</property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnCheckBox"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxLEFT|wxRIGHT</property>

View File

@ -1,8 +1,8 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Feb 9 2018)
// C++ code generated with wxFormBuilder (version Nov 30 2016)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#ifndef __DIALOG_DRC_BASE_H__
@ -11,6 +11,7 @@
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
class DIALOG_SHIM;
class DRCLISTBOX;
#include "dialog_shim.h"
@ -63,6 +64,7 @@ class DIALOG_DRC_CONTROL_BASE : public DIALOG_SHIM
wxStaticText* m_MicroViaMinTitle;
wxStaticText* m_MicroViaMinUnit;
wxCheckBox* m_cbRefillZones;
wxCheckBox* m_cbReportAllTrackErrors;
wxCheckBox* m_cbCourtyardOverlap;
wxCheckBox* m_cbCourtyardMissing;
wxStaticText* m_staticTextRpt;

View File

@ -135,6 +135,7 @@ DRC::DRC( PCB_EDIT_FRAME* aPcbWindow )
m_abortDRC = false;
m_drcInProgress = false;
m_refillZones = false; // Only fill zones if requested by user.
m_reportAllTrackErrors = false;
m_doCreateRptFile = false;
// m_rptFilename set to empty by its constructor
@ -165,9 +166,9 @@ int DRC::Drc( TRACK* aRefSegm, TRACK* aList )
if( !doTrackDrc( aRefSegm, aList, true ) )
{
wxASSERT( m_currentMarker );
if( m_currentMarker )
m_pcbEditorFrame->SetMsgPanel( m_currentMarker );
return BAD_DRC;
}
@ -711,11 +712,13 @@ void DRC::testTracks( wxWindow *aActiveWindow, bool aShowProgressBar )
if( !doTrackDrc( segm, segm->Next(), true ) )
{
wxASSERT( m_currentMarker );
if( m_currentMarker )
{
addMarkerToPcb ( m_currentMarker );
m_currentMarker = nullptr;
}
}
}
if( progressDialog )
progressDialog->Destroy();

View File

@ -174,6 +174,7 @@ private:
bool m_doFootprintOverlapping;
bool m_doNoCourtyardDefined;
bool m_refillZones;
bool m_reportAllTrackErrors;
wxString m_rptFilename;
@ -501,12 +502,14 @@ public:
* @param aKeepoutTest Tells whether to test keepout areas.
* @param aCourtyardTest Tells whether to test footprint courtyard overlap.
* @param aCourtyardMissingTest Tells whether to test missing courtyard definition in footprint.
* @param aReportAllTrackErrors Tells whether or not to stop checking track connections after the first error.
* @param aReportName A string telling the disk file report name entered.
* @param aSaveReport A boolean telling whether to generate disk file report.
*/
void SetSettings( bool aPad2PadTest, bool aUnconnectedTest,
bool aZonesTest, bool aKeepoutTest, bool aRefillZones,
bool aCourtyardTest, bool aCourtyardMissingTest,
bool aReportAllTrackErrors,
const wxString& aReportName, bool aSaveReport )
{
m_doPad2PadTest = aPad2PadTest;
@ -518,6 +521,7 @@ public:
m_doFootprintOverlapping = aCourtyardTest;
m_doNoCourtyardDefined = aCourtyardMissingTest;
m_refillZones = aRefillZones;
m_reportAllTrackErrors = aReportAllTrackErrors;
}

View File

@ -141,6 +141,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
LSET layerMask;
int net_code_ref;
wxPoint shape_pos;
bool success = true;
NETCLASSPTR netclass = aRefSeg->GetNetClass();
BOARD_DESIGN_SETTINGS& dsnSettings = m_pcb->GetDesignSettings();
@ -165,14 +166,21 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
{
if( refvia->GetWidth() < dsnSettings.m_MicroViasMinSize )
{
m_currentMarker = fillMarker( refvia, NULL,
DRCE_TOO_SMALL_MICROVIA, m_currentMarker );
addMarkerToPcb( fillMarker( refvia, NULL,
DRCE_TOO_SMALL_MICROVIA, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
if( refvia->GetDrillValue() < dsnSettings.m_MicroViasMinDrill )
{
m_currentMarker = fillMarker( refvia, NULL,
DRCE_TOO_SMALL_MICROVIA_DRILL, m_currentMarker );
addMarkerToPcb( fillMarker( refvia, NULL,
DRCE_TOO_SMALL_MICROVIA_DRILL, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
}
@ -180,14 +188,21 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
{
if( refvia->GetWidth() < dsnSettings.m_ViasMinSize )
{
m_currentMarker = fillMarker( refvia, NULL,
DRCE_TOO_SMALL_VIA, m_currentMarker );
addMarkerToPcb( fillMarker( refvia, NULL,
DRCE_TOO_SMALL_VIA, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
if( refvia->GetDrillValue() < dsnSettings.m_ViasMinDrill )
{
m_currentMarker = fillMarker( refvia, NULL,
DRCE_TOO_SMALL_VIA_DRILL, m_currentMarker );
addMarkerToPcb( fillMarker( refvia, NULL,
DRCE_TOO_SMALL_VIA_DRILL, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
}
@ -197,8 +212,11 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
// and a default via hole can be bigger than some vias sizes
if( refvia->GetDrillValue() > refvia->GetWidth() )
{
m_currentMarker = fillMarker( refvia, NULL,
DRCE_VIA_HOLE_BIGGER, m_currentMarker );
addMarkerToPcb( fillMarker( refvia, NULL,
DRCE_VIA_HOLE_BIGGER, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
@ -206,8 +224,11 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( ( refvia->GetViaType() == VIA_MICROVIA ) &&
( m_pcb->GetDesignSettings().m_MicroViasAllowed == false ) )
{
m_currentMarker = fillMarker( refvia, NULL,
DRCE_MICRO_VIA_NOT_ALLOWED, m_currentMarker );
addMarkerToPcb( fillMarker( refvia, NULL,
DRCE_MICRO_VIA_NOT_ALLOWED, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
@ -215,8 +236,11 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( ( refvia->GetViaType() == VIA_BLIND_BURIED ) &&
( m_pcb->GetDesignSettings().m_BlindBuriedViaAllowed == false ) )
{
m_currentMarker = fillMarker( refvia, NULL,
DRCE_BURIED_VIA_NOT_ALLOWED, m_currentMarker );
addMarkerToPcb( fillMarker( refvia, NULL,
DRCE_BURIED_VIA_NOT_ALLOWED, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
@ -242,8 +266,11 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( err )
{
m_currentMarker = fillMarker( refvia, NULL,
DRCE_MICRO_VIA_INCORRECT_LAYER_PAIR, m_currentMarker );
addMarkerToPcb( fillMarker( refvia, NULL,
DRCE_MICRO_VIA_INCORRECT_LAYER_PAIR, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
}
@ -253,8 +280,11 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
{
if( aRefSeg->GetWidth() < dsnSettings.m_TrackMinWidth )
{
m_currentMarker = fillMarker( aRefSeg, NULL,
DRCE_TOO_SMALL_TRACK_WIDTH, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, NULL,
DRCE_TOO_SMALL_TRACK_WIDTH, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
}
@ -325,8 +355,11 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( !checkClearanceSegmToPad( &dummypad, aRefSeg->GetWidth(),
netclass->GetClearance() ) )
{
m_currentMarker = fillMarker( aRefSeg, pad,
DRCE_TRACK_NEAR_THROUGH_HOLE, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, pad,
DRCE_TRACK_NEAR_THROUGH_HOLE, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
@ -343,10 +376,14 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
shape_pos = pad->ShapePos();
m_padToTestPos = shape_pos - origin;
if( !checkClearanceSegmToPad( pad, aRefSeg->GetWidth(), aRefSeg->GetClearance( pad ) ) )
if( !checkClearanceSegmToPad( pad, aRefSeg->GetWidth(),
aRefSeg->GetClearance( pad ) ) )
{
m_currentMarker = fillMarker( aRefSeg, pad,
DRCE_TRACK_NEAR_PAD, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, pad,
DRCE_TRACK_NEAR_PAD, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
}
@ -361,6 +398,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
// Test the reference segment with other track segments
wxPoint segStartPoint;
wxPoint segEndPoint;
for( track = aStart; track; track = track->Next() )
{
// No problem if segments have the same net code:
@ -394,8 +432,11 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
// Test distance between two vias, i.e. two circles, trivial case
if( EuclideanNorm( segStartPoint ) < w_dist )
{
m_currentMarker = fillMarker( aRefSeg, track,
DRCE_VIA_NEAR_VIA, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, track,
DRCE_VIA_NEAR_VIA, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
}
@ -410,8 +451,11 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( !checkMarginToCircle( segStartPoint, w_dist, delta.x ) )
{
m_currentMarker = fillMarker( track, aRefSeg,
DRCE_VIA_NEAR_TRACK, m_currentMarker );
addMarkerToPcb( fillMarker( track, aRefSeg,
DRCE_VIA_NEAR_TRACK, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
}
@ -432,8 +476,11 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
continue;
m_currentMarker = fillMarker( aRefSeg, track,
DRCE_TRACK_NEAR_VIA, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, track,
DRCE_TRACK_NEAR_VIA, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
@ -459,15 +506,21 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
// Fine test : we consider the rounded shape of each end of the track segment:
if( segStartPoint.x >= 0 && segStartPoint.x <= m_segmLength )
{
m_currentMarker = fillMarker( aRefSeg, track,
DRCE_TRACK_ENDS1, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, track,
DRCE_TRACK_ENDS1, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
{
m_currentMarker = fillMarker( aRefSeg, track,
DRCE_TRACK_ENDS2, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, track,
DRCE_TRACK_ENDS2, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
}
@ -480,15 +533,21 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
// Fine test : we consider the rounded shape of the ends
if( segEndPoint.x >= 0 && segEndPoint.x <= m_segmLength )
{
m_currentMarker = fillMarker( aRefSeg, track,
DRCE_TRACK_ENDS3, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, track,
DRCE_TRACK_ENDS3, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) )
{
m_currentMarker = fillMarker( aRefSeg, track,
DRCE_TRACK_ENDS4, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, track,
DRCE_TRACK_ENDS4, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
}
@ -500,8 +559,11 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
// handled)
// X.............X
// O--REF--+
m_currentMarker = fillMarker( aRefSeg, track,
DRCE_TRACK_SEGMENTS_TOO_CLOSE, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, track,
DRCE_TRACK_SEGMENTS_TOO_CLOSE, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
}
@ -514,24 +576,33 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( segStartPoint.y > segEndPoint.y )
std::swap( segStartPoint.y, segEndPoint.y );
if( (segStartPoint.y < 0) && (segEndPoint.y > 0) )
if( ( segStartPoint.y < 0 ) && ( segEndPoint.y > 0 ) )
{
m_currentMarker = fillMarker( aRefSeg, track,
DRCE_TRACKS_CROSSING, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, track,
DRCE_TRACKS_CROSSING, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
// At this point the drc error is due to an end near a reference segm end
if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
{
m_currentMarker = fillMarker( aRefSeg, track,
DRCE_ENDS_PROBLEM1, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, track,
DRCE_ENDS_PROBLEM1, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) )
{
m_currentMarker = fillMarker( aRefSeg, track,
DRCE_ENDS_PROBLEM2, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, track,
DRCE_ENDS_PROBLEM2, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
}
@ -558,8 +629,11 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( !checkLine( segStartPoint, segEndPoint ) )
{
m_currentMarker = fillMarker( aRefSeg, track,
DRCE_ENDS_PROBLEM3, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, track,
DRCE_ENDS_PROBLEM3, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
else // The drc error is due to the starting or the ending point of the reference segment
@ -586,15 +660,21 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( !checkMarginToCircle( relStartPos, w_dist, delta.x ) )
{
m_currentMarker = fillMarker( aRefSeg, track,
DRCE_ENDS_PROBLEM4, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, track,
DRCE_ENDS_PROBLEM4, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
if( !checkMarginToCircle( relEndPos, w_dist, delta.x ) )
{
m_currentMarker = fillMarker( aRefSeg, track,
DRCE_ENDS_PROBLEM5, m_currentMarker );
addMarkerToPcb( fillMarker( aRefSeg, track,
DRCE_ENDS_PROBLEM5, nullptr ) );
success = false;
if( !m_reportAllTrackErrors )
return false;
}
}
@ -602,7 +682,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
}
}
return true;
return success;
}