PureBasic Forum
http://forums.purebasic.com/english/

hybrid web application : HTML5 + PB
http://forums.purebasic.com/english/viewtopic.php?f=12&t=64672
Page 1 of 2

Author:  eddy [ Sat Jan 23, 2016 5:59 pm ]
Post subject:  hybrid web application : HTML5 + PB

Hi,
In this program, my purpose is to create hybrib web app (like http://nwjs.io/ or http://electron.atom.io/)

  • local server coded in Purebasic
  • frontend UI coded in HTML5 / Jquery / UI Kit
  • communication between webgadget and purebasic app
  • Resize window event
  • Drag window event
  • Supported OS: win7/8/10, mac, linux

TODO:
  • Add PostEvent data

Image

Code:


; **********************************
; JQuery events: https://api.jquery.com/category/events/
; UI KIT (visual framework): http://getuikit.com/index.html
; **********************************
EnableExplicit
Runtime Enumeration
   #server : #file : #xml : #dialog : #win : #web
   #border1 : #border2 : #border3 : #border4 : #border5 : #border6 : #border7 : #border8 : #toolbar
   #maxmimize : #minimize : #close
   #connect
EndEnumeration
Enumeration #PB_Event_FirstCustomValue + 678910101
   #PB_Event_WebGadget
EndEnumeration
Procedure captureWindow(border=-1, mouseHitX=0, mouseHitY=0, nodeWidth=0, nodeHeight=0)
   Static win, x, y, x2, y2, w, h, offsetX, offsetY, captureWindow
   Protected refreshingDelay=20 ;laggy refreshing
   Select border
      Case -1
         If captureWindow
            x=#PB_Ignore
            y=#PB_Ignore
            w=#PB_Ignore
            h=#PB_Ignore
            If captureWindow=#toolbar
               x=DesktopMouseX() + offsetX
               y=DesktopMouseY() + offsetY
            EndIf           
            If captureWindow=#border1 Or captureWindow=#border4 Or captureWindow=#border6
               x=DesktopMouseX() + offsetX
               w=(x2-x)               
            EndIf
            If captureWindow=#border1 Or captureWindow=#border2 Or captureWindow=#border3
               y=DesktopMouseY() + offsetY
               h=(y2-y)
            EndIf
            If captureWindow=#border3 Or captureWindow=#border5 Or captureWindow=#border8
               w=(DesktopMouseX()-WindowX(win)) + offsetX
            EndIf
            If captureWindow=#border6 Or captureWindow=#border7 Or captureWindow=#border8
               h=(DesktopMouseY()-WindowY(win)) + offsetY
            EndIf
            ResizeWindow(win, x, y, w, h)
            refreshingDelay=1 ;smooth refreshing
         EndIf
      Case 0
         captureWindow=0
         Debug "drag end"
      Default
         If captureWindow=0 And border>=#border1 And border<=#toolbar
            Debug "drag start"
            captureWindow=border
            win=EventWindow()
            If captureWindow=#toolbar
               offsetX=-mouseHitX
               offsetY=-mouseHitY
            EndIf           
            If captureWindow=#border1 Or captureWindow=#border4 Or captureWindow=#border6
               x2=WindowX(win) + WindowWidth(win)
               offsetX=-mouseHitX
            EndIf
            If captureWindow=#border1 Or captureWindow=#border2 Or captureWindow=#border3
               y2=WindowY(win) + WindowHeight(win)
               offsetY=-mouseHitY
            EndIf           
            If captureWindow=#border3 Or captureWindow=#border5 Or captureWindow=#border8
               offsetX=nodeWidth-mouseHitX
            EndIf
            If captureWindow=#border6 Or captureWindow=#border7 Or captureWindow=#border8
               offsetY=nodeHeight-mouseHitY
            EndIf
         EndIf
   EndSelect
   ProcedureReturn refreshingDelay
EndProcedure
CreateRegularExpression(0, "eventType=(?<eventType>[^&]+)" +
                           "(&eventWhich=(?<eventWhich>[^&]+))+" +
                           "(&eventGadget=(?<eventGadget>[^&]+))?" +
                           "(&nodeName=(?<nodeName>[^&]+))?" +
                           "(&nodeWidth=(?<nodeWidth>[^&]+))?" +
                           "(&nodeHeight=(?<nodeHeight>[^&]+))?" +
                           "(&mouseHitX=(?<mouseHitX>[^&]+))?" +
                           "(&mouseHitY=(?<mouseHitY>[^&]+))?")
Procedure WebServer(port)
   InitNetwork()
   Protected *Buffer=AllocateMemory(1000)
   CreateNetworkServer(#server, port, #PB_Network_TCP, "127.0.0.1")
   Repeat
      Select NetworkServerEvent()
         Case #PB_NetworkEvent_Data
            Protected Client=EventClient()           
            Protected Size=ReceiveNetworkData(Client, *Buffer, MemorySize(*Buffer))
            ;Debug "msg from " + Client
            If Size
               Protected Answer$="Status: 200 OK" + #CRLF$ +
                                 "Content-type: text/plain" + #CRLF$ + #CRLF$ +
                                 "** Purebasic Response **" + #CRLF$
               SendNetworkString(Client, Answer$)
               
               Protected Buffer$=PeekS(*Buffer, Size, #PB_UTF8)
               ;Debug Buffer$
               If ExamineRegularExpression(0, Buffer$)
                  If NextRegularExpressionMatch(0)
                     Protected eventType=#PB_Event_None
                     Protected eventType$=RegularExpressionNamedGroup(0, "eventType")
                     Protected eventWhich$=RegularExpressionNamedGroup(0, "eventWhich")
                     Protected eventGadget=-1
                     Protected eventGadget$=URLDecoder(RegularExpressionNamedGroup(0, "eventGadget"))
                     Protected nodeName$=RegularExpressionNamedGroup(0, "nodeName")
                     Protected nodeWidth=Val(RegularExpressionNamedGroup(0, "nodeWidth"))
                     Protected nodeHeight=Val(RegularExpressionNamedGroup(0, "nodeHeight"))
                     Protected mouseHitX=Val(RegularExpressionNamedGroup(0, "mouseHitX"))
                     Protected mouseHitY=Val(RegularExpressionNamedGroup(0, "mouseHitY"))
                     If IsRuntime(eventGadget$) : eventGadget=GetRuntimeInteger(eventGadget$) : EndIf
                     Debug Hex(Client) + ": " + eventType$ + " " + nodeName$ + " " + eventGadget$ + " " + mouseHitX + " " + mouseHitY + " " + nodeWidth + " " + nodeHeight + " " + ""
                     Select LCase(eventType$)
                        Case "click", "contextmenu" :
                           If eventWhich$="1" : eventType=#PB_EventType_LeftClick : Else : eventType=#PB_EventType_RightClick : EndIf                           
                        Case "dblclick" :
                           If eventWhich$="1" : eventType=#PB_EventType_LeftDoubleClick : Else : eventType=#PB_EventType_RightDoubleClick : EndIf
                        Case "mousedown"
                           Select eventWhich$
                              Case "1" : eventType=#PB_EventType_LeftButtonDown
                                 captureWindow(eventGadget, mouseHitX, mouseHitY, nodeWidth, nodeHeight)
                              Case "2" : eventType=#PB_EventType_MiddleButtonDown
                              Case "3" : eventType=#PB_EventType_RightButtonDown
                                 captureWindow(0)
                           EndSelect                           
                        Case "mouseup"
                           Select eventWhich$
                              Case "1" : eventType=#PB_EventType_LeftButtonUp
                                 captureWindow(0)
                              Case "2" : eventType=#PB_EventType_MiddleButtonUp
                              Case "3" : eventType=#PB_EventType_RightButtonUp
                           EndSelect
                        Case "focusin" : eventType=#PB_EventType_Focus
                        Case "focusout" : eventType=#PB_EventType_LostFocus
                        Case "change" : eventType=#PB_EventType_Change
                     EndSelect
                     PostEvent(#PB_Event_WebGadget, EventWindow(), eventGadget, eventType)                     
                  EndIf
               EndIf
               
               If ConnectionID(Client)
                  Debug Hex(Client) + ": Disconnected!"
                  CloseNetworkConnection(Client)
               EndIf               
            EndIf
      EndSelect
      Protected refreshingDelay=captureWindow()
      Delay(refreshingDelay)
   ForEver   
EndProcedure

Define port=Random(7000, 6000)
Define thread=CreateThread(@WebServer(), port)
Define file$=GetCurrentDirectory() + "test.html"
CreateFile(#file, file$)
WriteStringN(#file, "<!DOCTYPE html>                                         " + #LF$ +
                    "<html lang='en' class='uk-height-1-1 uk-notouch'>       " + #LF$ +
                    "<head>                                                  " + #LF$ +
                    "<meta http-equiv='X-UA-Compatible' content='IE=edge'>   " + #LF$ + ;forces to use most recent IE version (workaround For Windows)
                    "<meta name='viewport' content='width=device-width, initial-scale=1'>                                           " + #LF$ +
                    "<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/uikit/2.24.3/css/uikit.min.css' />         " + #LF$ +
                    "<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/uikit/2.24.3/css/uikit.gradient.min.css' />" + #LF$ +
                    "<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js'></script>                      " + #LF$ +
                    "<script src='https://cdnjs.cloudflare.com/ajax/libs/uikit/2.24.3/js/uikit.min.js'></script>                    " + #LF$ +
                    "<script>                                                " + #LF$ +
                    "var PostToWebServer = function(e) {                     " + #LF$ +
                    "      if (e.type == 'contextmenu' || e.target.id=='#toolbar') e.preventDefault();  " + #LF$ + ;prevent To use default context menu
                    "      if (e.target.id) event.stopPropagation();         " + #LF$ +                            ;prevent To receive same event from parent nodes
                    "      $.ajax({                                          " + #LF$ +
                    "         type: 'POST',                                  " + #LF$ +
                    "         url: 'http://localhost:" + port + "',          " + #LF$ +
                    "         data: {                                        " + #LF$ +
                    "             'eventType':e.type                         " + #LF$ +
                    "            ,'eventWhich':e.which                       " + #LF$ +
                    "            ,'eventGadget':e.target.id                  " + #LF$ +
                    "            ,'nodeName':e.target.nodeName               " + #LF$ +
                    "            ,'nodeWidth':e.target.clientWidth           " + #LF$ +
                    "            ,'nodeHeight':e.target.clientHeight         " + #LF$ +
                    "            ,'mouseHitX':e.offsetX                      " + #LF$ +
                    "            ,'mouseHitY':e.offsetY                      " + #LF$ +
                    "         },                                             " + #LF$ +
                    "         dataType: 'json',                              " + #LF$ +
                    "         async:true                                     " + #LF$ +
                    "      })                                                " + #LF$ +
                    "      .done(function(data)                              " + #LF$ +
                    "      {                                                 " + #LF$ +
                    "         /**alert(data); /**/                           " + #LF$ +
                    "      })                                                " + #LF$ +
                    "   };                                                                                                             " + #LF$ +
                    "$(document).on({                                                                                                  " + #LF$ +
                    "   'mousedown mouseup click dblclick contextmenu' : PostToWebServer                                               " + #LF$ +
                    "});                                                                                                               " + #LF$ +
                    "$(document).on({ 'focus blur change' : PostToWebServer },'input');                                                " + #LF$ +
                    "</script>                                                                                                         " + #LF$ +
                    "</head>                                                                                                           " + #LF$ +
                    "<body class='uk-flex uk-flex-column uk-height-1-1'>                                                               " + #LF$ +
                    "   <div class='uk-flex' style='height:10px;cursor:n-resize'>                                                      " + #LF$ +
                    "      <div id='#border1' class='uk-block-secondary' style='width:10px;cursor:se-resize'></div>                    " + #LF$ +
                    "      <div id='#border2' class='uk-block-primary uk-flex-item-1'></div>                                           " + #LF$ +
                    "      <div id='#border3' class='uk-block-secondary' style='width:10px;cursor:sw-resize'></div>                    " + #LF$ +
                    "   </div>                                                                                                         " + #LF$ +
                    "   <div class='uk-flex uk-flex-item-1' >                                                                          " + #LF$ +
                    "      <div id='#border4' class='uk-block-primary' style='width:10px;cursor:w-resize'></div>                       " + #LF$ +
                    "      <div id='content' class='uk-flex-item-1'>                                                                   " + #LF$ +
                    "         <nav id='#toolbar' class='uk-navbar uk-navbar-attached'>                                                 " + #LF$ +
                    "            <ul class='uk-navbar-nav'><li class='uk-active'><a href='#'>File</a></li></ul>                        " + #LF$ +
                    "            <div class='uk-navbar-content uk-navbar-flip'>                                                        " + #LF$ +
                    "               <a id='#minimize' href='#' class='uk-icon-small uk-icon-minus-circle' style='color:gray'></a>      " + #LF$ +
                    "               <a id='#maxmimize' href='#' class='uk-icon-small uk-icon-chevron-circle-up' style='color:gray'></a>" + #LF$ +
                    "               <a id='#close' href='#' class='uk-icon-small uk-icon-times-circle' style='color:gray'></a>         " + #LF$ +
                    "            </div>                                                                                                " + #LF$ +
                    "         </nav>                                                                                                   " + #LF$ +
                    "         <div class='uk-panel uk-panel-box uk-panel-box-secondary uk-margin-left uk-margin-right uk-margin-top'>  " + #LF$ +
                    "         <form class='uk-form'>                                                                                   " + #LF$ +
                    "            <fieldset>                                                                                            " + #LF$ +
                    "               <legend>LOGIN</legend>                                                                             " + #LF$ +
                    "               <div class='uk-form-row'><input type='text' placeholder='Username'></div>                          " + #LF$ +
                    "               <div class='uk-form-row'><input type='password' placeholder='Password'></div>                      " + #LF$ +
                    "               <div class='uk-form-row'>                                                                          " + #LF$ +
                    "                  <button id='#connect' class='uk-button uk-button-large uk-button-primary uk-animation-hover     " + #LF$ +
                    "                     uk-animation-scale uk-animation-reverse'><i class='uk-icon-refresh uk-icon-spin'></i>&nbsp;Connect</button>       " + #LF$ +
                    "               </div>                                                                                             " + #LF$ +
                    "            </fieldset>                                                                                           " + #LF$ +
                    "         </form>                                                                                                  " + #LF$ +
                    "         </div>                                                                                                   " + #LF$ +
                    "      </div>                                                                                                      " + #LF$ +
                    "      <div id='#border5' class='uk-block-primary' style='width:10px;cursor:w-resize'></div>                       " + #LF$ +
                    "   </div>                                                                                                         " + #LF$ +
                    "   <div class='uk-flex' style='height:10px;cursor:n-resize'>                                                      " + #LF$ +
                    "      <div id='#border6' class='uk-block-secondary' style='width:10px;cursor:sw-resize'></div>                    " + #LF$ +
                    "      <div id='#border7' class='uk-block-primary uk-flex-item-1'></div>                                           " + #LF$ +
                    "      <div id='#border8' class='uk-block-secondary' style='width:10px;cursor:se-resize'></div>                    " + #LF$ +
                    "   </div>                                                                                                         " + #LF$ +
                    "</body>                                                                                                           " + #LF$+
                    "</html>")
CloseFile(#file)

Define xml$="<window id='#win' name='win' text='WEB APP' minwidth='600' minheight='400' width='600' height='400' margin='0' flags='#PB_Window_ScreenCentered | #PB_Window_BorderLess'>" +
            "   <web id='#web'></web>" +
            "</window>"
If CatchXML(#xml, @xml$, StringByteLength(xml$)) And XMLStatus(#xml)=#PB_XML_Success And CreateDialog(#dialog) And OpenXMLDialog(#dialog, #xml, "win")
   SmartWindowRefresh(#win, #True)
   SetGadgetText(#web, "file:///" + file$)
   Repeat     
      Select WaitWindowEvent()
         Case #PB_Event_CloseWindow
            Debug "quit"
            Break
         Case #PB_Event_SizeWindow
         Case #PB_Event_MoveWindow
         Case #PB_Event_DeactivateWindow
            Debug "de-activate"
         Case #PB_Event_Gadget
           
           
         Case #PB_Event_WebGadget
            Select EventType()
               Case #PB_EventType_LostFocus
                  Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=LostFocus"
               Case #PB_EventType_Focus
                  Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Focus"
               Case #PB_EventType_Change
                  Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Change"
               Case #PB_EventType_LeftButtonDown
                  Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Left-MouseDown"
               Case #PB_EventType_LeftButtonUp
                  Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Left-MouseUp"
               Case #PB_EventType_RightButtonDown
                  Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Right-MouseDown"
               Case #PB_EventType_RightButtonUp
                  Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Right-MouseUp"
               Case #PB_EventType_MiddleButtonDown
                  Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Middle-MouseDown"
               Case #PB_EventType_MiddleButtonUp
                  Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Middle-MouseDown"                 
               Case #PB_EventType_RightClick
                  Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Right-Click"
               Case #PB_EventType_RightDoubleClick
                  Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Right-DblClick"
               Case #PB_EventType_LeftClick
                  Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Left-Click"
                  Select EventGadget()
                     Case #close : Break ;close window
                     Case #maxmimize : SetWindowState(#win, #PB_Window_Maximize)
                     Case #minimize : SetWindowState(#win, #PB_Window_Minimize)
                  EndSelect
               Case #PB_EventType_LeftDoubleClick
                  Debug "win=" + EventWindow() + " gadget=" + EventGadget() + " eventType=Left-DblClick"
            EndSelect
      EndSelect
   ForEver
EndIf

Author:  idle [ Sun Jan 24, 2016 7:32 am ]
Post subject:  Re: hybrid web application : HTML5 + PB

that's some clever foo! :shock:

Author:  HanPBF [ Sun Jan 24, 2016 10:51 am ]
Post subject:  Re: hybrid web application : HTML5 + PB

Hello eddy,

thanks for the great example.

This is application development which is future proof!

- setting up a web server in an enterprise is a mess: what for when how who etc....
- given a local example and sync via database (the PB part) is client/server model and works
- JS is ubiquitous; Win10 apps will be done that way (o.k. Microsoft does always only 80% for new technics...)
- PB lacks a full featured GUI framework (and it's o.k.; PB is not .NET/JAVA!); for JS there are thousands (s. a. jqWidgets)
- if management wants a full featured web app -> You are already done!
- nwjs.io is a mess and tricky, electron not free (for an enterprise)
- even You find a good all-tier-model; You get quickly into the vendor lock-in
- PB has a great WebSocket example; so, switching from this example to a "server" web-server is possible (http://www.purebasic.fr/english/viewtopic.php?f=12&t=61606&p=466507)
- problem: getting the browser chromeless; I got it with Firefox portable and some plugins
- even You can not get the browser chromeless; users want a good application no matter if there is an address bar or not

Your example use a webgadget via dialog library, correct?
Maybe there is not the latest browser version available?

But that is not a problem; it's possible to open any browser and run program.
Network does the connection.

With this architecture, PB has also hundreds of GUI frameworks available!

Then, SpiderBasic makes more sense (http://www.spiderbasic.com/).
Instead of bringing a whole framework to web; only JavaScript should be replaced für PB'ers (s. a. altjs).

Author:  eddy [ Sun Jan 24, 2016 1:53 pm ]
Post subject:  Re: hybrid web application : HTML5 + PB

Mac & Linux web gadget work with webkit engine. So there are much less limitations and I suppose the UI is displayed correctly

But for windows web gadget, I added a metatag to force IE to use the most recent rendering engine.
vista -> IE9
win7 -> IE10
win8.1 -> IE11
win10 -> IE11

Author:  eddy [ Sun Jan 24, 2016 2:13 pm ]
Post subject:  Re: hybrid web application : HTML5 + PB

There's an other solution using URL scheme (for example: myPBApp://generateReport/sales/2015-10-10)
  • It don't need local web server.
  • It's cross-platform but I don't know how to code this feature on MAC & Linux

Author:  IdeasVacuum [ Sun Jan 24, 2016 9:32 pm ]
Post subject:  Re: hybrid web application : HTML5 + PB

Isn't this similar to what you can do with SpiderBasic?

Author:  eddy [ Sun Jan 24, 2016 11:06 pm ]
Post subject:  Re: hybrid web application : HTML5 + PB

IdeasVacuum wrote:
Isn't this similar to what you can do with SpiderBasic?
No.

SpiderBasic can create pure web applications.
  • These web apps have to run inside a web browser (Chrome,FF,IE)
  • They have access to web capabilities (HTML5 Api)
  • They have no access to native desktop or mobile capabilities. (Mac,Win,Linux,Android,iOS...)

An hybrid app is a web application hosted inside a native application that utilizes native platform’s WebView (a webgadget in my example).
This enables them to access desktop or mobile capabilities.

Apache Cordova is the most famous hybrid app solution.
Spiderbasic combined with Cordova, you could create mobile or desktop app (Win10, iOS, Android, Ubuntu, FirefoxOS, ...)

Author:  eddy [ Mon Feb 01, 2016 12:55 am ]
Post subject:  Re: hybrid web application : HTML5 + PB

Updated
  • resize window
  • drag window
  • close button
  • improved example

Author:  firace [ Thu Jan 25, 2018 10:48 pm ]
Post subject:  Re: hybrid web application : HTML5 + PB

This seems to no longer work... I'm just getting a blank page.

Note: Tested on Win 10 x64, with no admin rights

Author:  HanPBF [ Wed Feb 21, 2018 10:17 am ]
Post subject:  Re: hybrid web application : HTML5 + PB

Quote:
electron not free (for an enterprise)

Not true anymore; I guess it's free.

SpiderBasic: You could build the frontend with SpiderBasic and run it in electron.
Electron's backend is node.js.
But via WebSocket/File or any other connection, other backends are possible.

I use PureBasic as backend with access to File System, ORACLE, MS SQL Server, MySQL/ODBC.

Don't know how SpiderBasic's debugging works; debugging JavaScript itself is very easy with debugger embedded in browser.

Author:  Kiffi [ Wed Feb 21, 2018 3:33 pm ]
Post subject:  Re: hybrid web application : HTML5 + PB

i personally like NW.js more than electron.

Here is a small tutorial how to run a SpiderBasic-WebApp as a Desktop-Application: http://forums.spiderbasic.com/viewtopic.php?p=5086#p5086

Greetings ... Peter

Author:  HanPBF [ Wed Feb 21, 2018 3:35 pm ]
Post subject:  Re: hybrid web application : HTML5 + PB

Hello kiffi!

Yes, thanks for the hint!

Any main differences or dis/advantages beteen electron and nw.js?

Author:  Kiffi [ Wed Feb 21, 2018 3:57 pm ]
Post subject:  Re: hybrid web application : HTML5 + PB

HanPBF wrote:
Any main differences or dis/advantages beteen electron and nw.js?

* NW.js is easy to control from SpiderBasic (take a look at: https://github.com/spiderbytes/NwJs)

* NW.js has a 'built-in' NodeJS. There's no need to install it separately.

* The Setup is much easier (in my opinion).

Greetings ... Peter

Author:  Kwai chang caine [ Fri Feb 23, 2018 6:11 pm ]
Post subject:  Re: hybrid web application : HTML5 + PB

Quote:
This seems to no longer work... I'm just getting a blank page
Personally i have exactely the page presented by eddy :wink:
I take advantage to this message for thanks EDDY for his sharing 8)

Author:  HanPBF [ Thu Mar 08, 2018 2:57 pm ]
Post subject:  Re: hybrid web application : HTML5 + PB

Short info for someone thinking about electron vs. nw.js.

Electron is a mess.
nw.js just works.

Packaging is not good solved with both frameworks.

So, I switched from electron to nw.js; which was easy as I don't use node.js at the moment but AJAX.

Regards!

Page 1 of 2 All times are UTC + 1 hour
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/