Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

745 lines
17 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #define PROTECTED_THINGS_DISABLE
  7. #undef PROTECT_FILEIO_FUNCTIONS
  8. #undef fopen
  9. #include "winlite.h"
  10. #include "basetypes.h"
  11. #include "utlvector.h"
  12. #include "utlsymbol.h"
  13. #include "utldict.h"
  14. #include "utlbuffer.h"
  15. #include "steamcommon.h"
  16. #include "bugreporter/bugreporter.h"
  17. #include "filesystem_tools.h"
  18. #include "KeyValues.h"
  19. #include "netadr.h"
  20. #include "steam/steamclientpublic.h"
  21. bool UploadBugReport(
  22. const netadr_t& cserIP,
  23. const CSteamID& userid,
  24. int build,
  25. char const *title,
  26. char const *body,
  27. char const *exename,
  28. char const *gamedir,
  29. char const *mapname,
  30. char const *reporttype,
  31. char const *email,
  32. char const *accountname,
  33. int ram,
  34. int cpu,
  35. char const *processor,
  36. unsigned int high,
  37. unsigned int low,
  38. unsigned int vendor,
  39. unsigned int device,
  40. char const *osversion,
  41. char const *attachedfile,
  42. unsigned int attachedfilesize
  43. );
  44. IBaseFileSystem *g_pFileSystem = NULL;
  45. class CBug
  46. {
  47. public:
  48. CBug()
  49. {
  50. Clear();
  51. }
  52. void Clear()
  53. {
  54. Q_memset( title, 0, sizeof( title ) );
  55. Q_memset( desc, 0, sizeof( desc ) );
  56. Q_memset( submitter, 0, sizeof( submitter ) );
  57. Q_memset( owner, 0, sizeof( owner ) );
  58. Q_memset( severity, 0, sizeof( severity ) );
  59. Q_memset( priority, 0, sizeof( priority ) );
  60. Q_memset( area, 0, sizeof( area ) );
  61. Q_memset( mapnumber, 0, sizeof( mapnumber) );
  62. Q_memset( reporttype, 0, sizeof( reporttype ) );
  63. Q_memset( level, 0, sizeof( level ) );
  64. Q_memset( build, 0, sizeof( build ) );
  65. Q_memset( position, 0, sizeof( position ) );
  66. Q_memset( orientation, 0, sizeof( orientation ) );
  67. Q_memset( screenshot_unc, 0, sizeof( screenshot_unc ) );
  68. Q_memset( savegame_unc, 0, sizeof( savegame_unc ) );
  69. Q_memset( bsp_unc, 0, sizeof( bsp_unc ) );
  70. Q_memset( vmf_unc, 0, sizeof( vmf_unc ) );
  71. Q_memset( driverinfo, 0, sizeof( driverinfo ) );
  72. Q_memset( misc, 0, sizeof( misc ) );
  73. Q_memset( zip, 0, sizeof( zip ) );
  74. Q_memset( exename, 0, sizeof( exename ) );
  75. Q_memset( gamedir, 0, sizeof( gamedir ) );
  76. ram = 0;
  77. cpu = 0;
  78. Q_memset( processor, 0, sizeof( processor ) );
  79. dxversionhigh = 0;
  80. dxversionlow = 0;
  81. dxvendor = 0;
  82. dxdevice = 0;
  83. Q_memset( osversion, 0, sizeof( osversion ) );
  84. includedfiles.Purge();
  85. }
  86. char title[ 256 ];
  87. char desc[ 8192 ];
  88. char owner[ 256 ];
  89. char submitter[ 256 ];
  90. char severity[ 256 ];
  91. char priority[ 256 ];
  92. char area[ 256 ];
  93. char mapnumber[ 256 ];
  94. char reporttype[ 256 ];
  95. char level[ 256 ];
  96. char build[ 256 ];
  97. char position[ 256 ];
  98. char orientation[ 256 ];
  99. char screenshot_unc[ 256 ];
  100. char savegame_unc[ 256 ];
  101. char bsp_unc[ 256 ];
  102. char vmf_unc[ 256 ];
  103. char driverinfo[ 2048 ];
  104. char misc[ 1024 ];
  105. char exename[ 256 ];
  106. char gamedir[ 256 ];
  107. unsigned int ram;
  108. unsigned int cpu;
  109. char processor[ 256 ];
  110. unsigned int dxversionhigh;
  111. unsigned int dxversionlow;
  112. unsigned int dxvendor;
  113. unsigned int dxdevice;
  114. char osversion[ 256 ];
  115. char zip[ 256 ];
  116. struct incfile
  117. {
  118. char name[ 256 ];
  119. };
  120. CUtlVector< incfile > includedfiles;
  121. };
  122. class CBugReporter : public IBugReporter
  123. {
  124. public:
  125. CBugReporter();
  126. virtual ~CBugReporter();
  127. // Initialize and login with default username/password for this computer (from resource/bugreporter.res)
  128. virtual bool Init( CreateInterfaceFn engineFactory );
  129. virtual void Shutdown();
  130. virtual bool IsPublicUI() { return true; }
  131. virtual char const *GetUserName();
  132. virtual char const *GetUserName_Display();
  133. virtual int GetNameCount();
  134. virtual char const *GetName( int index );
  135. virtual int GetDisplayNameCount();
  136. virtual char const *GetDisplayName( int index );
  137. virtual char const *GetDisplayNameForUserName( char const *username );
  138. virtual char const *GetUserNameForDisplayName( char const *display );
  139. virtual int GetSeverityCount();
  140. virtual char const *GetSeverity( int index );
  141. virtual int GetPriorityCount();
  142. virtual char const *GetPriority( int index );
  143. virtual int GetAreaCount();
  144. virtual char const *GetArea( int index );
  145. virtual int GetAreaMapCount();
  146. virtual char const *GetAreaMap( int index );
  147. virtual int GetMapNumberCount();
  148. virtual char const *GetMapNumber( int index );
  149. virtual int GetReportTypeCount();
  150. virtual char const *GetReportType( int index );
  151. virtual char const *GetRepositoryURL( void ) { return NULL; }
  152. virtual char const *GetSubmissionURL( void ) { return NULL; }
  153. virtual int GetLevelCount(int area) { return 0; }
  154. virtual char const *GetLevel(int area, int index ) { return ""; }
  155. // Submission API
  156. virtual void StartNewBugReport();
  157. virtual void CancelNewBugReport();
  158. virtual bool CommitBugReport( int& bugSubmissionId );
  159. virtual void SetTitle( char const *title );
  160. virtual void SetDescription( char const *description );
  161. // NULL for current user
  162. virtual void SetSubmitter( char const *username = 0 );
  163. virtual void SetOwner( char const *username );
  164. virtual void SetSeverity( char const *severity );
  165. virtual void SetPriority( char const *priority );
  166. virtual void SetArea( char const *area );
  167. virtual void SetMapNumber ( char const *mapnumber );
  168. virtual void SetReportType( char const *reporttype );
  169. virtual void SetLevel( char const *levelnamne );
  170. virtual void SetPosition( char const *position );
  171. virtual void SetOrientation( char const *pitch_yaw_roll );
  172. virtual void SetBuildNumber( char const *build_num );
  173. virtual void SetScreenShot( char const *screenshot_unc_address );
  174. virtual void SetSaveGame( char const *savegame_unc_address );
  175. virtual void SetBSPName( char const *bsp_unc_address );
  176. virtual void SetVMFName( char const *vmf_unc_address );
  177. virtual void AddIncludedFile( char const *filename );
  178. virtual void ResetIncludedFiles();
  179. virtual void SetDriverInfo( char const *info );
  180. virtual void SetZipAttachmentName( char const *zipfilename );
  181. virtual void SetMiscInfo( char const *info );
  182. virtual void SetCSERAddress( const struct netadr_s& adr );
  183. virtual void SetExeName( char const *exename );
  184. virtual void SetGameDirectory( char const *gamedir );
  185. virtual void SetRAM( int ram );
  186. virtual void SetCPU( int cpu );
  187. virtual void SetProcessor( char const *processor );
  188. virtual void SetDXVersion( unsigned int high, unsigned int low, unsigned int vendor, unsigned int device );
  189. virtual void SetOSVersion( char const *osversion );
  190. virtual void SetSteamUserID( void *steamid, int idsize );
  191. private:
  192. void SubstituteBugId( int bugid, char *out, int outlen, CUtlBuffer& src );
  193. CUtlSymbolTable m_BugStrings;
  194. CUtlVector< CUtlSymbol > m_Severity;
  195. CUtlVector< CUtlSymbol > m_Area;
  196. CUtlVector< CUtlSymbol > m_MapNumber;
  197. CUtlVector< CUtlSymbol > m_ReportType;
  198. CUtlSymbol m_UserName;
  199. CBug *m_pBug;
  200. netadr_t m_cserIP;
  201. CSteamID m_SteamID;
  202. };
  203. CBugReporter::CBugReporter()
  204. {
  205. Q_memset( &m_cserIP, 0, sizeof( m_cserIP ) );
  206. m_pBug = NULL;
  207. m_Severity.AddToTail( m_BugStrings.AddString( "Zero" ) );
  208. m_Severity.AddToTail( m_BugStrings.AddString( "Low" ) );
  209. m_Severity.AddToTail( m_BugStrings.AddString( "Medium" ) );
  210. m_Severity.AddToTail( m_BugStrings.AddString( "High" ) );
  211. m_Severity.AddToTail( m_BugStrings.AddString( "Showstopper" ) );
  212. m_ReportType.AddToTail( m_BugStrings.AddString( "<<Choose Item>>" ) );
  213. m_ReportType.AddToTail( m_BugStrings.AddString( "Video / Display Problems" ) );
  214. m_ReportType.AddToTail( m_BugStrings.AddString( "Network / Connectivity Problems" ) );
  215. m_ReportType.AddToTail( m_BugStrings.AddString( "Download / Installation Problems" ) );
  216. m_ReportType.AddToTail( m_BugStrings.AddString( "In-game Crash" ) );
  217. m_ReportType.AddToTail( m_BugStrings.AddString( "Game play / Strategy Problems" ) );
  218. m_ReportType.AddToTail( m_BugStrings.AddString( "Steam Problems" ) );
  219. m_ReportType.AddToTail( m_BugStrings.AddString( "Unlisted Bug" ) );
  220. m_ReportType.AddToTail( m_BugStrings.AddString( "Feature Request / Suggestion" ) );
  221. }
  222. CBugReporter::~CBugReporter()
  223. {
  224. m_BugStrings.RemoveAll();
  225. m_Severity.Purge();
  226. m_Area.Purge();
  227. m_MapNumber.Purge();
  228. m_ReportType.Purge();
  229. delete m_pBug;
  230. }
  231. //-----------------------------------------------------------------------------
  232. // Purpose: Initialize and login with default username/password for this computer (from resource/bugreporter.res)
  233. // Output : Returns true on success, false on failure.
  234. //-----------------------------------------------------------------------------
  235. bool CBugReporter::Init( CreateInterfaceFn engineFactory )
  236. {
  237. g_pFileSystem = (IFileSystem *)engineFactory( FILESYSTEM_INTERFACE_VERSION, NULL );
  238. if ( !g_pFileSystem )
  239. {
  240. AssertMsg( 0, "Failed to create/get IFileSystem" );
  241. return false;
  242. }
  243. return true;
  244. }
  245. void CBugReporter::Shutdown()
  246. {
  247. }
  248. char const *CBugReporter::GetUserName()
  249. {
  250. return m_UserName.String();
  251. }
  252. char const *CBugReporter::GetUserName_Display()
  253. {
  254. return GetUserName();
  255. }
  256. int CBugReporter::GetNameCount()
  257. {
  258. return 1;
  259. }
  260. char const *CBugReporter::GetName( int index )
  261. {
  262. if ( index < 0 || index >= 1 )
  263. return "<<Invalid>>";
  264. return GetUserName();
  265. }
  266. int CBugReporter::GetDisplayNameCount()
  267. {
  268. return 1;
  269. }
  270. char const *CBugReporter::GetDisplayName( int index )
  271. {
  272. if ( index < 0 || index >= 1 )
  273. return "<<Invalid>>";
  274. return GetUserName();
  275. }
  276. char const *CBugReporter::GetDisplayNameForUserName( char const *username )
  277. {
  278. return username;
  279. }
  280. char const *CBugReporter::GetUserNameForDisplayName( char const *display )
  281. {
  282. return display;
  283. }
  284. int CBugReporter::GetSeverityCount()
  285. {
  286. return m_Severity.Count() ;
  287. }
  288. char const *CBugReporter::GetSeverity( int index )
  289. {
  290. if ( index < 0 || index >= m_Severity.Count() )
  291. return "<<Invalid>>";
  292. return m_BugStrings.String( m_Severity[ index ] );
  293. }
  294. int CBugReporter::GetPriorityCount()
  295. {
  296. return 0;
  297. }
  298. char const *CBugReporter::GetPriority( int index )
  299. {
  300. return "<<Invalid>>";
  301. }
  302. int CBugReporter::GetAreaCount()
  303. {
  304. return 0;
  305. }
  306. char const *CBugReporter::GetArea( int index )
  307. {
  308. return "<<Invalid>>";
  309. }
  310. int CBugReporter::GetAreaMapCount()
  311. {
  312. return 0;
  313. }
  314. char const *CBugReporter::GetAreaMap( int index )
  315. {
  316. return "<<Invalid>>";
  317. }
  318. int CBugReporter::GetMapNumberCount()
  319. {
  320. return 0;
  321. }
  322. char const *CBugReporter::GetMapNumber( int index )
  323. {
  324. return "<<Invalid>>";
  325. }
  326. int CBugReporter::GetReportTypeCount()
  327. {
  328. return m_ReportType.Count();
  329. }
  330. char const *CBugReporter::GetReportType( int index )
  331. {
  332. if ( index < 0 || index >= m_ReportType.Count() )
  333. return "<<Invalid>>";
  334. return m_BugStrings.String( m_ReportType[ index ] );
  335. }
  336. void CBugReporter::StartNewBugReport()
  337. {
  338. if ( !m_pBug )
  339. {
  340. m_pBug = new CBug();
  341. }
  342. else
  343. {
  344. m_pBug->Clear();
  345. }
  346. }
  347. void CBugReporter::CancelNewBugReport()
  348. {
  349. if ( !m_pBug )
  350. return;
  351. m_pBug->Clear();
  352. }
  353. void CBugReporter::SubstituteBugId( int bugid, char *out, int outlen, CUtlBuffer& src )
  354. {
  355. out[ 0 ] = 0;
  356. char *dest = out;
  357. src.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
  358. char const *replace = "\\BugId\\";
  359. int replace_len = Q_strlen( replace );
  360. for ( int pos = 0; pos <= src.TellPut() && ( ( dest - out ) < outlen ); )
  361. {
  362. char const *str = ( char const * )src.PeekGet( pos );
  363. if ( !Q_strnicmp( str, replace, replace_len ) )
  364. {
  365. *dest++ = '\\';
  366. char num[ 32 ];
  367. Q_snprintf( num, sizeof( num ), "%i", bugid );
  368. char *pnum = num;
  369. while ( *pnum )
  370. {
  371. *dest++ = *pnum++;
  372. }
  373. *dest++ = '\\';
  374. pos += replace_len;
  375. continue;
  376. }
  377. *dest++ = *str;
  378. ++pos;
  379. }
  380. *dest = 0;
  381. }
  382. bool CBugReporter::CommitBugReport( int& bugSubmissionId )
  383. {
  384. bugSubmissionId = -1;
  385. if ( !m_pBug )
  386. return false;
  387. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  388. buf.Printf( "%s\n\n", m_pBug->desc );
  389. buf.Printf( "level: %s\nbuild: %s\nposition: setpos %s; setang %s\n",
  390. m_pBug->level,
  391. m_pBug->build,
  392. m_pBug->position,
  393. m_pBug->orientation );
  394. if ( m_pBug->screenshot_unc[ 0 ] )
  395. {
  396. buf.Printf( "screenshot: %s\n", m_pBug->screenshot_unc );
  397. }
  398. if ( m_pBug->savegame_unc[ 0 ] )
  399. {
  400. buf.Printf( "savegame: %s\n", m_pBug->savegame_unc );
  401. }
  402. /*
  403. if ( m_pBug->bsp_unc[ 0 ] )
  404. {
  405. buf.Printf( "bsp: %s\n", m_pBug->bsp_unc );
  406. }
  407. if ( m_pBug->vmf_unc[ 0 ] )
  408. {
  409. buf.Printf( "vmf: %s\n", m_pBug->vmf_unc );
  410. }
  411. if ( m_pBug->includedfiles.Count() > 0 )
  412. {
  413. int c = m_pBug->includedfiles.Count();
  414. for ( int i = 0 ; i < c; ++i )
  415. {
  416. buf.Printf( "include: %s\n", m_pBug->includedfiles[ i ].name );
  417. }
  418. }
  419. */
  420. if ( m_pBug->driverinfo[ 0 ] )
  421. {
  422. buf.Printf( "%s\n", m_pBug->driverinfo );
  423. }
  424. if ( m_pBug->misc[ 0 ] )
  425. {
  426. buf.Printf( "%s\n", m_pBug->misc );
  427. }
  428. buf.PutChar( 0 );
  429. // Store desc
  430. int bugId = 0;
  431. bugSubmissionId = (int)bugId;
  432. int attachedfilesize = ( m_pBug->zip[ 0 ] == 0 ) ? 0 : g_pFileSystem->Size( m_pBug->zip );
  433. if ( !UploadBugReport(
  434. m_cserIP,
  435. m_SteamID,
  436. atoi( m_pBug->build ),
  437. m_pBug->title,
  438. (char const *)buf.Base(),
  439. m_pBug->exename,
  440. m_pBug->gamedir,
  441. m_pBug->level,
  442. m_pBug->reporttype,
  443. m_pBug->owner,
  444. m_pBug->submitter,
  445. m_pBug->ram,
  446. m_pBug->cpu,
  447. m_pBug->processor,
  448. m_pBug->dxversionhigh,
  449. m_pBug->dxversionlow,
  450. m_pBug->dxvendor,
  451. m_pBug->dxdevice,
  452. m_pBug->osversion,
  453. m_pBug->zip,
  454. attachedfilesize
  455. ) )
  456. {
  457. Msg( "Unable to upload bug...\n" );
  458. }
  459. m_pBug->Clear();
  460. return true;
  461. }
  462. void CBugReporter::SetTitle( char const *title )
  463. {
  464. Assert( m_pBug );
  465. Q_strncpy( m_pBug->title, title, sizeof( m_pBug->title ) );
  466. }
  467. void CBugReporter::SetDescription( char const *description )
  468. {
  469. Assert( m_pBug );
  470. Q_strncpy( m_pBug->desc, description, sizeof( m_pBug->desc ) );
  471. }
  472. void CBugReporter::SetSubmitter( char const *username /*= 0*/ )
  473. {
  474. m_UserName = username;
  475. /*
  476. if ( !username )
  477. {
  478. username = GetUserName();
  479. }
  480. */
  481. Assert( m_pBug );
  482. Q_strncpy( m_pBug->submitter, username ? username : "", sizeof( m_pBug->submitter ) );
  483. }
  484. void CBugReporter::SetOwner( char const *username )
  485. {
  486. Q_strncpy( m_pBug->owner, username, sizeof( m_pBug->owner ) );
  487. }
  488. void CBugReporter::SetSeverity( char const *severity )
  489. {
  490. }
  491. void CBugReporter::SetPriority( char const *priority )
  492. {
  493. }
  494. void CBugReporter::SetArea( char const *area )
  495. {
  496. }
  497. void CBugReporter::SetMapNumber( char const *mapnumber )
  498. {
  499. }
  500. void CBugReporter::SetReportType( char const *reporttype )
  501. {
  502. Q_strncpy( m_pBug->reporttype, reporttype, sizeof( m_pBug->reporttype ) );
  503. }
  504. void CBugReporter::SetLevel( char const *levelnamne )
  505. {
  506. Assert( m_pBug );
  507. Q_strncpy( m_pBug->level, levelnamne, sizeof( m_pBug->level ) );
  508. }
  509. void CBugReporter::SetDriverInfo( char const *info )
  510. {
  511. Assert( m_pBug );
  512. Q_strncpy( m_pBug->driverinfo, info, sizeof( m_pBug->driverinfo ) );
  513. }
  514. void CBugReporter::SetZipAttachmentName( char const *zipfilename )
  515. {
  516. Assert( m_pBug );
  517. Q_strncpy( m_pBug->zip, zipfilename, sizeof( m_pBug->zip ) );
  518. }
  519. void CBugReporter::SetMiscInfo( char const *info )
  520. {
  521. Assert( m_pBug );
  522. Q_strncpy( m_pBug->misc, info, sizeof( m_pBug->misc ) );
  523. }
  524. void CBugReporter::SetPosition( char const *position )
  525. {
  526. Assert( m_pBug );
  527. Q_strncpy( m_pBug->position, position, sizeof( m_pBug->position ) );
  528. }
  529. void CBugReporter::SetOrientation( char const *pitch_yaw_roll )
  530. {
  531. Assert( m_pBug );
  532. Q_strncpy( m_pBug->orientation, pitch_yaw_roll, sizeof( m_pBug->orientation ) );
  533. }
  534. void CBugReporter::SetBuildNumber( char const *build_num )
  535. {
  536. Assert( m_pBug );
  537. Q_strncpy( m_pBug->build, build_num, sizeof( m_pBug->build ) );
  538. }
  539. void CBugReporter::SetScreenShot( char const *screenshot_unc_address )
  540. {
  541. Assert( m_pBug );
  542. Q_strncpy( m_pBug->screenshot_unc, screenshot_unc_address, sizeof( m_pBug->screenshot_unc ) );
  543. }
  544. void CBugReporter::SetSaveGame( char const *savegame_unc_address )
  545. {
  546. Assert( m_pBug );
  547. Q_strncpy( m_pBug->savegame_unc, savegame_unc_address, sizeof( m_pBug->savegame_unc ) );
  548. }
  549. void CBugReporter::SetBSPName( char const *bsp_unc_address )
  550. {
  551. }
  552. void CBugReporter::SetVMFName( char const *vmf_unc_address )
  553. {
  554. }
  555. void CBugReporter::AddIncludedFile( char const *filename )
  556. {
  557. }
  558. void CBugReporter::ResetIncludedFiles()
  559. {
  560. }
  561. void CBugReporter::SetExeName( char const *exename )
  562. {
  563. Assert( m_pBug );
  564. Q_strncpy( m_pBug->exename, exename, sizeof( m_pBug->exename ) );
  565. }
  566. void CBugReporter::SetGameDirectory( char const *pchGamedir )
  567. {
  568. Assert( m_pBug );
  569. Q_FileBase( pchGamedir, m_pBug->gamedir, sizeof( m_pBug->gamedir ) );
  570. }
  571. void CBugReporter::SetRAM( int ram )
  572. {
  573. Assert( m_pBug );
  574. m_pBug->ram = ram;
  575. }
  576. void CBugReporter::SetCPU( int cpu )
  577. {
  578. Assert( m_pBug );
  579. m_pBug->cpu = cpu;
  580. }
  581. void CBugReporter::SetProcessor( char const *processor )
  582. {
  583. Assert( m_pBug );
  584. Q_strncpy( m_pBug->processor, processor, sizeof( m_pBug->processor ) );
  585. }
  586. void CBugReporter::SetDXVersion( unsigned int high, unsigned int low, unsigned int vendor, unsigned int device )
  587. {
  588. Assert( m_pBug );
  589. m_pBug->dxversionhigh = high;
  590. m_pBug->dxversionlow = low;
  591. m_pBug->dxvendor = vendor;
  592. m_pBug->dxdevice = device;
  593. }
  594. void CBugReporter::SetOSVersion( char const *osversion )
  595. {
  596. Assert( m_pBug );
  597. Q_strncpy( m_pBug->osversion, osversion, sizeof( m_pBug->osversion ) );
  598. }
  599. void CBugReporter::SetCSERAddress( const struct netadr_s& adr )
  600. {
  601. m_cserIP = adr;
  602. }
  603. void CBugReporter::SetSteamUserID( void *steamid, int idsize )
  604. {
  605. Assert( idsize == sizeof( uint64 ) );
  606. m_SteamID.SetFromUint64( *((uint64*)steamid) );
  607. }
  608. EXPOSE_SINGLE_INTERFACE( CBugReporter, IBugReporter, INTERFACEVERSION_BUGREPORTER );