Author Topic: C::B 13.12 Can't work with big project which have more than 100 files.  (Read 20888 times)

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 12067
    • Travis build status
Re: C::B 13.12 Can't work with big project which have more than 100 files.
« Reply #30 on: March 01, 2014, 01:48:57 pm »
There should only be 2 cases:
1.) A short list of methods and always the docs on the right
2.) A long list of methods including args if the docs are disabled.

Every other state is invalid and we need to dig into it.
Totally agree about this :)
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5230
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: C::B 13.12 Can't work with big project which have more than 100 files.
« Reply #31 on: March 01, 2014, 03:40:02 pm »
@Morten:
Code: [Select]
Index: trunk/src/plugins/codecompletion/codecompletion.cpp
===================================================================
--- trunk/src/plugins/codecompletion/codecompletion.cpp (revision 9667)
+++ trunk/src/plugins/codecompletion/codecompletion.cpp (revision 9668)
@@ -1004,8 +1004,10 @@
 
                 if (token->m_TokenKind & tkAnyFunction)
                 {
-                    //tmp << token->GetFormattedArgs();
-                    tmp << _T("(): ") << token->m_FullType;
+                    if (m_DocHelper.GetOptions().m_Enabled)
+                        tmp << _T("(): ") << token->m_FullType;
+                    else
+                        tmp << token->GetFormattedArgs() << _T(": ") << token->m_FullType;
                 }
                 else if (token->m_TokenKind == tkVariable)
                     tmp << _T(": ") << token->m_FullType;

Is it m_DocHelper.GetOptions().m_ShowAlways instead of m_DocHelper.GetOptions().m_Enabled? or both of them?
I mean in my post: Re: C::B 13.12 Can't work with big project which have more than 100 files.
I need to check on Show token's details even it hasn't documentation. to let the documentation tip window shown in the case there is no Doxygen styled document associated with the token.

If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 12067
    • Travis build status
Re: C::B 13.12 Can't work with big project which have more than 100 files.
« Reply #32 on: March 01, 2014, 03:44:50 pm »
As far as I'm concerned this m_DocHelper.GetOptions().m_ShowAlways should be removed from the interface and should be set to always be true.
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline MortenMacFly

  • Administrator
  • Lives here!
  • *****
  • Posts: 9504
Re: C::B 13.12 Can't work with big project which have more than 100 files.
« Reply #33 on: March 01, 2014, 03:47:25 pm »
Is it m_DocHelper.GetOptions().m_ShowAlways instead of m_DocHelper.GetOptions().m_Enabled? or both of them?
Yeah - that's tricky. If you disable "Always show" than you've a "mixed mode". It means if the method is not documented you'll stick with the mini view w/o arguments and unclear duplicates. If the method is documented its OK.

There is no good solution to this case because you cannot fill the CC list in a "mixed mode" - it would become too large again.

The only feasible solution I see is to remove this option and always show what the docs have to offer by default.
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: http://www.codeblocks.org/docs/main_codeblocks_en.html
C::B FAQ: http://wiki.codeblocks.org/index.php?title=FAQ

Offline MortenMacFly

  • Administrator
  • Lives here!
  • *****
  • Posts: 9504
Re: C::B 13.12 Can't work with big project which have more than 100 files.
« Reply #34 on: March 01, 2014, 03:47:46 pm »
As far as I'm concerned this m_DocHelper.GetOptions().m_ShowAlways should be removed from the interface and should be set to always be true.
Our posts crossed - I've just posted the same. :-)
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: http://www.codeblocks.org/docs/main_codeblocks_en.html
C::B FAQ: http://wiki.codeblocks.org/index.php?title=FAQ

Offline MortenMacFly

  • Administrator
  • Lives here!
  • *****
  • Posts: 9504
Re: C::B 13.12 Can't work with big project which have more than 100 files.
« Reply #35 on: March 01, 2014, 04:04:00 pm »
The only feasible solution I see is to remove this option and always show what the docs have to offer by default.
I've implemented that (see SVN) - it makes the code even easier... which is good. :-)
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: http://www.codeblocks.org/docs/main_codeblocks_en.html
C::B FAQ: http://wiki.codeblocks.org/index.php?title=FAQ

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5230
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: C::B 13.12 Can't work with big project which have more than 100 files.
« Reply #36 on: March 01, 2014, 04:08:13 pm »
The only feasible solution I see is to remove this option and always show what the docs have to offer by default.
I've implemented that (see SVN) - it makes the code even easier... which is good. :-)
Good work, you are quicker than my reply.

Below is what I want to post.

Quote
I'm OK to remove the m_ShowAlways option.

Reasons:
For overloaded function tokens with no doxygen comment, if m_Enabled == true, and m_ShowAlways == false, we can still see duplicated "DecBy" entries but no document window shown, too bad! Also, it is too large (information duplicated) when both showing function arguments in the suggestion list and document window.

BTW: I found that the document window is very useful even we don't have much doxygen style document for a token. I can navigate on the suggestion list entries by click on the "goto declaration/implementation".
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5230
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: C::B 13.12 Can't work with big project which have more than 100 files.
« Reply #37 on: March 01, 2014, 04:17:32 pm »
@morten, rev 9669.

Code: [Select]
src/plugins/codecompletion/cctest/cctest_frame.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/plugins/codecompletion/cctest/cctest_frame.cpp b/src/plugins/codecompletion/cctest/cctest_frame.cpp
index f0c008e..d2aa4bc 100644
--- a/src/plugins/codecompletion/cctest/cctest_frame.cpp
+++ b/src/plugins/codecompletion/cctest/cctest_frame.cpp
@@ -242,6 +242,7 @@ CCTestFrame::CCTestFrame(const wxString& main_file) :
                             gcc_base + mingwver + _T("\\include")                                                   + _T("\n"));
 
     m_HeadersCtrl->SetValue(_T("<_mingw.h>,<cstddef>,<w32api.h>,<winbase.h>,<wx/defs.h>,<wx/dlimpexp.h>,<wx/toplevel.h>,<boost/config.hpp>,<boost/filesystem/config.hpp>,\"pch.h\",\"sdk.h\",\"stdafx.h\""));
+//  m_HeadersCtrl->SetValue(_T("           <cstddef>,<w32api.h>,            <wx/defs.h>,<wx/dlimpexp.h>,<wx/toplevel.h>,<boost/config.hpp>,<boost/filesystem/config.hpp>,\"pch.h\",\"sdk.h\",\"stdafx.h\""));
 
     CCLogger::Get()->Init(this, idCCLogger, idCCLogger, idCCAddToken);
     m_StatuBar->SetStatusText(_("Ready!"));
@@ -364,7 +365,7 @@ void CCTestFrame::Start()
         m_StatuBar->SetStatusText(m_CurrentFile);
 
         // This is the core parse stage for files
-        // m_NativeParser.Parse(m_CurrentFile);
+        m_NativeParser.Parse(m_CurrentFile);
 
         // Here we are going to test the expression solving algorithm
         m_NativeParser.BatchTest(m_CurrentFile);
m_NativeParser.BatchTest(m_CurrentFile) will internally parse the file, so I think m_NativeParser.Parse(m_CurrentFile) is not necessary.
What m_NativeParser.BatchTest(m_CurrentFile) do is:
1, parse the file
2, run the test (suggestion list test)


(I'm going to bed now  :)..)
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline MortenMacFly

  • Administrator
  • Lives here!
  • *****
  • Posts: 9504
Re:
« Reply #38 on: March 01, 2014, 10:11:27 pm »
Well actually not. If you comment the line cctest does simply nothing. At least not on my pc...
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: http://www.codeblocks.org/docs/main_codeblocks_en.html
C::B FAQ: http://wiki.codeblocks.org/index.php?title=FAQ

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5230
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: C::B 13.12 Can't work with big project which have more than 100 files.
« Reply #39 on: March 02, 2014, 01:10:59 am »
Well actually not. If you comment the line cctest does simply nothing. At least not on my pc...
I will check it later.

BTW, current trunk build failed:
Code: [Select]
-------------- Build: Code-completion in Code::Blocks wx2.8.x (compiler: GNU GCC Compiler)---------------

[  5.0%] g++.exe -Wall -g -pipe -mthreads -fmessage-length=0 -fexceptions -Winvalid-pch -DHAVE_W32API_H -D__WXMSW__ -DWXUSINGDLL -DcbDEBUG -DCB_PRECOMP -DWX_PRECOMP -DwxUSE_UNICODE -DBUILDING_PLUGIN -iquote.objs\include -I.objs\include -I. -IE:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\include -IE:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\lib\gcc_dll\mswu -Isdk\wxscintilla\include -Isdk\wxpropgrid\include -Iinclude\tinyxml -Iinclude -Iinclude\mozilla_chardet -Iinclude\mozilla_chardet\mfbt -Iinclude\mozilla_chardet\nsprpub\pr\include -Iinclude\mozilla_chardet\xpcom -Iinclude\mozilla_chardet\xpcom\base -Iinclude\mozilla_chardet\xpcom\glue -c plugins\codecompletion\ccoptionsdlg.cpp -o .objs\plugins\codecompletion\ccoptionsdlg.o
plugins\codecompletion\ccoptionsdlg.cpp: In constructor 'CCOptionsDlg::CCOptionsDlg(wxWindow*, NativeParser*, CodeCompletion*, DocumentationHelper*)':
plugins\codecompletion\ccoptionsdlg.cpp:180:84: error: 'class DocumentationHelper' has no member named 'GetOptions'
plugins\codecompletion\ccoptionsdlg.cpp:181:84: error: 'class DocumentationHelper' has no member named 'GetOptions'
plugins\codecompletion\ccoptionsdlg.cpp: In member function 'virtual void CCOptionsDlg::OnApply()':
plugins\codecompletion\ccoptionsdlg.cpp:287:22: error: 'class DocumentationHelper' has no member named 'GetOptions'
plugins\codecompletion\ccoptionsdlg.cpp:288:22: error: 'class DocumentationHelper' has no member named 'GetOptions'
Process terminated with status 1 (0 minute(s), 55 second(s))
4 error(s), 0 warning(s) (0 minute(s), 55 second(s))
Do you forget to commit the change of GetOptions?
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5230
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: C::B 13.12 Can't work with big project which have more than 100 files.
« Reply #40 on: March 02, 2014, 01:42:41 am »

BTW, current trunk build failed:
Code: [Select]
-------------- Build: Code-completion in Code::Blocks wx2.8.x (compiler: GNU GCC Compiler)---------------

[  5.0%] g++.exe -Wall -g -pipe -mthreads -fmessage-length=0 -fexceptions -Winvalid-pch -DHAVE_W32API_H -D__WXMSW__ -DWXUSINGDLL -DcbDEBUG -DCB_PRECOMP -DWX_PRECOMP -DwxUSE_UNICODE -DBUILDING_PLUGIN -iquote.objs\include -I.objs\include -I. -IE:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\include -IE:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\lib\gcc_dll\mswu -Isdk\wxscintilla\include -Isdk\wxpropgrid\include -Iinclude\tinyxml -Iinclude -Iinclude\mozilla_chardet -Iinclude\mozilla_chardet\mfbt -Iinclude\mozilla_chardet\nsprpub\pr\include -Iinclude\mozilla_chardet\xpcom -Iinclude\mozilla_chardet\xpcom\base -Iinclude\mozilla_chardet\xpcom\glue -c plugins\codecompletion\ccoptionsdlg.cpp -o .objs\plugins\codecompletion\ccoptionsdlg.o
plugins\codecompletion\ccoptionsdlg.cpp: In constructor 'CCOptionsDlg::CCOptionsDlg(wxWindow*, NativeParser*, CodeCompletion*, DocumentationHelper*)':
plugins\codecompletion\ccoptionsdlg.cpp:180:84: error: 'class DocumentationHelper' has no member named 'GetOptions'
plugins\codecompletion\ccoptionsdlg.cpp:181:84: error: 'class DocumentationHelper' has no member named 'GetOptions'
plugins\codecompletion\ccoptionsdlg.cpp: In member function 'virtual void CCOptionsDlg::OnApply()':
plugins\codecompletion\ccoptionsdlg.cpp:287:22: error: 'class DocumentationHelper' has no member named 'GetOptions'
plugins\codecompletion\ccoptionsdlg.cpp:288:22: error: 'class DocumentationHelper' has no member named 'GetOptions'
Process terminated with status 1 (0 minute(s), 55 second(s))
4 error(s), 0 warning(s) (0 minute(s), 55 second(s))
Do you forget to commit the change of GetOptions?

Fixed in trunk now.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5230
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: no need to run m_NativeParser.Parse(m_CurrentFile) in cctest
« Reply #41 on: March 02, 2014, 03:33:37 pm »
Well actually not. If you comment the line cctest does simply nothing. At least not on my pc...
That was strange, I just comment the line
Code: [Select]
m_NativeParser.Parse(m_CurrentFile);
But if you look at the code:
Code: [Select]
bool NativeParserTest::TestParseAndCodeCompletion(wxString filename)
{
    Clear();//clear the tree
    bool parseResult = false;
    parseResult = Parse(filename);
    if(!parseResult)
        return false;
    int passCount = 0;
    int failCount = 0;

    wxString testResult;
    wxString message = wxString::Format(_T("********************************************************\n  Testing in file: %s\n********************************************************"),filename.wx_str());
    wxLogMessage(message);
    testResult<<message<<wxT("\n");


    // read the test cases of CodeCompletion test
    wxTextFile source;
    source.Open(filename);
    wxString str;

    for ( str = source.GetLastLine();
          source.GetCurrentLine() > 0;
          str = source.GetPrevLine() )
    {

        // a test case should be put in a line, and start with the double slash
        if (str.StartsWith(_T("//")))
        {
            // do tests here, example of line is below
            // tc.St    //StaticVoid
            // remove the beginning "//"
            str.Remove(0,2);

            // find the second "//", the string after the second double slash are the
            // the result should be listed
            wxString expression;
            wxString match;
            int pos = str.Find(_T("//"));
            if (pos == wxNOT_FOUND)
                break;
            expression = str.Mid(0,pos);
            match = str.Mid(pos+2);// the remaining string

            expression.Trim();
            expression.Trim(true);
            match.Trim();
            match.Trim(true);

            wxArrayString suggestList;
            // the match can have many items, like: AAA,BBBB
            wxStringTokenizer tkz(match, wxT(","));
            while ( tkz.HasMoreTokens() )
            {
                wxString token = tkz.GetNextToken();
                suggestList.Add(token);
            }

            TokenIdxSet searchScope;
            searchScope.insert(-1);
            TokenIdxSet result;
            TestExpression(expression,searchScope,result);

            // loop the suggestList to see it is in the result Tokens
            for (size_t i=0;i<suggestList.GetCount();i++)
            {
                wxString element = suggestList[i];
                bool pass = false; // pass the test?
                for (TokenIdxSet::const_iterator it = result.begin();
                     it != result.end();
                     ++it)
                {
                    const Token* token = m_Parser.GetTokenTree()->at(*it);
                    if (!token || token->m_Name.IsEmpty())
                        continue;
                    if (element.IsSameAs(token->m_Name))
                    {
                        message = wxString::Format(_T("-PASS: %s  %s"),expression.wx_str(),element.wx_str());
                        testResult<<message<<wxT("\n");
                        wxLogMessage(message);
                        pass = true;
                        passCount++;
                    }

                }
                if (pass == false)
                {
                    message = wxString::Format(_T("*FAIL: %s  %s"),expression.wx_str(),element.wx_str());
                    testResult<<message<<wxT("\n");
                    wxLogMessage(message);
                    failCount++;
                }
            }
            // wxLogMessage(_T("Result have %lu matches"), static_cast<unsigned long>(result.size()));
        }
        else
            break; // if the line is not started with //, then we just stop testing
    }

    // report the test result here again in the last stage, further more, we can show this in another text control

    wxLogMessage(wxT("--------------------------------------------------------\nTotal %d tests, %d PASS, %d FAIL\n--------------------------------------------------------"), passCount+failCount, passCount, failCount);

    return true;
}

You see, the steps of NativeParserTest::TestParseAndCodeCompletion is:
1, clear the TokenTree
2, parse the file
3, run tests
4, report fail and pass results.

BTW: Here is the log message I see:
Code: [Select]
000001. --------------M-a-i-n--L-o-g--------------


000002. -----------I-n-t-e-r-i-m--L-o-g-----------
********************************************************
  Testing in file: C:\DOCUME~1\zyh23\LOCALS~2\Temp\cc125.h
********************************************************
*FAIL:  vt[1].  GetInt
-PASS:  g_S.  i
-PASS:  g_  g_S
-PASS:  tc.Vo  Void
-PASS:  tc.St  StaticVoid
-PASS:  tc.GetC  GetClass
-PASS:  tc.GetI  GetInt
-PASS:  str.  size
-PASS:  str.  length
--------------------------------------------------------
Total 9 tests, 8 PASS, 1 FAIL
--------------------------------------------------------


Note that I remove CC_PARSER_TEST macro definition in rev9644 (see the bold text below), since it run our test much faster, in the future, we can run many tests in a single run(we can have many cc_xxxxx files which contains many kinds of tests, then our cctest project test them one by one)

Quote
SHA-1: 40c5a4c8323e26aad488c536d426d1ab34cc66a5

* * cctest: add a framework of codecompletion test, the details are listed in C::B forum topic (batch codecompletion test framework - http://forums.codeblocks.org/index.php/topic,17538.msg120196.html#msg120196)
1, remove the file cctest.h and cctest.cpp, because those standalone classes/functions were moved to NativeParserTest class (derived from NativeParserBase), so a lot of functions can be reused from NativeParserBase.
2, remove CC_PARSER_TEST definition to reduce parser log messages, only show codecompletion test result and the show fail and pass testing counts. If the user need to see the full parser log messages, they should define them, which will plot a log of log messages.
3, redirect the wxLogMessage to the text ctrl of the frame.
4, fix typo in comments, and add some comments.
5, project target setting change, make it a gui app instead of console app, and redirect the wxLogMessage to the wxTextCtrl.
6, set the default parsing file to testing/cc_function_decls.cpp, not the default test.h
7, add the wxsmith file to cbp, so it can be opened quickly from the project manager.
8, by default, Token tree structure is not logged, but it can be logged by click the "Print Tree" button.
9, add some string variable to the wx and gcc search path, avoid the hard-coded path.

git-svn-id: https://svn.code.sf.net/p/codeblocks/code/[email protected] 2a5c6006-c6dd-42ca-98ab-0921f2732cef
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline MortenMacFly

  • Administrator
  • Lives here!
  • *****
  • Posts: 9504
Re: no need to run m_NativeParser.Parse(m_CurrentFile) in cctest
« Reply #42 on: March 02, 2014, 03:45:04 pm »
BTW: Here is the log message I see:
Code: [Select]
000001. --------------M-a-i-n--L-o-g--------------


000002. -----------I-n-t-e-r-i-m--L-o-g-----------
********************************************************
  Testing in file: C:\DOCUME~1\zyh23\LOCALS~2\Temp\cc125.h
********************************************************
*FAIL:  vt[1].  GetInt
-PASS:  g_S.  i
-PASS:  g_  g_S
-PASS:  tc.Vo  Void
-PASS:  tc.St  StaticVoid
-PASS:  tc.GetC  GetClass
-PASS:  tc.GetI  GetInt
-PASS:  str.  size
-PASS:  str.  length
--------------------------------------------------------
Total 9 tests, 8 PASS, 1 FAIL
--------------------------------------------------------
Yes, the verbose part of how the parser works is missing there, too. But thats the part (at least) I am usually interested.
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: http://www.codeblocks.org/docs/main_codeblocks_en.html
C::B FAQ: http://wiki.codeblocks.org/index.php?title=FAQ

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5230
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: no need to run m_NativeParser.Parse(m_CurrentFile) in cctest
« Reply #43 on: March 02, 2014, 03:53:57 pm »
BTW: Here is the log message I see:
Code: [Select]
000001. --------------M-a-i-n--L-o-g--------------


000002. -----------I-n-t-e-r-i-m--L-o-g-----------
********************************************************
  Testing in file: C:\DOCUME~1\zyh23\LOCALS~2\Temp\cc125.h
********************************************************
*FAIL:  vt[1].  GetInt
-PASS:  g_S.  i
-PASS:  g_  g_S
-PASS:  tc.Vo  Void
-PASS:  tc.St  StaticVoid
-PASS:  tc.GetC  GetClass
-PASS:  tc.GetI  GetInt
-PASS:  str.  size
-PASS:  str.  length
--------------------------------------------------------
Total 9 tests, 8 PASS, 1 FAIL
--------------------------------------------------------
Yes, the verbose part of how the parser works is missing there, too. But thats the part (at least) I am usually interested.
You can simply add the CC_PARSER_TEST, then every verbose log messages are returned, but parsing a file (specially have many #include files) will takes for a long time.  ;)
Maybe, we can add an option?
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline MortenMacFly

  • Administrator
  • Lives here!
  • *****
  • Posts: 9504
Re:
« Reply #44 on: March 02, 2014, 07:25:59 pm »
Well the default case for me is that I have a small code snippet to reproduce a certain error. Then it will be very fast and the information is essential to track down parser errors. So yes, please make it an option which imho should be enabled by default.
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: http://www.codeblocks.org/docs/main_codeblocks_en.html
C::B FAQ: http://wiki.codeblocks.org/index.php?title=FAQ