diff --git a/favourite_terminal.txt b/favourite_terminal.txt new file mode 100644 index 0000000..215d430 --- /dev/null +++ b/favourite_terminal.txt @@ -0,0 +1,11 @@ +xfce4-terminal -e + +# The first two lines of this file contain the prefix and suffix +# that it takes to execute a shell script in your favourite terminal. +# examples (note that some lines contain a trailing space): +# xfce4-terminal -e +# +# xterm -hold -e +# +# terminus -e +# diff --git a/phyportal b/phyportal new file mode 100644 index 0000000..423626d Binary files /dev/null and b/phyportal differ diff --git a/phyportal.exe b/phyportal.exe new file mode 100644 index 0000000..86c9f2f Binary files /dev/null and b/phyportal.exe differ diff --git a/phyportal.ico b/phyportal.ico new file mode 100644 index 0000000..0341321 Binary files /dev/null and b/phyportal.ico differ diff --git a/phyportal.lpi b/phyportal.lpi new file mode 100644 index 0000000..69896fa --- /dev/null +++ b/phyportal.lpi @@ -0,0 +1,87 @@ + + + + + + + + + + + + <Scaled Value="True"/> + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <XPManifest> + <DpiAware Value="True"/> + </XPManifest> + <Icon Value="0"/> + </General> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + </RunParams> + <RequiredPackages Count="1"> + <Item1> + <PackageName Value="LCL"/> + </Item1> + </RequiredPackages> + <Units Count="3"> + <Unit0> + <Filename Value="phyportal.lpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="unit1.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="Form1"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="Unit1"/> + </Unit1> + <Unit2> + <Filename Value="unit2.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="Form2"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="Unit2"/> + </Unit2> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="phyportal"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf2Set"/> + </Debugging> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/phyportal.lpr b/phyportal.lpr new file mode 100644 index 0000000..d10d657 --- /dev/null +++ b/phyportal.lpr @@ -0,0 +1,23 @@ +program phyportal; + +{$mode objfpc}{$H+} + +uses + {$IFDEF UNIX}{$IFDEF UseCThreads} + cthreads, + {$ENDIF}{$ENDIF} + Interfaces, // this includes the LCL widgetset + Forms, Unit1, Unit2 + { you can add units after this }; + +{$R *.res} + +begin + RequireDerivedFormResource:=True; + Application.Scaled:=True; + Application.Initialize; + Application.CreateForm(TForm1, Form1); + Application.CreateForm(TForm2, Form2); + Application.Run; +end. + diff --git a/phyportal.lps b/phyportal.lps new file mode 100644 index 0000000..424f729 --- /dev/null +++ b/phyportal.lps @@ -0,0 +1,179 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectSession> + <PathDelim Value="\"/> + <Version Value="12"/> + <BuildModes Active="Default"/> + <Units Count="4"> + <Unit0> + <Filename Value="phyportal.lpr"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="-1"/> + <WindowIndex Value="-1"/> + <TopLine Value="-1"/> + <CursorPos X="-1" Y="-1"/> + <UsageCount Value="183"/> + </Unit0> + <Unit1> + <Filename Value="unit1.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="Form1"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="Unit1"/> + <IsVisibleTab Value="True"/> + <TopLine Value="539"/> + <CursorPos X="68" Y="551"/> + <UsageCount Value="183"/> + <Loaded Value="True"/> + <LoadedDesigner Value="True"/> + </Unit1> + <Unit2> + <Filename Value="unit2.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="Form2"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="Unit2"/> + <EditorIndex Value="1"/> + <TopLine Value="24"/> + <CursorPos X="77" Y="49"/> + <UsageCount Value="178"/> + <Loaded Value="True"/> + <LoadedDesigner Value="True"/> + </Unit2> + <Unit3> + <Filename Value="C:\lazarus\fpc\3.0.4\source\packages\fcl-process\src\process.pp"/> + <EditorIndex Value="-1"/> + <TopLine Value="268"/> + <CursorPos X="21" Y="24"/> + <UsageCount Value="5"/> + </Unit3> + </Units> + <JumpHistory Count="30" HistoryIndex="29"> + <Position1> + <Filename Value="unit1.pas"/> + <Caret Line="729" TopLine="716"/> + </Position1> + <Position2> + <Filename Value="unit1.pas"/> + <Caret Line="730" TopLine="716"/> + </Position2> + <Position3> + <Filename Value="unit1.pas"/> + <Caret Line="733" TopLine="716"/> + </Position3> + <Position4> + <Filename Value="unit1.pas"/> + <Caret Line="736" TopLine="716"/> + </Position4> + <Position5> + <Filename Value="unit1.pas"/> + <Caret Line="725" TopLine="716"/> + </Position5> + <Position6> + <Filename Value="unit1.pas"/> + <Caret Line="729" TopLine="716"/> + </Position6> + <Position7> + <Filename Value="unit1.pas"/> + <Caret Line="730" TopLine="716"/> + </Position7> + <Position8> + <Filename Value="unit1.pas"/> + <Caret Line="733" TopLine="716"/> + </Position8> + <Position9> + <Filename Value="unit1.pas"/> + <Caret Line="686" Column="76" TopLine="674"/> + </Position9> + <Position10> + <Filename Value="unit1.pas"/> + </Position10> + <Position11> + <Filename Value="unit1.pas"/> + <Caret Line="488" Column="3" TopLine="467"/> + </Position11> + <Position12> + <Filename Value="unit1.pas"/> + <Caret Line="763" Column="12" TopLine="742"/> + </Position12> + <Position13> + <Filename Value="unit1.pas"/> + <Caret Line="201" Column="86" TopLine="193"/> + </Position13> + <Position14> + <Filename Value="unit1.pas"/> + <Caret Line="204" Column="18" TopLine="191"/> + </Position14> + <Position15> + <Filename Value="unit1.pas"/> + <Caret Line="190" Column="52" TopLine="176"/> + </Position15> + <Position16> + <Filename Value="unit1.pas"/> + <Caret Line="926" Column="20" TopLine="924"/> + </Position16> + <Position17> + <Filename Value="unit1.pas"/> + <Caret Line="12" Column="3"/> + </Position17> + <Position18> + <Filename Value="unit1.pas"/> + <Caret Line="584" Column="54" TopLine="476"/> + </Position18> + <Position19> + <Filename Value="unit1.pas"/> + <Caret Line="488" Column="75" TopLine="479"/> + </Position19> + <Position20> + <Filename Value="unit1.pas"/> + <Caret Line="323" Column="11" TopLine="308"/> + </Position20> + <Position21> + <Filename Value="unit1.pas"/> + <Caret Line="10" Column="26"/> + </Position21> + <Position22> + <Filename Value="unit1.pas"/> + <Caret Line="71" Column="11" TopLine="51"/> + </Position22> + <Position23> + <Filename Value="unit1.pas"/> + <Caret Line="74" Column="11" TopLine="54"/> + </Position23> + <Position24> + <Filename Value="unit1.pas"/> + <Caret Line="75" Column="11" TopLine="55"/> + </Position24> + <Position25> + <Filename Value="unit1.pas"/> + <Caret Line="76" Column="11" TopLine="56"/> + </Position25> + <Position26> + <Filename Value="unit1.pas"/> + <Caret Line="77" Column="11" TopLine="57"/> + </Position26> + <Position27> + <Filename Value="unit1.pas"/> + <Caret Line="305" Column="15" TopLine="284"/> + </Position27> + <Position28> + <Filename Value="unit1.pas"/> + <Caret Line="323" Column="15" TopLine="302"/> + </Position28> + <Position29> + <Filename Value="unit1.pas"/> + <Caret Line="12" Column="24"/> + </Position29> + <Position30> + <Filename Value="unit1.pas"/> + <Caret Line="85" Column="16" TopLine="58"/> + </Position30> + </JumpHistory> + <RunParams> + <FormatVersion Value="2"/> + <Modes ActiveMode=""/> + </RunParams> + </ProjectSession> +</CONFIG> diff --git a/phyportal.res b/phyportal.res new file mode 100644 index 0000000..1adb040 Binary files /dev/null and b/phyportal.res differ diff --git a/unit1.lfm b/unit1.lfm new file mode 100644 index 0000000..eeeeabd --- /dev/null +++ b/unit1.lfm @@ -0,0 +1,959 @@ +object Form1: TForm1 + Left = 550 + Height = 781 + Top = 0 + Width = 1016 + Caption = 'phyportal' + ClientHeight = 781 + ClientWidth = 1016 + Color = clNavy + Font.Height = -14 + Font.Name = 'Open Sans' + OnCreate = FormCreate + OnShow = FormShow + Position = poDesktopCenter + LCLVersion = '2.2.0.4' + object Shape1: TShape + Left = 13 + Height = 288 + Top = 64 + Width = 986 + Brush.Color = clSilver + Pen.Style = psClear + end + object Label1: TLabel + Left = 19 + Height = 20 + Top = 90 + Width = 39 + Caption = 'phy-1' + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object LabelCPU1: TLabel + Left = 90 + Height = 20 + Top = 90 + Width = 116 + Caption = 'CPUs busy (total):' + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + end + object LabelMEM1: TLabel + Left = 90 + Height = 20 + Top = 115 + Width = 114 + Caption = 'RAM used (total):' + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + end + object Button2: TButton + Left = 90 + Height = 25 + Top = 141 + Width = 124 + Caption = 'more info...' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button2Click + ParentFont = False + TabOrder = 0 + end + object Memo1: TMemo + Left = 397 + Height = 76 + Top = 90 + Width = 421 + Font.Height = -14 + Font.Name = 'Open Sans' + Lines.Strings = ( + 'getm (by klingbei) uses 50 cores (expected end 2023-10-10)' + 'cdo merge (by thomas) uses 2 cores (expected end 2023-10-10)' + ) + OnChange = Memo1Change + ParentFont = False + ReadOnly = True + ScrollBars = ssBoth + TabOrder = 1 + WordWrap = False + end + object Button3: TButton + Left = 826 + Height = 25 + Top = 90 + Width = 165 + Caption = 'start jupyter lab' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button3Click + ParentFont = False + TabOrder = 2 + end + object Button4: TButton + Left = 825 + Height = 25 + Top = 115 + Width = 166 + Caption = 'start console' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button4Click + ParentFont = False + TabOrder = 3 + end + object Label4: TLabel + Left = 19 + Height = 20 + Top = 64 + Width = 165 + Caption = 'IOW COMPUTE SERVERS' + Font.Color = clGreen + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object Button5: TButton + Left = 825 + Height = 25 + Top = 141 + Width = 166 + Caption = 'start console via xpra' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button5Click + ParentFont = False + TabOrder = 4 + end + object Shape2: TShape + Left = 13 + Height = 51 + Top = 6 + Width = 986 + Brush.Color = clSilver + Pen.Style = psClear + end + object Label5: TLabel + Left = 19 + Height = 20 + Top = 6 + Width = 41 + Caption = 'LINKS' + Font.Color = clGreen + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object Button1: TButton + Left = 19 + Height = 25 + Top = 26 + Width = 114 + Caption = 'beginners'' intro' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button1Click + ParentFont = False + TabOrder = 5 + end + object Button6: TButton + Left = 134 + Height = 25 + Top = 26 + Width = 114 + Caption = 'phywiki' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button6Click + ParentFont = False + TabOrder = 6 + end + object Button7: TButton + Left = 250 + Height = 25 + Top = 26 + Width = 114 + Caption = 'webmail' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button7Click + ParentFont = False + TabOrder = 7 + end + object Button8: TButton + Left = 365 + Height = 25 + Top = 26 + Width = 114 + Caption = 'chat' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button8Click + ParentFont = False + TabOrder = 8 + end + object Button9: TButton + Left = 480 + Height = 25 + Top = 26 + Width = 114 + Caption = 'owncloud' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button9Click + ParentFont = False + TabOrder = 9 + end + object Button10: TButton + Left = 595 + Height = 25 + Top = 26 + Width = 114 + Caption = 'public drive' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button10Click + ParentFont = False + TabOrder = 10 + end + object Button11: TButton + Left = 710 + Height = 25 + Top = 26 + Width = 114 + Caption = 'git server' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button11Click + ParentFont = False + TabOrder = 11 + end + object Label6: TLabel + Left = 19 + Height = 20 + Top = 179 + Width = 39 + Caption = 'phy-2' + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object LabelCPU2: TLabel + Left = 90 + Height = 20 + Top = 179 + Width = 116 + Caption = 'CPUs busy (total):' + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + end + object LabelMEM2: TLabel + Left = 90 + Height = 20 + Top = 205 + Width = 114 + Caption = 'RAM used (total):' + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + end + object Button12: TButton + Left = 90 + Height = 25 + Top = 230 + Width = 124 + Caption = 'more info...' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button12Click + ParentFont = False + TabOrder = 12 + end + object Memo2: TMemo + Left = 397 + Height = 76 + Top = 179 + Width = 421 + Font.Height = -14 + Font.Name = 'Open Sans' + Lines.Strings = ( + 'getm (by klingbei) uses 50 cores (expected end 2023-10-10)' + 'cdo merge (by thomas) uses 2 cores (expected end 2023-10-10)' + ) + OnChange = Memo1Change + ParentFont = False + ReadOnly = True + ScrollBars = ssBoth + TabOrder = 13 + WordWrap = False + end + object Button13: TButton + Left = 826 + Height = 25 + Top = 179 + Width = 165 + Caption = 'start jupyter lab' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button13Click + ParentFont = False + TabOrder = 14 + end + object Button14: TButton + Left = 825 + Height = 25 + Top = 205 + Width = 166 + Caption = 'start console' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button14Click + ParentFont = False + TabOrder = 15 + end + object Button15: TButton + Left = 825 + Height = 25 + Top = 230 + Width = 166 + Caption = 'start console via xpra' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button15Click + ParentFont = False + TabOrder = 16 + end + object Label9: TLabel + Left = 19 + Height = 20 + Top = 269 + Width = 39 + Caption = 'phy-3' + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object LabelCPU3: TLabel + Left = 90 + Height = 20 + Top = 269 + Width = 116 + Caption = 'CPUs busy (total):' + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + end + object LabelMEM3: TLabel + Left = 90 + Height = 20 + Top = 294 + Width = 114 + Caption = 'RAM used (total):' + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + end + object Button16: TButton + Left = 90 + Height = 25 + Top = 320 + Width = 124 + Caption = 'more info...' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button16Click + ParentFont = False + TabOrder = 17 + end + object Memo3: TMemo + Left = 397 + Height = 76 + Top = 269 + Width = 421 + Font.Height = -14 + Font.Name = 'Open Sans' + Lines.Strings = ( + 'getm (by klingbei) uses 50 cores (expected end 2023-10-10)' + 'cdo merge (by thomas) uses 2 cores (expected end 2023-10-10)' + ) + OnChange = Memo1Change + ParentFont = False + ReadOnly = True + ScrollBars = ssBoth + TabOrder = 18 + WordWrap = False + end + object Button17: TButton + Left = 826 + Height = 25 + Top = 269 + Width = 165 + Caption = 'start jupyter lab' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button17Click + ParentFont = False + TabOrder = 19 + end + object Button18: TButton + Left = 825 + Height = 25 + Top = 294 + Width = 166 + Caption = 'start console' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button18Click + ParentFont = False + TabOrder = 20 + end + object Button19: TButton + Left = 825 + Height = 25 + Top = 320 + Width = 166 + Caption = 'start console via xpra' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button19Click + ParentFont = False + TabOrder = 21 + end + object Shape3: TShape + Left = 13 + Height = 109 + Top = 358 + Width = 986 + Brush.Color = clSilver + Pen.Style = psClear + end + object Label12: TLabel + Left = 19 + Height = 20 + Top = 384 + Width = 39 + Caption = 'phy-4' + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object LabelCPU4: TLabel + Left = 90 + Height = 20 + Top = 384 + Width = 116 + Caption = 'CPUs busy (total):' + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + end + object LabelMEM4: TLabel + Left = 90 + Height = 20 + Top = 410 + Width = 114 + Caption = 'RAM used (total):' + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + end + object Button20: TButton + Left = 90 + Height = 25 + Top = 435 + Width = 124 + Caption = 'more info...' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button20Click + ParentFont = False + TabOrder = 22 + end + object Memo4: TMemo + Left = 397 + Height = 76 + Top = 384 + Width = 421 + Font.Height = -14 + Font.Name = 'Open Sans' + Lines.Strings = ( + 'getm (by klingbei) uses 50 cores (expected end 2023-10-10)' + 'cdo merge (by thomas) uses 2 cores (expected end 2023-10-10)' + ) + OnChange = Memo1Change + ParentFont = False + ReadOnly = True + ScrollBars = ssBoth + TabOrder = 23 + WordWrap = False + end + object Button21: TButton + Left = 826 + Height = 25 + Top = 384 + Width = 165 + Caption = 'start jupyter lab' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button21Click + ParentFont = False + TabOrder = 24 + end + object Button22: TButton + Left = 825 + Height = 25 + Top = 410 + Width = 166 + Caption = 'start console' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button22Click + ParentFont = False + TabOrder = 25 + end + object Button23: TButton + Left = 825 + Height = 25 + Top = 435 + Width = 166 + Caption = 'start console via xpra' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button23Click + ParentFont = False + TabOrder = 26 + end + object Label15: TLabel + Left = 19 + Height = 20 + Top = 358 + Width = 118 + Caption = 'IOW GPU SERVER' + Font.Color = clGreen + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object Shape5: TShape + Left = 13 + Height = 198 + Top = 474 + Width = 986 + Brush.Color = clSilver + Pen.Style = psClear + end + object Label16: TLabel + Left = 19 + Height = 20 + Top = 499 + Width = 47 + Caption = 'phy-10' + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object LabelCPU5: TLabel + Left = 90 + Height = 20 + Top = 499 + Width = 116 + Caption = 'CPUs busy (total):' + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + end + object LabelMEM5: TLabel + Left = 90 + Height = 20 + Top = 525 + Width = 114 + Caption = 'RAM used (total):' + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + end + object Button24: TButton + Left = 90 + Height = 25 + Top = 550 + Width = 124 + Caption = 'more info...' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button24Click + ParentFont = False + TabOrder = 27 + end + object Memo5: TMemo + Left = 397 + Height = 76 + Top = 499 + Width = 421 + Font.Height = -14 + Font.Name = 'Open Sans' + Lines.Strings = ( + 'getm (by klingbei) uses 50 cores (expected end 2023-10-10)' + 'cdo merge (by thomas) uses 2 cores (expected end 2023-10-10)' + ) + OnChange = Memo1Change + ParentFont = False + ReadOnly = True + ScrollBars = ssBoth + TabOrder = 28 + WordWrap = False + end + object Button25: TButton + Left = 826 + Height = 25 + Top = 499 + Width = 165 + Caption = 'start jupyter lab' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button25Click + ParentFont = False + TabOrder = 29 + end + object Button26: TButton + Left = 825 + Height = 25 + Top = 525 + Width = 166 + Caption = 'start console' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button26Click + ParentFont = False + TabOrder = 30 + end + object Button27: TButton + Left = 825 + Height = 25 + Top = 550 + Width = 166 + Caption = 'start console via xpra' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button27Click + ParentFont = False + TabOrder = 31 + end + object Label19: TLabel + Left = 19 + Height = 20 + Top = 474 + Width = 131 + Caption = 'IOW DATA SERVERS' + Font.Color = clGreen + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object Label20: TLabel + Left = 19 + Height = 20 + Top = 589 + Width = 47 + Caption = 'phy-11' + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object LabelCPU6: TLabel + Left = 90 + Height = 20 + Top = 589 + Width = 116 + Caption = 'CPUs busy (total):' + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + end + object LabelMEM6: TLabel + Left = 90 + Height = 20 + Top = 614 + Width = 114 + Caption = 'RAM used (total):' + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + end + object Button28: TButton + Left = 90 + Height = 25 + Top = 640 + Width = 124 + Caption = 'more info...' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button28Click + ParentFont = False + TabOrder = 32 + end + object Memo6: TMemo + Left = 397 + Height = 76 + Top = 589 + Width = 421 + Font.Height = -14 + Font.Name = 'Open Sans' + Lines.Strings = ( + 'getm (by klingbei) uses 50 cores (expected end 2023-10-10)' + 'cdo merge (by thomas) uses 2 cores (expected end 2023-10-10)' + ) + OnChange = Memo1Change + ParentFont = False + ReadOnly = True + ScrollBars = ssBoth + TabOrder = 33 + WordWrap = False + end + object Button29: TButton + Left = 826 + Height = 25 + Top = 589 + Width = 165 + Caption = 'start jupyter lab' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button29Click + ParentFont = False + TabOrder = 34 + end + object Button30: TButton + Left = 825 + Height = 25 + Top = 614 + Width = 166 + Caption = 'start console' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button30Click + ParentFont = False + TabOrder = 35 + end + object Button31: TButton + Left = 825 + Height = 25 + Top = 640 + Width = 166 + Caption = 'start console via xpra' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button31Click + ParentFont = False + TabOrder = 36 + end + object Shape7: TShape + Left = 13 + Height = 96 + Top = 678 + Width = 859 + Brush.Color = clSilver + Pen.Style = psClear + end + object Label23: TLabel + Left = 19 + Height = 20 + Top = 678 + Width = 164 + Caption = 'EXTERNAL RESSOURCES' + Font.Color = clGreen + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object Label24: TLabel + Left = 21 + Height = 20 + Top = 698 + Width = 205 + Caption = 'haumea cluster (Uni Rostock)' + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object Button32: TButton + Left = 19 + Height = 25 + Top = 717 + Width = 109 + Caption = 'get account...' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button32Click + ParentFont = False + TabOrder = 37 + end + object Button33: TButton + Left = 135 + Height = 25 + Top = 717 + Width = 165 + Caption = 'start jupyter lab' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button33Click + ParentFont = False + TabOrder = 38 + end + object Button34: TButton + Left = 134 + Height = 25 + Top = 742 + Width = 166 + Caption = 'start console' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button34Click + ParentFont = False + TabOrder = 39 + end + object Label25: TLabel + Left = 365 + Height = 20 + Top = 698 + Width = 149 + Caption = 'NHR supercomputers' + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object Button35: TButton + Left = 365 + Height = 25 + Top = 717 + Width = 115 + Caption = 'get account...' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button35Click + ParentFont = False + TabOrder = 40 + end + object Button36: TButton + Left = 481 + Height = 25 + Top = 717 + Width = 178 + Caption = 'start jupyter lab (berlin)' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button36Click + ParentFont = False + TabOrder = 41 + end + object Button37: TButton + Left = 481 + Height = 25 + Top = 742 + Width = 178 + Caption = 'start console (berlin)' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button37Click + ParentFont = False + TabOrder = 42 + end + object Button38: TButton + Left = 666 + Height = 25 + Top = 717 + Width = 192 + Caption = 'start jupyter lab (göttingen)' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button38Click + ParentFont = False + TabOrder = 43 + end + object Button39: TButton + Left = 666 + Height = 25 + Top = 742 + Width = 192 + Caption = 'start console (göttingen)' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button39Click + ParentFont = False + TabOrder = 44 + end + object Label26: TLabel + Left = 398 + Height = 20 + Top = 69 + Width = 101 + Caption = 'registered jobs' + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + end + object Button40: TButton + Left = 506 + Height = 18 + Top = 69 + Width = 109 + Caption = 'refresh' + Font.Height = -14 + Font.Name = 'Open Sans' + OnClick = Button40Click + ParentFont = False + TabOrder = 45 + end + object Shape8: TShape + Left = 880 + Height = 96 + Top = 678 + Width = 119 + Brush.Color = clSilver + Pen.Style = psClear + end + object Label27: TLabel + Left = 888 + Height = 20 + Top = 678 + Width = 52 + Caption = 'STATUS' + Font.Color = clGreen + Font.Height = -14 + Font.Name = 'Open Sans' + Font.Style = [fsBold] + ParentFont = False + end + object LabelStatus: TLabel + Left = 888 + Height = 67 + Top = 701 + Width = 100 + AutoSize = False + Font.Height = -14 + Font.Name = 'Open Sans' + ParentFont = False + WordWrap = True + end + object Timer1: TTimer + Interval = 120000 + OnTimer = Timer1Timer + Left = 257 + Top = 94 + end +end diff --git a/unit1.pas b/unit1.pas new file mode 100644 index 0000000..a32cf2a --- /dev/null +++ b/unit1.pas @@ -0,0 +1,1114 @@ +unit Unit1; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, Process, lclintf +{$IFDEF WINDOWS} + ,ShellApi +{$ENDIF} + ; + +type + + { TForm1 } + + TForm1 = class(TForm) + Button1: TButton; + Button10: TButton; + Button11: TButton; + Button12: TButton; + Button13: TButton; + Button14: TButton; + Button15: TButton; + Button16: TButton; + Button17: TButton; + Button18: TButton; + Button19: TButton; + Button2: TButton; + Button20: TButton; + Button21: TButton; + Button22: TButton; + Button23: TButton; + Button24: TButton; + Button25: TButton; + Button26: TButton; + Button27: TButton; + Button28: TButton; + Button29: TButton; + Button3: TButton; + Button30: TButton; + Button31: TButton; + Button32: TButton; + Button33: TButton; + Button34: TButton; + Button35: TButton; + Button36: TButton; + Button37: TButton; + Button38: TButton; + Button39: TButton; + Button4: TButton; + Button40: TButton; + Button5: TButton; + Button6: TButton; + Button7: TButton; + Button8: TButton; + Button9: TButton; + Label1: TLabel; + LabelCPU3: TLabel; + LabelMEM3: TLabel; + Label12: TLabel; + LabelCPU4: TLabel; + LabelMEM4: TLabel; + Label15: TLabel; + Label16: TLabel; + LabelCPU5: TLabel; + LabelMEM5: TLabel; + Label19: TLabel; + LabelCPU1: TLabel; + Label20: TLabel; + LabelCPU6: TLabel; + LabelMEM6: TLabel; + Label23: TLabel; + Label24: TLabel; + Label25: TLabel; + Label26: TLabel; + LabelMEM1: TLabel; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + LabelCPU2: TLabel; + LabelMEM2: TLabel; + Label9: TLabel; + LabelStatus: TLabel; + Memo1: TMemo; + Memo2: TMemo; + Memo3: TMemo; + Memo4: TMemo; + Memo5: TMemo; + Memo6: TMemo; + Shape1: TShape; + Shape2: TShape; + Shape3: TShape; + Shape5: TShape; + Shape7: TShape; + Timer1: TTimer; + procedure Button10Click(Sender: TObject); + procedure Button11Click(Sender: TObject); + procedure Button12Click(Sender: TObject); + procedure Button13Click(Sender: TObject); + procedure Button14Click(Sender: TObject); + procedure Button15Click(Sender: TObject); + procedure Button16Click(Sender: TObject); + procedure Button17Click(Sender: TObject); + procedure Button18Click(Sender: TObject); + procedure Button19Click(Sender: TObject); + procedure Button1Click(Sender: TObject); + procedure Button20Click(Sender: TObject); + procedure Button21Click(Sender: TObject); + procedure Button22Click(Sender: TObject); + procedure Button23Click(Sender: TObject); + procedure Button24Click(Sender: TObject); + procedure Button25Click(Sender: TObject); + procedure Button26Click(Sender: TObject); + procedure Button27Click(Sender: TObject); + procedure Button28Click(Sender: TObject); + procedure Button29Click(Sender: TObject); + procedure Button2Click(Sender: TObject); + procedure Button30Click(Sender: TObject); + procedure Button31Click(Sender: TObject); + procedure Button32Click(Sender: TObject); + procedure Button33Click(Sender: TObject); + procedure Button34Click(Sender: TObject); + procedure Button35Click(Sender: TObject); + procedure Button36Click(Sender: TObject); + procedure Button37Click(Sender: TObject); + procedure Button38Click(Sender: TObject); + procedure Button39Click(Sender: TObject); + procedure Button3Click(Sender: TObject); + procedure Button40Click(Sender: TObject); + procedure Button4Click(Sender: TObject); + procedure Button5Click(Sender: TObject); + procedure Button6Click(Sender: TObject); + procedure Button7Click(Sender: TObject); + procedure Button8Click(Sender: TObject); + procedure Button9Click(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure Label6Click(Sender: TObject); + procedure Memo1Change(Sender: TObject); + procedure Timer1Timer(Sender: TObject); + private + + public + + end; + +var + Form1: TForm1; + haumea_unlocked, hlrn_unlocked: Boolean; + favouriteTerminalStart, favouriteTerminalEnd: String; + +implementation + +uses Unit2; + +{$R *.lfm} + +procedure OpenNmonUrl(hostname: String); +begin + OpenUrl('http://phywiki.io-warnemuende.de/local_htmls/nmon/nmon_stat_'+hostname+'.html') +end; + +function funIstVerzeichnisLeer(strVerzeichnis: string): boolean; +// check if directory empty +var + srDatensatz: TSearchRec; + intI: integer; +begin + Result := False; + + FindFirst(IncludeTrailingPathDelimiter(strVerzeichnis) + '*', faAnyFile, srDatensatz); + + for intI := 1 to 2 do + if (srDatensatz.Name = '.') or (srDatensatz.Name = '..') then + Result := FindNext(srDatensatz) <> 0; + + FindClose(srDatensatz); +end; + +procedure ShowUsageInfo(var sl: TStringList; var LabelCPU: TLabel; var LabelMEM: TLabel; var Memo: TMemo); +begin + LabelCPU.Caption := 'CPUs used (total): '+trim(sl[0])+' ('+trim(sl[1])+')'; + sl.Delete(0); sl.Delete(0); + LabelMEM.Caption := 'RAM used (total): '+ + IntToStr(round(StrToInt(trim(sl[0]))/1024/1024))+' GB ('+ + IntToStr(round(StrToInt(trim(sl[1]))/1024/1024))+' GB)'; + sl.Delete(0); sl.Delete(0); + Memo.Lines.Clear; + while (sl.count>1) and (sl[0]<>'*****') do + begin + Memo.Lines.Add(sl[0]); + sl.Delete(0); + end; + sl.Delete(0); + Memo.SelStart := 0; + Memo.SelLength := 0; +end; + +function SpaceItem(var s: String): String; +//returns the text before the first space and removes this part from the input string +begin + s:=trim(s); + if pos(' ',s)>0 then + begin + result:=copy(s,1,pos(' ',s)-1); + s:=trim(copy(s,pos(' ',s)+1,length(s))); + end + else + begin + result:=s; + s:=''; + end; +end; + +function MyRunProcess(command: String; hidden: Boolean; wait: Boolean; var process: TProcess): TStringList; +var + mycommand: String; + AProcess: TProcess; + AStringList: TStringList; + si: String; +begin + AProcess := TProcess.Create(nil); + //split into command and arguments + mycommand:=command; + AProcess.Executable := SpaceItem(mycommand); + while mycommand<>'' do + AProcess.Parameters.Add(spaceItem(myCommand)); + if wait then + AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes] + else + AProcess.Options := AProcess.Options + [poUsePipes]; + if hidden then + AProcess.ShowWindow := swoHide + else + AProcess.Options := AProcess.Options + [poNewConsole]; + AProcess.Execute; + AStringList := TStringList.Create; + if wait then AStringList.LoadFromStream(AProcess.Output); + process := AProcess; + Result := AStringList; +end; + +function MyRunProcess(command: String; hidden: Boolean; wait: Boolean): TStringList; overload; +var + AProcess: TProcess; + AStringList: TStringList; +begin + AStringList:=MyRunProcess(command,hidden,wait,AProcess); + AProcess.Free; + Result := AStringList; +end; + +procedure unlock_haumea; +begin + MyRunProcess('xterm -e ssh-add '+GetUserDir+'/.ssh/id_rsa_unirostock',false,true); + haumea_unlocked:=true; +end; + +procedure unlock_hlrn; +begin + MyRunProcess('xterm -e ssh-add '+GetUserDir+'/.ssh/id_rsa_hlrn',false,true); + hlrn_unlocked:=true; +end; + +procedure ShowErrorDisconnectedIOW; +begin + if MessageDlg('Connection failed', + 'Could not connect to IOW server rdpserv. Please check if you are in the IOW Intranet.'+chr(13)+ + 'Would you like to see instructions how to connect?',mtConfirmation,[mbYes,mbAbort],0,mbAbort)=mrYes then + OpenUrl('https://intranet.io-warnemuende.de/vpn-access-to-the-iow.html'); +end; + +procedure ShowErrorDisconnectedHaumea; +begin + if MessageDlg('Connection failed', + 'Could not connect to haumea1. Please check if your settings in ~/.ssh/config are correct.'+chr(13)+ + 'Would you like to see instructions how to connect?',mtConfirmation,[mbYes,mbAbort],0,mbAbort)=mrYes then + OpenUrl('http://phywiki.io-warnemuende.de/do/view/Server/UniRostockClusterDocu'); +end; + +function PortFromUserid(userid: Integer; where: String='IOW'; what: String='JUPYTER'): Integer; +begin + Result:=0; + if (where='IOW' ) and (what='JUPYTER') then Result:=userid+10000; + if (where='REMOTE') and (what='JUPYTER') then Result:=userid+10000; + if (where='IOW' ) and (what='XPRA') then Result:=userid+20000; + if (where='REMOTE') and (what='XPRA') then Result:=userid+20000; +end; + +procedure StartJupyterlabIOW(hostname: String); +var + sl, sl1: TStringList; + username, command, s: String; + userid, port, ReadSize: Integer; + process: TProcess; + Buffer: array[0..100000] of char; + found, hasGPU: boolean; + portBlocked: Boolean; + F: TextFile; +begin + hasGPU := (hostname='phy-4'); + // Show Form2 to enter details for parallel processing and job registration + Form2.Edit1.Text:=hostname; + Form2.Label2.Visible:=true; + Form2.SpinEdit1.Visible:=true; + Form2.SpinEdit1.Value:=1; + Form2.Label3.Visible := hasGPU; + Form2.Edit2.Visible := hasGPU; + Form2.Edit2.Text := 'no GPUs'; + Form2.Label4.Visible:=true; + Form2.Edit3.Visible:=true; + Form2.Edit3.Text:=''; + Form2.SpinEdit2.Value:=8; + Form2.Label6.Visible:=false; + Form2.ComboBox1.Visible:=false; + Form2.Tag:=0; + Form2.ShowModal; + Application.ProcessMessages; + if Form2.Tag<>1 then exit; + + Form1.LabelStatus.Caption:='connecting to IOW...'; + Form1.LabelStatus.Repaint; + found:=false; // we will try to find the token in the output + // get IOW username and userid + sl:=MyRunProcess('ssh rdpserv whoami ; id -u',true,true); + if sl.count=2 then + begin + username:=trim(sl[0]); + userid:=StrToInt(sl[1]); + port:=PortFromUserid(userid,'IOW'); + // write the jupyterlab script + AssignFile(F,ExtractFilePath(Application.ExeName)+'/jupyterlab_iow.sh'); + rewrite(F); + writeln(F,'source ~/.bashrc'); + writeln(F,'source ~/.bash_profile'); + writeln(F,'module load miniconda3'); + writeln(F,'ncores='+IntToStr(Form2.SpinEdit1.Value)); + if Form2.Edit3.Text<>'' then + begin + writeln(F,'echo $BASHPID > PID'); + if hasGPU then + writeln(F,'echo "$ncores CPU cores and '+Form2.Edit2.Text+'" >> PID') + else + writeln(F,'echo "$ncores CPU cores" >> PID'); + writeln(F,'echo "runs '+IntToStr(Form2.SpinEdit2.Value)+' hours" >> PID'); + writeln(F,'echo "'+Form2.Edit3.Text+'" >> PID'); + writeln(F,'add_to_list < PID'); + end; + writeln(F,'export OMP_NUM_THREADS=$ncores'); + writeln(F,'export OPENBLAS_NUM_THREADS=$ncores'); + writeln(F,'export MKL_NUM_THREADS=$ncores'); + writeln(F,'export VECLIB_MAXIMUM_THREADS=$ncores'); + writeln(F,'export NUMEXPR_NUM_THREADS=$ncores'); + writeln(F,'jupyter lab'); + closefile(F); + Form1.LabelStatus.Caption:='transferring job script...'; + Form1.LabelStatus.Repaint; + // copy the jupyterlab script to IOW + command := 'scp '+ExtractFilePath(application.ExeName)+'/jupyterlab_iow.sh rdpserv:/home/nis/'+username; + MyRunProcess(command,true,true); + // convert to unix line endings and set execute permissions + command := 'ssh rdpserv dos2unix /home/nis/'+username+'/jupyterlab_iow.sh'; + MyRunProcess(command,true,true); + command := 'ssh rdpserv chmod u+x /home/nis/'+username+'/jupyterlab_iow.sh'; + MyRunProcess(command,true,true); + Form1.LabelStatus.Caption:='checking if port is free...'; + Form1.LabelStatus.Repaint; + // check if port is in use + portBlocked:=false; + command := 'ssh rdpserv fuser '+IntToStr(port)+'/tcp'; + sl1:=MyRunProcess(command,true,true); + if sl1.Count>=1 then portBlocked:=true; + sl1.Free; + command := 'ssh rdpserv ssh '+hostname+' fuser '+IntToStr(port)+'/tcp'; + sl1:=MyRunProcess(command,true,true); + if sl1.Count>=1 then portBlocked:=true; + sl1.Free; + if portBlocked then + if MessageDlg('port in use','Port '+IntToStr(port)+' is already in use by another process. Kill that process?',mtConfirmation,[mbYes,mbAbort],0,mbAbort)=mrYes then + begin + command := 'ssh rdpserv fuser -k -n tcp '+IntToStr(port); + MyRunProcess(command,true,true); + command := 'ssh rdpserv ssh '+hostname+' fuser -k -n tcp '+IntToStr(port); + MyRunProcess(command,true,true); + sleep(1000); + end + else + exit; + Form1.LabelStatus.Caption:='running jupyterlab command...'; + Form1.LabelStatus.Repaint; + // prepare the jupyterlab command and run it + command := 'ssh -t rdpserv -L '+IntToStr(port)+':localhost:'+IntToStr(port)+ + ' ssh -t '+hostname+' -L '+IntToStr(port)+':localhost:'+IntToStr(port)+ + ' /bin/bash -c "/home/nis/'+username+'/jupyterlab_iow.sh 2>&1"'; + {$IFDEF LINUX} + AssignFile(F,ExtractFilePath(Application.ExeName)+'/command.sh'); + Rewrite(F); + writeln(F,command); + closefile(F); + MyRunProcess('/bin/bash -e '+ExtractFilePath(Application.ExeName)+'/command.sh',true,false,process); + {$ENDIF} + {$IFDEF WINDOWS} + MyRunProcess(command,true,false,process); + {$ENDIF} + // seek the output for the token + while (process.Running or (process.Output.NumBytesAvailable > 0)) and (not found) do + begin + Form1.LabelStatus.Caption:='waiting for the token...'; + Form1.LabelStatus.Repaint; + if process.Output.NumBytesAvailable > 0 then + begin + // make sure that we don't read more data than we have allocated + // in the buffer + ReadSize := process.Output.NumBytesAvailable; + if ReadSize > SizeOf(Buffer) then + ReadSize := SizeOf(Buffer); + // now read the output into the buffer + process.Output.Read(Buffer[0], ReadSize); + // and if it contains a token, then open a URL in the browser + s:=Buffer; + if pos('?token=',s)>0 then + begin + s:=copy(s,pos('?token=',s)+7,48); + Form1.LabelStatus.Caption:='opening browser...'; + Form1.LabelStatus.Repaint; + OpenUrl('http://127.0.0.1:'+IntToStr(port)+'?token='+s); + found:=true; + end; + end; + end; + end + else + ShowErrorDisconnectedIOW; + Form1.Timer1Timer(Form1); + sl.Free; + Form1.LabelStatus.Caption:=''; +end; + +procedure StartJupyterlabRemote(hostname: String='haumea1'); +var + sl, sl1: TStringList; + username, command, s: String; + i, userid, port, ReadSize: Integer; + process, process1: TProcess; + Buffer: array[0..100000] of char; + found, hasGPU: boolean; + portBlocked: Boolean; + F: TextFile; + remoteBasepath, nodeName: String; +begin + {$IFDEF WINDOWS} + // first we need to start the ssh-agent to enable passwordless login + MyRunProcess('powershell -command "& {&''Start-Service'' ssh-agent}"',true,true); + {$ENDIF} + {$IFDEF Linux} + // we need to unlock a key to allow passwordless login + if (hostname='haumea1') and (haumea_unlocked=false) then unlock_haumea; + if (hostname='blogin') and (hlrn_unlocked=false) then unlock_hlrn; + if (hostname='glogin') and (hlrn_unlocked=false) then unlock_hlrn; + {$ENDIF} + if hostname='haumea1' then remoteBasepath:='/data'; + if hostname='blogin' then remoteBasepath:='/scratch/usr'; + if hostname='glogin' then remoteBasepath:='/scratch/usr'; + // Show Form2 to enter details for parallel processing and job registration + Form2.Edit1.Text:=hostname; + Form2.Label2.Visible:=false; + Form2.SpinEdit1.Visible:=false; + Form2.Label3.Visible := false; + Form2.Edit2.Visible := false; + Form2.Label4.Visible:=false; + Form2.Edit3.Visible:=false; + Form2.SpinEdit2.Value:=8; + Form2.Label6.Visible:=true; + Form2.ComboBox1.Visible:=true; + Form2.ComboBox1.Items.Clear; + if hostname='haumea1' then + begin + Form2.ComboBox1.Items.Add('compute'); + Form2.ComboBox1.Items.Add('requeue'); + end + else if hostname='blogin' then + begin + Form2.ComboBox1.Items.Add('standard96'); + Form2.ComboBox1.Items.Add('standard96:test'); + Form2.ComboBox1.Items.Add('large96'); + Form2.ComboBox1.Items.Add('large96:test'); + Form2.ComboBox1.Items.Add('huge96'); + end + else if hostname='glogin' then + begin + Form2.ComboBox1.Items.Add('medium40'); + Form2.ComboBox1.Items.Add('medium40:test'); + Form2.ComboBox1.Items.Add('large40'); + Form2.ComboBox1.Items.Add('large40:test'); + Form2.ComboBox1.Items.Add('standard96'); + Form2.ComboBox1.Items.Add('standard96:test'); + Form2.ComboBox1.Items.Add('large96'); + Form2.ComboBox1.Items.Add('large96:test'); + Form2.ComboBox1.Items.Add('huge96'); + end; + Form2.ComboBox1.ItemIndex:=0; + Form2.Tag:=0; + Form2.ShowModal; + Application.ProcessMessages; + if Form2.Tag <> 1 then exit; + + Form1.LabelStatus.Caption:='connecting to '+hostname+'...'; + Form1.LabelStatus.Repaint; + found:=false; // we will try to find the token in the output + // get remote location username and userid + sl:=MyRunProcess('ssh '+hostname+' whoami ; id -u',true,true); + if sl.count=2 then + begin + username:=trim(sl[0]); + userid:=StrToInt(sl[1]); + port:=PortFromUserid(userid,'REMOTE'); + // write the jupyterlab script + AssignFile(F,ExtractFilePath(Application.ExeName)+'/jupyterlab_remote.sh'); + rewrite(F); + writeln(F,'#!/bin/bash'); + writeln(F,'#'); + writeln(F,'#SBATCH --job-name=jupyter'); + writeln(F,'#SBATCH --output='+remoteBasepath+'/%u/.jupyter_out.txt'); + writeln(F,'#SBATCH --nodes 1'); + writeln(F,'#SBATCH --ntasks=1'); + writeln(F,'#SBATCH -t '+IntToStr(Form2.SpinEdit2.Value)+':00:00'); + writeln(F,'#SBATCH -p '+Form2.ComboBox1.Items[Form2.ComboBox1.ItemIndex]); + writeln(F,''); + writeln(F,'source ~/.bashrc'); + writeln(F,'PATH=$PATH:$HOME/.local/bin:$HOME/bin'); + writeln(F,''); + writeln(F,'export PATH'); + writeln(F,''); + if hostname='haumea1' then + begin + writeln(F,'export MODULEPATH=$MODULEPATH:/data/iow/iow-modules/DATAFORMATS'); + writeln(F,'export MODULEPATH=$MODULEPATH:/data/iow/iow-modules/VISUALISATION'); + writeln(F,'export MODULEPATH=$MODULEPATH:/data/iow/iow-modules/MPI'); + writeln(F,'export MODULEPATH=$MODULEPATH:/data/iow/iow-modules/NUMERICS'); + writeln(F,'module load miniconda3'); + end + else + writeln(F,'module load anaconda3'); + writeln(F,''); + writeln(F,'export OMP_NUM_THREADS=40'); + writeln(F,'export KMP_AFFINITY=compact,1,0,granularity=fine'); + writeln(F,'export MKLDNN_VERBOSE=1'); + writeln(F,'export MYJUPYTERPORT='+IntToStr(port)); + writeln(F,'export XDG_RUNTIME_DIR="'+remoteBasepath+'/$USER"'); + writeln(F,'hostname > '+remoteBasepath+'/'+username+'/.jupyterlab_hostname.txt'); + writeln(F,'jupyter lab --port $MYJUPYTERPORT --ip 0.0.0.0 --no-browser --notebook-dir="'+remoteBasepath+'/$USER"'); + closefile(F); + Form1.LabelStatus.Caption:='transferring job script...'; + Form1.LabelStatus.Repaint; + // copy the jupyterlab script to IOW + command := 'scp '+ExtractFilePath(application.ExeName)+'/jupyterlab_remote.sh '+hostname+':'+remoteBasepath+'/'+username; + MyRunProcess(command,true,true); + // convert to unix line endings and set execute permissions + command := 'ssh '+hostname+' sed -i ''s/\r//'' '+remoteBasepath+'/'+username+'/jupyterlab_remote.sh'; + MyRunProcess(command,true,true); + command := 'ssh '+hostname+' chmod u+x '+remoteBasepath+'/'+username+'/jupyterlab_remote.sh'; + MyRunProcess(command,true,true); + Form1.LabelStatus.Caption:='checking if port is free...'; + Form1.LabelStatus.Repaint; + // check if port is in use + portBlocked:=false; + command := 'ssh '+hostname+' fuser '+IntToStr(port)+'/tcp'; + sl1:=MyRunProcess(command,true,true); + if sl1.Count>=1 then portBlocked:=true; + sl1.Free; + if portBlocked then + if MessageDlg('port in use','Port '+IntToStr(port)+' is already in use by another process. Kill that process?',mtConfirmation,[mbYes,mbAbort],0,mbAbort)=mrYes then + begin + command := 'ssh '+hostname+' fuser -k -n tcp '+IntToStr(port); + MyRunProcess(command,true,true); + sleep(1000); + end + else + exit; + // delete output files of an old jupyterlab job if exists + Form1.LabelStatus.Caption:='cleaning up old files...'; + Form1.LabelStatus.Repaint; + command := 'ssh -q '+hostname+' "if [ -f '+remoteBasepath+'/'+username+ + '/.jupyter_out.txt ] ; then rm '+remoteBasepath+'/'+username+'/.jupyter_out.txt ; fi"'; + {$IFDEF LINUX} + AssignFile(F,ExtractFilePath(Application.ExeName)+'/command.sh'); + Rewrite(F); + writeln(F,command); + closefile(F); + MyRunProcess('/bin/bash -e '+ExtractFilePath(Application.ExeName)+'/command.sh',true,true); + {$ENDIF} + {$IFDEF WINDOWS} + MyRunProcess(command,true,true); + {$ENDIF} + command := 'ssh -q '+hostname+' "if [ -f '+remoteBasepath+'/'+username+ + '/.jupyterlab_hostname.txt ] ; then rm '+remoteBasepath+'/'+username+'/.jupyterlab_hostname.txt ; fi"'; + {$IFDEF LINUX} + AssignFile(F,ExtractFilePath(Application.ExeName)+'/command.sh'); + Rewrite(F); + writeln(F,command); + closefile(F); + MyRunProcess('/bin/bash -e '+ExtractFilePath(Application.ExeName)+'/command.sh',true,true); + {$ENDIF} + {$IFDEF WINDOWS} + MyRunProcess(command,true,true); + {$ENDIF} + // prepare the command to submit the job and run it + Form1.LabelStatus.Caption:='submitting job...'; + Form1.LabelStatus.Repaint; + command := 'ssh '+hostname+' sbatch '+remoteBasepath+'/'+username+'/jupyterlab_remote.sh'; + MyRunProcess(command,true,true); + // wait until the output file exists + Form1.LabelStatus.Caption:='waiting for job to start...'; + Form1.LabelStatus.Repaint; + found:=false; + while not found do + begin + command:='ssh '+hostname+' ls '+remoteBasepath+'/'+username+'/.jupyter_out.txt'; + sl1:=MyRunProcess(command,true,true); + if sl1.Count>0 then found:=true; + sl1.Free; + sleep(1000); + end; + // then, get the node name + Form1.LabelStatus.Caption:='job is running, checking on which node...'; + Form1.LabelStatus.Repaint; + command:='ssh '+hostname+' cat '+remoteBasepath+'/'+username+'/.jupyterlab_hostname.txt'; + sl1:=MyRunProcess(command,true,true); + while sl1.count<1 do + begin + sleep(500); + sl1.Free; + sl1:=MyRunProcess(command,true,true); + end; + nodeName:=sl1[0]; + // open SSH tunnel for the ports + Form1.LabelStatus.Caption:='opening ssh tunnel...'; + Form1.LabelStatus.Repaint; + command := 'ssh -L '+IntToStr(port)+':localhost:'+IntToStr(port)+' '+hostname+ + ' ssh -L '+IntToStr(port)+':localhost:'+IntToStr(port)+ + ' -N '+nodeName+' & 2>/dev/null'; + {$IFDEF LINUX} + AssignFile(F,ExtractFilePath(Application.ExeName)+'/command.sh'); + Rewrite(F); + writeln(F,command); + closefile(F); + MyRunProcess('/bin/bash -e '+ExtractFilePath(Application.ExeName)+'/command.sh',true,false,process); + {$ENDIF} + {$IFDEF WINDOWS} + MyRunProcess(command,true,false,process); + {$ENDIF} + // grep until we find the token + Form1.LabelStatus.Caption:='waiting for token...'; + Form1.LabelStatus.Repaint; + command := 'ssh '+hostname+' grep "token" '+remoteBasepath+'/'+username+'/.jupyter_out.txt 2>/dev/null'; + found:=false; + while not found do + begin + sl1 := MyRunProcess(command,true,true); + for i:=0 to sl1.Count-1 do + if pos('?token=',sl1[i])>0 then + begin + s:=copy(sl1[i],pos('?token=',sl1[i])+7,48); + if not found then + begin + Form1.LabelStatus.Caption:='opening browser...'; + Form1.LabelStatus.Repaint; + OpenUrl('http://127.0.0.1:'+IntToStr(port)+'?token='+s); + end; + found:=true; + end; + sleep(1000); + end; + end + else + if hostname='haumea1' then ShowErrorDisconnectedHaumea; + sl.Free; + Form1.LabelStatus.Caption:=''; +end; + +procedure StartConsoleIOW(hostname: String); +var + sl: TStringList; + F: TextFile; +begin + // get IOW username and userid + sl:=MyRunProcess('ssh rdpserv whoami ; id -u',true,true); + if sl.count=2 then + begin + // run command in console + {$IFDEF Linux} + AssignFile(F,ExtractFilePath(Application.ExeName)+'/command.sh'); + Rewrite(F); + writeln(F,'ssh -t -X rdpserv ssh -X '+hostname); + closefile(F); + MyRunProcess(FavouriteTerminalStart+' '+ExtractFilePath(application.ExeName)+'/command.sh'+FavouriteTerminalEnd,false,false); + {$ENDIF} + {$IFDEF WINDOWS} + ShellExecute(0,nil, PChar('cmd'),PChar('/C ssh -t rdpserv ssh '+hostname),nil,1); + {$ENDIF} + end + else + ShowErrorDisconnectedIOW; + sl.Free; +end; + +procedure StartConsoleRemote(hostname: String='haumea1'); +var + sl: TStringList; + F: TextFile; +begin + // first we need to start the ssh-agent to enable passwordless login + {$IFDEF WINDOWS} + MyRunProcess('powershell -command "& {&''Start-Service'' ssh-agent}"',true,true); + {$ENDIF} + {$IFDEF Linux} + // we need to unlock a key to allow passwordless login + if (hostname='haumea1') and (haumea_unlocked=false) then unlock_haumea; + if (hostname='blogin') and (hlrn_unlocked=false) then unlock_hlrn; + if (hostname='glogin') and (hlrn_unlocked=false) then unlock_hlrn; + {$ENDIF} + // get haumea username and userid + sl:=MyRunProcess('ssh '+hostname+' whoami ; id -u',true,true); + if sl.count=2 then + begin + // run command in console + {$IFDEF Linux} + AssignFile(F,ExtractFilePath(Application.ExeName)+'/command.sh'); + Rewrite(F); + writeln(F,'ssh -X '+hostname); + closefile(F); + MyRunProcess(FavouriteTerminalStart+' '+ExtractFilePath(application.ExeName)+'/command.sh'+FavouriteTerminalEnd,false,false); + {$ENDIF} + {$IFDEF WINDOWS} + ShellExecute(0,nil, PChar('cmd'),PChar('/C ssh '+hostname),nil,1); + {$ENDIF} + end + else + if hostname='haumea1' then ShowErrorDisconnectedHaumea; + sl.Free; +end; + +procedure StartXpraIOW(hostname: String); +var + sl, sl1: TStringList; + username, command, s: String; + userid, port, ReadSize: Integer; + process: TProcess; + Buffer: array[0..100000] of char; + found: boolean; + portBlocked: Boolean; +begin + found:=false; // we will seek the output to find out when the server is running + // get IOW username and userid + Form1.LabelStatus.Caption:='connecting to IOW...'; + Form1.LabelStatus.Repaint; + sl:=MyRunProcess('ssh rdpserv whoami ; id -u',true,true); + if sl.count=2 then + begin + username:=trim(sl[0]); + userid:=StrToInt(sl[1]); + port:=PortFromUserid(userid,'IOW','XPRA'); + Form1.LabelStatus.Caption:='sending xpra script...'; + Form1.LabelStatus.Repaint; + // copy the xpra script to IOW + command := 'scp '+ExtractFilePath(application.ExeName)+'/xpra_iow.sh rdpserv:/home/nis/'+username; + MyRunProcess(command,true,true); + // set execute permissions + command := 'ssh rdpserv chmod u+x /home/nis/'+username+'/xpra_iow.sh'; + MyRunProcess(command,true,true); + // check if port is in use + Form1.LabelStatus.Caption:='checking if port is free...'; + Form1.LabelStatus.Repaint; + portBlocked:=false; + command := 'ssh rdpserv fuser '+IntToStr(port)+'/tcp'; + sl1:=MyRunProcess(command,true,true); + if sl1.Count>=1 then portBlocked:=true; + sl1.Free; + command := 'ssh rdpserv ssh '+hostname+' fuser '+IntToStr(port)+'/tcp'; + sl1:=MyRunProcess(command,true,true); + if sl1.Count>=1 then portBlocked:=true; + sl1.Free; + if portBlocked then + if MessageDlg('port in use','Port '+IntToStr(port)+' is already in use by another process. Kill that process?',mtConfirmation,[mbYes,mbAbort],0,mbAbort)=mrYes then + begin + command := 'ssh rdpserv fuser -k -n tcp '+IntToStr(port); + MyRunProcess(command,true,true); + command := 'ssh rdpserv ssh '+hostname+' fuser -k -n tcp '+IntToStr(port); + MyRunProcess(command,true,true); + sleep(1000); + end + else + exit; + // prepare the xpra command and run it + Form1.LabelStatus.Caption:='starting xpra...'; + Form1.LabelStatus.Repaint; + command := 'ssh -t -X rdpserv -L '+IntToStr(port)+':localhost:'+IntToStr(port)+ + ' ssh -t -X '+hostname+' -L '+IntToStr(port)+':localhost:'+IntToStr(port)+ + ' /bin/bash -c /home/nis/'+username+'/xpra_iow.sh 2>&1'; + MyRunProcess(command,true,false,process); + // seek the output for the term "running" + Form1.LabelStatus.Caption:='waiting until xpra has started...'; + Form1.LabelStatus.Repaint; + while (process.Running or (process.Output.NumBytesAvailable > 0)) and (not found) do + begin + if process.Output.NumBytesAvailable > 0 then + begin + // make sure that we don't read more data than we have allocated + // in the buffer + ReadSize := process.Output.NumBytesAvailable; + if ReadSize > SizeOf(Buffer) then + ReadSize := SizeOf(Buffer); + // now read the output into the buffer + process.Output.Read(Buffer[0], ReadSize); + // and if it contains a token, then open a URL in the browser + s:=Buffer; + if pos('running',s)>0 then + begin + sleep(3000); //wait until it really starts + Form1.LabelStatus.Caption:='opening browser...'; + Form1.LabelStatus.Repaint; + OpenUrl('http://127.0.0.1:'+IntToStr(port)); + found:=true; + end; + end; + end; + end + else + ShowErrorDisconnectedIOW; + sl.Free; + Form1.LabelStatus.Caption:=''; +end; + +{ TForm1 } + +procedure TForm1.Button10Click(Sender: TObject); +{$IFDEF Linux} +var + found: Boolean; +{$ENDIF} +begin + {$IFDEF Linux} + found:=false; + if DirectoryExists('/public') then + if funIstVerzeichnisLeer('/public')=false then + begin + MyRunProcess('gdk-open /public',false,false); + end; + if not found then + ShowMessage('"/public" directory is not mounted on your machine. Please add it to the /etc/fstab or open a console on one of the phy servers and run "cd /public"') + + {$ENDIF} + {$IFDEF WINDOWS} + MyRunProcess('explorer \\netapp1.io-warnemuende.de\public',false,false); + {$ENDIF} +end; + +procedure TForm1.Button11Click(Sender: TObject); +begin + OpenUrl('https://git.io-warnemuende.de/'); +end; + +procedure TForm1.Button12Click(Sender: TObject); +begin + OpenNmonUrl('PHY-2'); +end; + +procedure TForm1.Button13Click(Sender: TObject); +begin + StartJupyterlabIOW('phy-2'); +end; + +procedure TForm1.Button14Click(Sender: TObject); +begin + StartConsoleIOW('phy-2'); +end; + +procedure TForm1.Button15Click(Sender: TObject); +begin + StartXpraIOW('phy-2'); +end; + +procedure TForm1.Button16Click(Sender: TObject); +begin + OpenNmonUrl('PHY-3'); +end; + +procedure TForm1.Button17Click(Sender: TObject); +begin + StartJupyterlabIOW('phy-3'); +end; + +procedure TForm1.Button18Click(Sender: TObject); +begin + StartConsoleIOW('phy-3'); +end; + +procedure TForm1.Button19Click(Sender: TObject); +begin + StartXpraIOW('phy-3'); +end; + +procedure TForm1.Button1Click(Sender: TObject); +begin + MyRunProcess(FavouriteTerminalStart+' '+ExtractFilePath(application.ExeName)+'/command.sh'+FavouriteTerminalEnd,false,false); + OpenUrl('http://phywiki.io-warnemuende.de/pub/Server/IntroductionNewColleagues/new_colleagues_introduction_it.pdf'); +end; + +procedure TForm1.Button20Click(Sender: TObject); +begin + OpenNmonUrl('PHY-4'); +end; + +procedure TForm1.Button21Click(Sender: TObject); +begin + StartJupyterlabIOW('phy-4'); +end; + +procedure TForm1.Button22Click(Sender: TObject); +begin + StartConsoleIOW('phy-4'); +end; + +procedure TForm1.Button23Click(Sender: TObject); +begin + StartXpraIOW('phy-4'); +end; + +procedure TForm1.Button24Click(Sender: TObject); +begin + OpenNmonUrl('PHY-10'); +end; + +procedure TForm1.Button25Click(Sender: TObject); +begin + StartJupyterlabIOW('phy-10'); +end; + +procedure TForm1.Button26Click(Sender: TObject); +begin + StartConsoleIOW('phy-10'); +end; + +procedure TForm1.Button27Click(Sender: TObject); +begin + StartXpraIOW('phy-10'); +end; + +procedure TForm1.Button28Click(Sender: TObject); +begin + OpenNmonUrl('PHY-11'); +end; + +procedure TForm1.Button29Click(Sender: TObject); +begin + StartJupyterlabIOW('phy-11'); +end; + +procedure TForm1.Button2Click(Sender: TObject); +begin + OpenNmonUrl('phy-1'); +end; + +procedure TForm1.Button30Click(Sender: TObject); +begin + StartConsoleIOW('phy-11'); +end; + +procedure TForm1.Button31Click(Sender: TObject); +begin + StartXpraIOW('phy-11'); +end; + +procedure TForm1.Button32Click(Sender: TObject); +begin + OpenUrl('http://phywiki.io-warnemuende.de/do/view/Server/UniRostockClusterDocumentationList'); +end; + +procedure TForm1.Button33Click(Sender: TObject); +begin + StartJupyterlabRemote('haumea1'); +end; + +procedure TForm1.Button34Click(Sender: TObject); +begin + StartConsoleRemote('haumea1'); +end; + +procedure TForm1.Button35Click(Sender: TObject); +begin + OpenUrl('http://phywiki.io-warnemuende.de/do/view/Server/HLRNApplicationProcedure'); +end; + +procedure TForm1.Button36Click(Sender: TObject); +begin + StartJupyterlabRemote('blogin'); +end; + +procedure TForm1.Button37Click(Sender: TObject); +begin + StartConsoleRemote('blogin'); +end; + +procedure TForm1.Button38Click(Sender: TObject); +begin + StartJupyterlabRemote('glogin'); +end; + +procedure TForm1.Button39Click(Sender: TObject); +begin + StartConsoleRemote('glogin'); +end; + +procedure TForm1.Button3Click(Sender: TObject); +begin + StartJupyterlabIOW('phy-1'); +end; + +procedure TForm1.Button40Click(Sender: TObject); +begin + timer1timer(self); +end; + +procedure TForm1.Button4Click(Sender: TObject); +begin + StartConsoleIOW('phy-1'); +end; + +procedure TForm1.Button5Click(Sender: TObject); +begin + StartXpraIOW('phy-1'); +end; + +procedure TForm1.Button6Click(Sender: TObject); +begin + OpenUrl('http://phywiki.io-warnemuende.de/'); +end; + +procedure TForm1.Button7Click(Sender: TObject); +begin + OpenUrl('https://email.io-warnemuende.de/'); +end; + +procedure TForm1.Button8Click(Sender: TObject); +begin + OpenUrl('https://chat.io-warnemuende.de/'); +end; + +procedure TForm1.Button9Click(Sender: TObject); +begin + OpenURL('https://owncloud.io-warnemuende.de') +end; + +procedure TForm1.FormCreate(Sender: TObject); +var + F: TextFile; +begin + haumea_unlocked:=false; + hlrn_unlocked:=false; + favouriteTerminalStart:='xterm -e '; + favouriteTerminalEnd:=''; + if FileExists(ExtractFilePath(Application.ExeName)+'/favourite_terminal.txt') then + begin + AssignFile(F,ExtractFilePath(Application.ExeName)+'/favourite_terminal.txt'); + Reset(F); + if not EOF(F) then + readln(F,favouriteTerminalStart); + readln(F,favouriteTerminalEnd); + closefile(F); + end; +end; + +procedure TForm1.FormShow(Sender: TObject); +begin + Timer1timer(self); +end; + +procedure TForm1.Label6Click(Sender: TObject); +begin + +end; + +procedure TForm1.Memo1Change(Sender: TObject); +begin + +end; + +procedure TForm1.Timer1Timer(Sender: TObject); +var + AStringList: TStringList; +begin + AStringList:=MyRunProcess('ssh rdpserv /sw/sys/scripts/combine_machine_usage',true,true); + if AStringList.Count>0 then + begin + // fill the information in into the GUI + ShowUsageInfo(AStringList,LabelCPU1, LabelMEM1, Memo1); + ShowUsageInfo(AStringList,LabelCPU2, LabelMEM2, Memo2); + ShowUsageInfo(AStringList,LabelCPU3, LabelMEM3, Memo3); + ShowUsageInfo(AStringList,LabelCPU4, LabelMEM4, Memo4); + ShowUsageInfo(AStringList,LabelCPU5, LabelMEM5, Memo5); + ShowUsageInfo(AStringList,LabelCPU6, LabelMEM6, Memo6); + end + else + begin + ShowErrorDisconnectedIOW; + Halt; + end; + AStringList.Free; +end; + +end. + diff --git a/unit2.lfm b/unit2.lfm new file mode 100644 index 0000000..d64be5a --- /dev/null +++ b/unit2.lfm @@ -0,0 +1,143 @@ +object Form2: TForm2 + Left = 578 + Height = 344 + Top = 344 + Width = 456 + Caption = 'phyportal - start jupyter lab' + ClientHeight = 344 + ClientWidth = 456 + Color = clNavy + Font.Height = -14 + Font.Name = 'Open Sans' + LCLVersion = '2.2.0.4' + object Shape1: TShape + Left = 6 + Height = 326 + Top = 6 + Width = 442 + Brush.Color = clSilver + Pen.Style = psClear + end + object Label1: TLabel + Left = 18 + Height = 20 + Top = 19 + Width = 132 + Caption = 'start jupyter lab on:' + end + object Edit1: TEdit + Left = 83 + Height = 30 + Top = 38 + Width = 311 + Color = clSilver + Enabled = False + TabOrder = 0 + Text = 'Edit1' + end + object Label2: TLabel + Left = 18 + Height = 20 + Top = 77 + Width = 225 + Caption = 'CPU cores for parallel computing:' + end + object SpinEdit1: TSpinEdit + Left = 83 + Height = 30 + Top = 96 + Width = 122 + MaxValue = 128 + MinValue = 1 + TabOrder = 1 + Value = 1 + end + object Label3: TLabel + Left = 237 + Height = 20 + Top = 77 + Width = 168 + Caption = 'Which GPUs will you use:' + end + object Edit2: TEdit + Left = 262 + Height = 30 + Top = 96 + Width = 134 + TabOrder = 2 + Text = 'no GPUs' + end + object Label4: TLabel + Left = 16 + Height = 20 + Top = 142 + Width = 359 + Caption = 'What will you do (leave empty for no job registration):' + end + object Edit3: TEdit + Left = 83 + Height = 30 + Top = 160 + Width = 313 + TabOrder = 3 + Text = 'Edit3' + end + object Label5: TLabel + Left = 17 + Height = 20 + Top = 198 + Width = 119 + Caption = 'How many hours?' + end + object BitBtn1: TBitBtn + Left = 82 + Height = 30 + Top = 275 + Width = 146 + Default = True + DefaultCaption = True + Kind = bkOK + ModalResult = 1 + OnClick = BitBtn1Click + TabOrder = 4 + end + object BitBtn2: TBitBtn + Left = 262 + Height = 30 + Top = 274 + Width = 134 + Cancel = True + DefaultCaption = True + Kind = bkCancel + ModalResult = 2 + OnClick = BitBtn2Click + TabOrder = 5 + end + object SpinEdit2: TSpinEdit + Left = 84 + Height = 30 + Top = 218 + Width = 121 + MaxValue = 1000 + MinValue = 1 + TabOrder = 6 + Value = 1 + end + object Label6: TLabel + Left = 233 + Height = 20 + Top = 198 + Width = 49 + Caption = 'Queue:' + end + object ComboBox1: TComboBox + Left = 243 + Height = 32 + Top = 218 + Width = 150 + ItemHeight = 0 + OnSelect = ComboBox1Select + Style = csDropDownList + TabOrder = 7 + end +end diff --git a/unit2.pas b/unit2.pas new file mode 100644 index 0000000..26142ca --- /dev/null +++ b/unit2.pas @@ -0,0 +1,69 @@ +unit Unit2; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, + Spin, Buttons; + +type + + { TForm2 } + + TForm2 = class(TForm) + BitBtn1: TBitBtn; + BitBtn2: TBitBtn; + ComboBox1: TComboBox; + Edit1: TEdit; + Edit2: TEdit; + Edit3: TEdit; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + Shape1: TShape; + SpinEdit1: TSpinEdit; + SpinEdit2: TSpinEdit; + procedure BitBtn1Click(Sender: TObject); + procedure BitBtn2Click(Sender: TObject); + procedure ComboBox1Select(Sender: TObject); + private + + public + + end; + +var + Form2: TForm2; + +implementation + +{$R *.lfm} + +{ TForm2 } + +procedure TForm2.ComboBox1Select(Sender: TObject); +begin + // in a queue called "test", jobs can run no longer than 1 hour by default + if ComboBox1.Items.Count>0 then + if pos('test',ComboBox1.Items[ComboBox1.ItemIndex])>0 then + SpinEdit2.Value:=1; +end; + +procedure TForm2.BitBtn1Click(Sender: TObject); +begin + Form2.Tag:=1; + Form2.Close; +end; + +procedure TForm2.BitBtn2Click(Sender: TObject); +begin + Form2.Close; +end; + +end. +