diff options
author | Ken Martin <ken.martin@kitware.com> | 2005-03-28 18:23:07 (GMT) |
---|---|---|
committer | Ken Martin <ken.martin@kitware.com> | 2005-03-28 18:23:07 (GMT) |
commit | 11965ebd34a41c6c1c452ae87134dd8a2221d5e2 (patch) | |
tree | 30f3ffd3e014777287a4a596825acf2a15d0eeb2 /Source/MFCDialog | |
parent | 98f30a3d29d4c1002aee3d66503d09bd85e926fa (diff) | |
download | CMake-11965ebd34a41c6c1c452ae87134dd8a2221d5e2.zip CMake-11965ebd34a41c6c1c452ae87134dd8a2221d5e2.tar.gz CMake-11965ebd34a41c6c1c452ae87134dd8a2221d5e2.tar.bz2 |
ENH: change how the generator is selected and what the last one used was
Diffstat (limited to 'Source/MFCDialog')
-rw-r--r-- | Source/MFCDialog/CMakeGenDialog.cpp | 129 | ||||
-rw-r--r-- | Source/MFCDialog/CMakeGenDialog.h | 70 | ||||
-rw-r--r-- | Source/MFCDialog/CMakeLists.txt | 8 | ||||
-rw-r--r-- | Source/MFCDialog/CMakeSetup.rc | 29 | ||||
-rw-r--r-- | Source/MFCDialog/CMakeSetupDialog.cpp | 107 | ||||
-rw-r--r-- | Source/MFCDialog/CMakeSetupDialog.h | 9 | ||||
-rw-r--r-- | Source/MFCDialog/resource.h | 3 |
7 files changed, 269 insertions, 86 deletions
diff --git a/Source/MFCDialog/CMakeGenDialog.cpp b/Source/MFCDialog/CMakeGenDialog.cpp new file mode 100644 index 0000000..a72a6d0 --- /dev/null +++ b/Source/MFCDialog/CMakeGenDialog.cpp @@ -0,0 +1,129 @@ +// CMakeGenDialog.cpp : implementation file +// + +#include "stdafx.h" +#include "CMakeSetup.h" +#include "CMakeGenDialog.h" +#include "../cmake.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CCMakeGenDialog dialog + + +CCMakeGenDialog::CCMakeGenDialog(CWnd* pParent /*=NULL*/) + : CDialog(CCMakeGenDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CCMakeGenDialog) + //}}AFX_DATA_INIT +} + + +void CCMakeGenDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CCMakeGenDialog) + DDX_Control(pDX, IDC_BuildForLabel, m_BuildForLabel); + DDX_Control(pDX, IDC_Generator, m_GeneratorChoice); + DDX_CBStringExact(pDX, IDC_Generator, m_GeneratorChoiceString); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CCMakeGenDialog, CDialog) + //{{AFX_MSG_MAP(CCMakeGenDialog) + // NOTE: the ClassWizard will add message map macros here + ON_CBN_EDITCHANGE(IDC_Generator, OnEditchangeGenerator) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CCMakeGenDialog message handler + + void CCMakeGenDialog::OnEditchangeGenerator() +{ + // TODO: Add your control notification handler code here + +} + + +BOOL CCMakeGenDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + std::vector<std::string> names; + this->m_CMakeInstance->GetRegisteredGenerators(names); + for(std::vector<std::string>::iterator i = names.begin(); + i != names.end(); ++i) + { + m_GeneratorChoice.AddString(i->c_str()); + } + + // we want to pick the best generator for their system first we check to + // see if they have run cmake before, if so we use that generator + std::string mp; + bool done = false; + + // is the last generator set? If so use it + mp = "[HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;LastGenerator]"; + cmSystemTools::ExpandRegistryValues(mp); + if(mp != "/registry") + { + m_GeneratorChoiceString = mp.c_str(); + done = true; + } + + // look for VS8 + if (!done) + { + // check for vs8 in registry then decide what default to use + mp = + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup;Dbghelp_path]"; + cmSystemTools::ExpandRegistryValues(mp); + if(mp != "/registry") + { + m_GeneratorChoiceString = "Visual Studio 8 2005"; + done = true; + } + } + + // look for VS7.1 + if (!done) + { + mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]"; + cmSystemTools::ExpandRegistryValues(mp); + if (mp != "/registry") + { + m_GeneratorChoiceString = "Visual Studio 7 .NET 2003"; + done = true; + } + } + + // look for VS7 + if (!done) + { + mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.0;InstallDir]"; + cmSystemTools::ExpandRegistryValues(mp); + if (mp != "/registry") + { + m_GeneratorChoiceString = "Visual Studio 7"; + done = true; + } + } + + // if still not done just guess on VS 6 + if (!done) + { + m_GeneratorChoiceString = "Visual Studio 6"; + } + + this->UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control +} + + diff --git a/Source/MFCDialog/CMakeGenDialog.h b/Source/MFCDialog/CMakeGenDialog.h new file mode 100644 index 0000000..f921f18 --- /dev/null +++ b/Source/MFCDialog/CMakeGenDialog.h @@ -0,0 +1,70 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#if !defined(CMAKE_GEN_DIALOG_INCLUDED) +#define CMAKE_GEN_DIALOG_INCLUDED + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// CMakeGenDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CCMakeGenDialog dialog + +class cmake; + +class CCMakeGenDialog : public CDialog +{ +// Construction +public: + CCMakeGenDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CCMakeGenDialog) + enum { IDD = IDD_GEN_DIALOG }; + CStatic m_BuildForLabel; + CComboBox m_GeneratorChoice; + CString m_GeneratorChoiceString; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CCMakeGenDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CCMakeGenDialog) + virtual BOOL OnInitDialog(); + afx_msg void OnEditchangeGenerator(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + + public: + cmake *m_CMakeInstance; +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif diff --git a/Source/MFCDialog/CMakeLists.txt b/Source/MFCDialog/CMakeLists.txt index 35609f3..060509f 100644 --- a/Source/MFCDialog/CMakeLists.txt +++ b/Source/MFCDialog/CMakeLists.txt @@ -1,11 +1,19 @@ SET( SRCS + CMakeSetup.h CMakeSetup.cpp + MakeHelp.h MakeHelp.cpp + CMakeGenDialog.h + CMakeGenDialog.cpp CMakeSetup.rc + CMakeSetupDialog.h CMakeSetupDialog.cpp + PathDialog.h PathDialog.cpp PropertyList.cpp + StdAfx.h StdAfx.cpp + resource.h CMakeCommandLineInfo.cpp ) diff --git a/Source/MFCDialog/CMakeSetup.rc b/Source/MFCDialog/CMakeSetup.rc index 6c0eb20..e1f9662 100644 --- a/Source/MFCDialog/CMakeSetup.rc +++ b/Source/MFCDialog/CMakeSetup.rc @@ -98,12 +98,8 @@ BEGIN COMBOBOX IDC_WhereBuild,96,26,169,68,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Browse...",IDC_BROWSE_BUILD,267,25,34,13 - RTEXT "Build For:",IDC_BuildForLabel,305,8,34,11, - SS_CENTERIMAGE - COMBOBOX IDC_Generator,345,7,97,50,CBS_DROPDOWN | CBS_SORT | - WS_VSCROLL | WS_TABSTOP CONTROL "Show Advanced Values",IDC_AdvancedValues,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,305,28,98,9 + BS_AUTOCHECKBOX | WS_TABSTOP,321,18,98,9 DEFPUSHBUTTON "Configure",IDC_BuildProjects,84,221,51,15 PUSHBUTTON "OK",IDC_OK,141,221,51,15 PUSHBUTTON "Cancel",IDCANCEL,198,221,51,15 @@ -129,6 +125,21 @@ BEGIN WS_BORDER END +IDD_GEN_DIALOG DIALOGEX 0, 0, 263, 86 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "Select Generator" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,70,65,50,14 + PUSHBUTTON "Cancel",IDCANCEL,143,65,50,14 + RTEXT "Build For:",IDC_BuildForLabel,7,45,34,11,SS_CENTERIMAGE + COMBOBOX IDC_Generator,52,45,204,117,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + CTEXT "Please select what build system you want CMake to generate files for.\nYou should select the tool that you will use to build the project.\nPress OK once you have made your selection.", + IDC_MouseHelpCaption,7,7,245,36 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -197,6 +208,14 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 176 END + + IDD_GEN_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 256 + TOPMARGIN, 7 + BOTTOMMARGIN, 79 + END END #endif // APSTUDIO_INVOKED diff --git a/Source/MFCDialog/CMakeSetupDialog.cpp b/Source/MFCDialog/CMakeSetupDialog.cpp index 7f7d8f3..fc2a6dd 100644 --- a/Source/MFCDialog/CMakeSetupDialog.cpp +++ b/Source/MFCDialog/CMakeSetupDialog.cpp @@ -179,7 +179,8 @@ CMakeSetupDialog::CMakeSetupDialog(const CMakeCommandLineInfo& cmdInfo, { this->m_WhereSource = cmdInfo.m_WhereSource; this->m_WhereBuild = cmdInfo.m_WhereBuild; - this->m_GeneratorChoiceString = cmdInfo.m_GeneratorChoiceString; + this->m_GeneratorDialog.m_GeneratorChoiceString = + cmdInfo.m_GeneratorChoiceString; this->m_AdvancedValues = cmdInfo.m_AdvancedValues; } else @@ -187,7 +188,8 @@ CMakeSetupDialog::CMakeSetupDialog(const CMakeCommandLineInfo& cmdInfo, this->m_WhereSource = _T(""); this->m_WhereBuild = _T(""); this->m_AdvancedValues = FALSE; - this->m_GeneratorChoiceString = cmdInfo.m_GeneratorChoiceString; + this->m_GeneratorDialog.m_GeneratorChoiceString = + cmdInfo.m_GeneratorChoiceString; this->ChangeDirectoriesFromFile((LPCTSTR)cmdInfo.m_LastUnknownParameter); } @@ -219,12 +221,10 @@ void CMakeSetupDialog::DoDataExchange(CDataExchange* pDX) CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CMakeSetupDialog) DDX_Control(pDX, IDC_AdvancedValues, m_AdvancedValuesControl); - DDX_Control(pDX, IDC_BuildForLabel, m_BuildForLabel); DDX_Control(pDX, IDC_BROWSE_SOURCE, m_BrowseSource); DDX_Control(pDX, IDC_BROWSE_BUILD, m_BrowseBuild); DDX_Control(pDX, IDC_DELETE_BUTTON, m_DeleteButton); DDX_Control(pDX, IDC_HELP_BUTTON, m_HelpButton); - DDX_Control(pDX, IDC_Generator, m_GeneratorChoice); DDX_Control(pDX, IDC_OK, m_OKButton); DDX_Control(pDX, IDCANCEL, m_CancelButton); DDX_CBStringExact(pDX, IDC_WhereSource, m_WhereSource); @@ -236,7 +236,6 @@ void CMakeSetupDialog::DoDataExchange(CDataExchange* pDX) DDX_Control(pDX, IDC_MouseHelpCaption, m_MouseHelp); DDX_Control(pDX, IDC_PROGRESS, m_StatusDisplay); DDX_Control(pDX, IDC_BuildProjects, m_Configure); - DDX_CBStringExact(pDX, IDC_Generator, m_GeneratorChoiceString); DDX_Check(pDX, IDC_AdvancedValues, m_AdvancedValues); //}}AFX_DATA_MAP } @@ -256,7 +255,6 @@ BEGIN_MESSAGE_MAP(CMakeSetupDialog, CDialog) ON_WM_SIZE() ON_WM_GETMINMAXINFO() ON_BN_CLICKED(IDC_OK, OnOk) - ON_CBN_EDITCHANGE(IDC_Generator, OnEditchangeGenerator) ON_BN_CLICKED(IDC_DELETE_BUTTON, OnDeleteButton) ON_BN_CLICKED(IDC_HELP_BUTTON, OnHelpButton) ON_BN_CLICKED(IDC_AdvancedValues, OnAdvancedValues) @@ -317,53 +315,11 @@ BOOL CMakeSetupDialog::OnInitDialog() SetIcon(m_hIcon, FALSE); // Set small icon // Load source and build dirs from registry this->LoadFromRegistry(); - std::vector<std::string> names; - this->m_CMakeInstance->GetRegisteredGenerators(names); - for(std::vector<std::string>::iterator i = names.begin(); - i != names.end(); ++i) - { - m_GeneratorChoice.AddString(i->c_str()); - } - if (m_GeneratorChoiceString == _T("")) - { - // check for vs7 in registry then decide what default to use - std::string mp; - mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup;Dbghelp_path]"; - cmSystemTools::ExpandRegistryValues(mp); - if(mp != "/registry") - { - m_GeneratorChoiceString = "Visual Studio 8 2005"; - } - else - { - mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]"; - cmSystemTools::ExpandRegistryValues(mp); - if (mp != "/registry") - { - m_GeneratorChoiceString = "Visual Studio 7 .NET 2003"; - } - else - { - mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.0;InstallDir]"; - cmSystemTools::ExpandRegistryValues(mp); - if (mp != "/registry") - { - m_GeneratorChoiceString = "Visual Studio 7"; - } - else - { - m_GeneratorChoiceString = "Visual Studio 6"; - } - } - } - } - // try to load the cmake cache from disk this->LoadCacheFromDiskToGUI(); m_WhereBuildControl.LimitText(2048); m_WhereSourceControl.LimitText(2048); - m_GeneratorChoice.LimitText(2048); // Set the version number char tmp[1024]; @@ -686,7 +642,7 @@ void CMakeSetupDialog::RunCMake(bool generateProjectFiles) m_CMakeInstance->SetHomeOutputDirectory(m_WhereBuild); m_CMakeInstance->SetStartOutputDirectory(m_WhereBuild); m_CMakeInstance->SetGlobalGenerator( - m_CMakeInstance->CreateGlobalGenerator(m_GeneratorChoiceString)); + m_CMakeInstance->CreateGlobalGenerator(m_GeneratorDialog.m_GeneratorChoiceString)); m_CMakeInstance->SetCMakeCommand(m_PathToExecutable); m_CMakeInstance->LoadCache(); if(m_CMakeInstance->Configure() != 0) @@ -714,10 +670,28 @@ void CMakeSetupDialog::RunCMake(bool generateProjectFiles) // Callback for build projects button void CMakeSetupDialog::OnConfigure() { - // if(!m_GeneratorPicked) -// { -// // generator has not been picked add one here -// } + if(!m_GeneratorPicked) + { + m_GeneratorDialog.m_CMakeInstance = this->m_CMakeInstance; + if(m_GeneratorDialog.DoModal() != IDOK) + { + return; + } + // save the generator choice in the registry + HKEY hKey; + DWORD dwDummy; + + if(RegCreateKeyEx(HKEY_CURRENT_USER, + m_RegistryKey, + 0, "", REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, + NULL, &hKey, &dwDummy) == ERROR_SUCCESS) + { + // save some values + RegSetValueEx(hKey, _T("LastGenerator"), 0, REG_SZ, + (CONST BYTE *)(const char *)m_GeneratorDialog.m_GeneratorChoiceString, + m_GeneratorDialog.m_GeneratorChoiceString.GetLength()); + } + } // enable error messages each time configure is pressed cmSystemTools::EnableMessages(); @@ -992,9 +966,9 @@ void CMakeSetupDialog::LoadCacheFromDiskToGUI() { m_GeneratorPicked = true; std::string curGen = it.GetValue(); - if(m_GeneratorChoiceString != curGen.c_str()) + if(m_GeneratorDialog.m_GeneratorChoiceString != curGen.c_str()) { - m_GeneratorChoiceString = curGen.c_str(); + m_GeneratorDialog.m_GeneratorChoiceString = curGen.c_str(); this->UpdateData(FALSE); } } @@ -1049,18 +1023,6 @@ void CMakeSetupDialog::OnSize(UINT nType, int cx, int cy) 0, 0, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOZORDER); - m_BuildForLabel.GetWindowRect(&cRect); - this->ScreenToClient(&cRect); - m_BuildForLabel.SetWindowPos(&wndTop, cRect.left + deltax, - cRect.top, - 0, 0, - SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOZORDER); - m_GeneratorChoice.GetWindowRect(&cRect); - this->ScreenToClient(&cRect); - m_GeneratorChoice.SetWindowPos(&wndTop, cRect.left + deltax, - cRect.top, - 0, 0, - SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOZORDER); m_BrowseSource.GetWindowRect(&cRect); this->ScreenToClient(&cRect); m_BrowseSource.SetWindowPos(&wndTop, cRect.left + deltax, @@ -1196,13 +1158,6 @@ void CMakeSetupDialog::OnOk() } } -void CMakeSetupDialog::OnEditchangeGenerator() -{ - // TODO: Add your control notification handler code here - -} - - // Create a shortcut on the desktop with the current Source/Build dir. int CMakeSetupDialog::CreateShortcut() { @@ -1296,7 +1251,7 @@ int CMakeSetupDialog::CreateShortcut() } // Set the arguments of the shortcut. - CString args = " /H=\"" + m_WhereSource + "\" /B=\"" + m_WhereBuild + "\" /G=\"" + m_GeneratorChoiceString + "\" /A=\"" + (m_AdvancedValues ? "TRUE" : "FALSE") + "\""; + CString args = " /H=\"" + m_WhereSource + "\" /B=\"" + m_WhereBuild + "\" /G=\"" + m_GeneratorDialog.m_GeneratorChoiceString + "\" /A=\"" + (m_AdvancedValues ? "TRUE" : "FALSE") + "\""; hres = psl->SetArguments(args); @@ -1445,7 +1400,7 @@ void CMakeSetupDialog::ChangeDirectoriesFromFile(const char* arg) path = ConvertToWindowsPath(it.GetValue()); m_WhereSource = path.c_str(); - m_GeneratorChoiceString = _T(""); + m_GeneratorDialog.m_GeneratorChoiceString = _T(""); return; } } diff --git a/Source/MFCDialog/CMakeSetupDialog.h b/Source/MFCDialog/CMakeSetupDialog.h index 4825368..5311a84 100644 --- a/Source/MFCDialog/CMakeSetupDialog.h +++ b/Source/MFCDialog/CMakeSetupDialog.h @@ -26,6 +26,8 @@ PURPOSE. See the above copyright notices for more information. #include "PropertyList.h" +#include "CMakeGenDialog.h" + ///////////////////////////////////////////////////////////////////////////// // CMakeSetupDialog dialog @@ -61,12 +63,10 @@ protected: //{{AFX_DATA(CMakeSetupDialog) enum { IDD = IDD_CMakeSetupDialog_DIALOG }; CButton m_AdvancedValuesControl; - CStatic m_BuildForLabel; CButton m_BrowseSource; CButton m_BrowseBuild; CButton m_HelpButton; CButton m_DeleteButton; - CComboBox m_GeneratorChoice; CButton m_OKButton; CButton m_CancelButton; CString m_WhereSource; @@ -79,7 +79,6 @@ protected: CStatic m_MouseHelp; CStatic m_StatusDisplay; CButton m_Configure; - CString m_GeneratorChoiceString; BOOL m_AdvancedValues; //}}AFX_DATA @@ -122,7 +121,6 @@ protected: afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnGetMinMaxInfo( MINMAXINFO FAR* lpMMI ); afx_msg void OnOk(); - afx_msg void OnEditchangeGenerator(); afx_msg void OnHelpButton(); afx_msg void OnDeleteButton(); afx_msg void OnAdvancedValues(); @@ -139,6 +137,9 @@ protected: HCURSOR m_Cursor; bool m_RunningConfigure; bool m_GeneratorPicked; + + CCMakeGenDialog m_GeneratorDialog; + }; //{{AFX_INSERT_LOCATION}} diff --git a/Source/MFCDialog/resource.h b/Source/MFCDialog/resource.h index 790102d..a4160a7 100644 --- a/Source/MFCDialog/resource.h +++ b/Source/MFCDialog/resource.h @@ -10,6 +10,7 @@ #define IDS_CREATESHORTCUT 102 #define IDR_MAINFRAME 128 #define IDD_CMAKE_HELP_DIALOG 133 +#define IDD_GEN_DIALOG 134 #define IDC_WhereSource 1001 #define IDC_BUTTON2 1002 #define IDC_BROWSE_SOURCE 1002 @@ -37,7 +38,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 134 +#define _APS_NEXT_RESOURCE_VALUE 135 #define _APS_NEXT_COMMAND_VALUE 32771 #define _APS_NEXT_CONTROL_VALUE 1030 #define _APS_NEXT_SYMED_VALUE 102 |