The Autobahn Has no Speed Limit – Your XPages Shouldn’t Either
Tweet about this event: #xpages
and mention us: @teamstudio @TLCCLTD @eknori
October 17, 2013
@teamstudio teamstudio.com
@TLCCLTD
@eknori
Taline Badrikian Marketing Director
Who we are
• Our background is in creating tools for collaborative computing in mid-size and large enterprises, primarily for Lotus Notes
• Easy-to-use tools for developers and administrators • 2300+ active customers, 47 countries • Offices in US, UK and Japan • Entered mobile space in 2010 with Unplugged – easy
mobilization of Notes apps to Blackberry, Android and iOS
Teamstudio Unplugged
• Your Mobile Domino Server – take your Notes apps with you!
• End users access Notes applications from mobile devices whether online or offline
• Leverages existing skills and technology – XPages – Replication model you already know
• IBM Collaboration Solutions Award Winner 2013
Teamstudio Continuity
• Mobile BCM application for smartphones and tablets – iOS, Android and BB
• Offline access to all your BCM and Disaster Recovery data
• Store plans, contacts, call trees, and more • Client available for download from app stores
Teamstudio
• Next webinar November 19th
• DCLUG – October 24th
• BLUG All Things Mobile – October 29th
• Promotions: – Chance to win an iPad mini when you get a demo of Teamstudio
Continuity
The Autobahn has no speed limit - Your XPages shouldn't either!
1
#XPages
Paul Della-Nebbia TLCC
@PaulDN
Your Host Today:
Upcoming and Recorded Webinars
2
Next Webinar on November 19th
www.tlcc.com/xpages-webinar
View Previous Webinars (use url above)
TLCC Courses and Services
3
• The Leader in Notes and Domino Training since 1997 • Self Paced Distance Learning Courses for Notes/Domino
– XPages, Development, and Administration (user too!) – Learn anywhere using your Notes client – Many demos and activities – An Instructor is a click away
• OnSite Private Classes • TLCC Mentoring Services
What’s New at TLCC
4
Free course – Introduction to XPages Development (both 8.5 and 9.0)
New Courses! • Notes Domino 9 Application Development 1 • Notes Domino 9 Application Development Update • Java 1 for XPages Development (9.0) • Notes Domino 9 System Administration Update • Notes Domino 9 System Administration 1
New Packages!
• XPages and JavaScript for Domino 9 Package • XPages and Rapid Development for Domino 9 Package • XPages, JavaScript and Rapid Development for Domino 9 Package
TLCC’s Fall Sale – Extended to Oct. 31st
XPages Skills Path
5
Core Notes/Domino Skills
Domino Object Model skills LotusScript or
Java
JavaScript for XPages Developers
XPages Development 1
Rapid XPages Development (user interface controls)
XPages Development 2
Mobile XPages Development
Java for XPages
Suggested TLCC Skills Path at TLCC.com
TLCC Can Help: • Self Paced Courses • Instructor Led Online • OnSite Private Instructor Led • Blended Learning • Custom courses
Asking Questions
6
Q & A at the end! Type in your questions as they come up
Your Presenters Today:
#XPages
7
Howard Greenberg IBM Champion
Founding Partner TLCC
@TLCCLtd
Ulrich Krause IBM Champion
Senior Software Architect BCC
@Eknori, @bccffm
About: Ulrich Krause
• Administrator /Developer since 1993 • Senior Software Architect at BCC, Germany
• OpenNTF Contributor • IBM Champion 2011/2012/2013
• Blog http://www.eknori.de • Web http://www.bcc.biz • Forum (de) (http://www.atnotes.de) • Twitter @eknori • Mail [email protected]
8
Agenda
• What factors affect Performance? • JSF Lifecycle Listener • Partial Update / Partial Execute • Tools • Coding Factors
– ViewNavigator vs. GetItemValue – SSJS vs. Java – Stringbuilder
• Questions???
9
XPages Request
10
Hardware
• The hardware used has a significant influence on performance. There are 3 key elements:
– CPU – Main Memory – Hard Disk
11
Hardware
• Main Memory – Limit defined by the operating system Scalability
• CPU – Cores / Clock / Cache Poor response time
• Weak CPU AND Low Memory – Poor overall performance – Poor response times – Server "hangs"
12
Network
• Latency – Time taken for data transmission between
multiple computers on a network • Bandwidth
– Rate of transmission of data • Greater Bandwidth
+ Lower Latency -------------------------------- = Better Connection
13
Client & Browser
• Hardware • How many data requests / responses are
transmitted • How much data is transferred (size) • Caching of resources • How much CSJS runs • Size / complexity of the CSS • Complexity of the site structure
14
Limiting factors on performance
• Browser / HTTP server – Network latency – distance/time to server. – Bandwidth – size of files. – Browser limits on concurrent downloads
• IE7 allows 2 downloads, IE8 allows 6
• HTTP Server / App Server
– HTTP Server JVM heap size & garbage collector – CPU time, competition between threads, gives slower
response times – Threads, limited to 40 by default
15
Limiting factors on performance
• App Server / Domino context – Read design elements from the NSF (XPage .class files, form
structure, etc) – Backend API calls may be expensive, especially for large data
sets – Design elements may be network requests
16
Limiting factors on performance
• Servlet / Lifecycle – Restore control tree – file system read. Control tree locking
– no concurrent access – Rendered re-evaluated for every control for most phases
• Browser/Client JavaScript/Dojo
– Inline JavaScript blocks insertion of later HTML elements into the DOM tree
– Dojo does AJAX requests for .js files for dojo modules that are not loaded
17
General Performance Options
• notes.ini – HTTPJVMMaxHeapSizeSet=1 – HTTPJVMMaxHeapSize=256M
• Should be set to ¼ of the available RAM
• Domino Administrator – HTTP server Disable Logging – HTTP server thread count defaults to 40
• link to IBM article
• Debugging enabled in notes.ini ? – JavaEnableDebug=1 – JavaDebugOptions=transport=dt_socket,server=y,suspen
d=n,address=8000 – JavascriptEnableDebug=1
18
Reducing Memory Utilization
• xsp.persistence.mode= – Defines the persistence mode for the JSF pages
• file: All the pages are persisted on disk • fileex: All the pages are persisted on disk except the current one,
which stays in memory • <else>: All the pages stay in memory (tree mode)
19
JavaScript/CSS Aggregation
• Groups many DOJO, CSS / JS files into a single file – Less requests from the browser to the server – Performance improvements on networks with high
latency – Enhanced performance parsing CSS / JS – Fewer connections to the server
On the Server: xsp.properties: xsp.resources.aggregate=true
20
JavaScript/CSS Aggregation
21
XPages PreLoad
• XPagesPreload=1 • New Feature in Notes / Domino 8.5.3 • Works on Server and Client • Java classes from the XPages runtime plug-ins loaded
from a fixed list of runtime classes ( 435 in ND 8.5.3 ) – com.ibm.xsp.core, common utility, JS wrapper, FSF runtime
classes
• Java classes referenced in *-faces.config.xml – XPages control renderer, data sources, complex types
22
XPages PreLoad
• XPagesPreloadDB = Server!!Db.nsf/XPage.xsp, myLocalDb.nsf
• Works at the application level • The application is loaded on the client / server startup into
memory – This happens even when the application is first opened in
the browser
23
XPages PreLoad (cont.)
• For each entry in the notes.ini variable, an XPage URL is generated and sent to the server
• The application is loaded, and the HTML generated
• The XPages runtime discards the HTML, but retains the application in memory
24
Scoped Variables
• applicationScope – Are visible for all users of one application – Expires some time after the last user used an
applicationScope variable – applicationScope variables are NOT persistent forever
• sessionScope – Is valid through the session of the current user – A user session expires after some time of inactivity – Uses don't have access to the sessionScope variables of
other users
25
Scoped Variables (cont.)
• viewScope – Is visible for views on the current page only.
– Useful for transporting a search query to a view.
• requestScope – Is valid through one request of the current user. – That includes refreshing of a page.
26
Caching with Application Scope
27
Next Up:
#XPages
28
Howard Greenberg IBM Champion
Founding Partner TLCC
@TLCCLtd
29
JSF Life Cycle - Post
Restore View
•Restore component tree •Events: •afterRestoreView
Apply Request Values
•Copy data to Editable controls
Process Validations
•Validations •Converters
Update Model Values
•Move values to data source
Invoke Application
•Application logic •Events: •onClientLoad (XPage, etc) •on… events of button, etc.
Render Response
•Convert to HTML, etc. •Events: •beforeRenderReponse •afterRenderResponse
Request
Response
Lifecycle1 XPage – Initial Page Load
30
Render Response
•Rendered property for id: label1 • Label property for id: label1 •Rendered property for id: inputText1 •Default value property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 • values property for id: comboBox1 • values property for id: comboBox1 •Rendered property for id: computedField1 •Value property for id: computedField1 •Rendered property for id: computedField2 •Value property for id: computedField2
31
Lifecyle1 – Submit (Full Update)
Restore View
Apply Request Values (8)
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Process Validations (11)
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Validation for inputText1 •Default value property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •values property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Update Model Values (8)
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Invoke Application (1)
•OnClick event for id: button1
Render Response (11)
•Rendered property for id: label1 •Label property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •values property for id: comboBox1 •values property for id: comboBox1 •Rendered property for id: computedField1 •Value property for id: computedField1 •Rendered property for id: computedField2 •Value property for id: computedField2 39 SSJS Calls
When to Execute - # vs $
• # is Compute dynamically – Executed every time the page is rendered – Use for values that are likely to change
• $ is Compute on Page Load – Executed when the page is first loaded – Use for values that don't change
32
<xp:label id="label1"> <xp:this.value>
<![CDATA[#{javascript:return “My Label”;}]]> </xp:this.value> </xp:label>
33
Lifecyle2 – Submit (Full Update) - On Page Load
Restore View
Apply Request Values
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Process Validations (2)
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Validation for inputText1 •Default value property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •values property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Update Model Values
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Invoke Application (1)
•OnClick event for id: button1
Render Response (3)
•Rendered property for id: label1 •Label property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •values property for id: comboBox1 •values property for id: comboBox1 •Rendered property for id: computedField1 •Value property for id: computedField1 •Rendered property for id: computedField2 •Value property for id: computedField2 6 SSJS Calls, saved 33
Changed all Rendered and Values (comboBox) to only compute on Page Load
Options for dynamically computing the Rendered: • Scoped variables
– Still get calculated but do the heavy lifting once and then read the scoped variable in the Rendered property
• DataContexts – Compute a value at the Xpage or Panel level once – Refer to the value using EL (much faster than SSJS)
34
But I need dynamic Rendering!
DataContext
• Can be thought of as global variables • Value can be computed dynamically or on page load
– Warning: Computing dynamically has performance impact
• Can be scoped to any level that a data source can – XPage, Custom Control or Panel – Set a dataContext in a panel in a repeat control to avoid
multiple references to a NotesDocument's item
• Can be referenced using EL – Benefit: Not having to go through the SSJS parser
35
DataContext - Pitfall
• Be careful binding data context variables dynamically – They will be recomputed multiple times, even when in
partial execution mode and if they are not in use (six times!)
• Apply Request Values • Process Validations • Update Model Values • Invoke Application • Twice in Render Response!
• If computed on page load then only computed once on page load
• See Paul Withers blog entry to learn how to set a data context value via code
36
• Partial Refresh (Update) – Computes entire XPage,
only sends back what is in the partial refresh id (refreshId)
• Partial Execution – Only calculates what is in
the area specified (execId)
37
Partial Refresh vs. Partial Execution?
38
Partial Refresh Demo - Results
Restore View
Apply Request Values (8)
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Process Validations (11)
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Validation for inputText1 •Default value property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •values property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Update Model Values (8)
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Invoke Application (1)
•OnClick event for id: button1
Render Response (2)
•Rendered property for id: label1 •Label property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •values property for id: comboBox1 •values property for id: comboBox1 •Rendered property for id: computedField1 •Value property for id: computedField1 •Rendered property for id: computedField2 •Value property for id: computedField2 30 SSJS Calls, saved 9
Only Savings were here!
Partial Refresh Pros and Cons
• Pros – Reduced control processing in the render response phase – Smaller response from server
• Means reduced network usage
– Better UI experience • Rest of the page is still visible while waiting for a response
• Cons – Controls like computed fields outside refresh area don’t refresh – Be careful turning this on for a completed XPage (TEST!) – Can only update one area (one id)
• Workaround on Tim Tripcony blog here 39
40
Partial Execution Demo - Results
Restore View
Apply Request Values (1)
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Process Validations (1)
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Validation for inputText1 •Default value property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •values property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Update Model Values (1)
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Invoke Application (1)
•OnClick event for id: button1
Render Response (12)
•Rendered property for id: label1 •Label property for id: label1 •Rendered property for id: inputText1 •Default value property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •values property for id: comboBox1 •values property for id: comboBox1 •Rendered property for id: computedField1 •Value property for id: computedField1 •Rendered property for id: computedField2 •Value property for id: computedField2
16 SSJS Calls Saved 13
Partial Execution Pros and Cons
• Pros – Reduced processing in the 3 data-processing phases
• Cons – Control with onClick event has to be inside the execId area – Editable values outside of the executed area do not get
submitted/updated (reset to default values) – Existing XPages need analysis/testing before using this
• Current onclick events might refer to controls where the data is not submitted
– ExecMode available in 8.5.1 – Have to use source to enter ExecId (in 8.5, 9.0 has Designer UI)
41
42
Partial Refresh AND Execution Demo - Results
Restore View
Apply Request Values (1)
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2 •Rendered property for id: computedField2
Process Validations (1)
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Validation for inputText1 •Default value property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •values property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Update Model Values (1)
•Rendered property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •Rendered property for id: comboBox1 •Rendered property for id: computedField1 •Rendered property for id: computedField2
Invoke Application (1)
•OnClick event for id: button1
Render Response (2)
•Rendered property for id: label1 •Label property for id: label1 •Rendered property for id: inputText1 •Rendered property for id: label2 •Rendered property for id: comboBox1 •values property for id: comboBox1 •values property for id: comboBox1 •Rendered property for id: computedField1 •Value property for id: computedField1 •Rendered property for id: computedField2 •Value property for id: computedField2
6 SSJS Calls, saved 33
disableValidators= true
• All phases (1-6) occur • Turns off all validators • Converters continue to work • Items in documents will be updated
43
Restore View Apply Request Values
Process Validations
•No Validators get executed here!
Update Model Values
Invoke Application
Render Response
Immediate = true
• JSF Lifecycle processes only phases (1, 2, 6)
• No data processing • Items in documents are not
updated • Onclick event handler scripts and
render response calculations are performed
44
Restore View Apply Request Values
Process Validations
Update Model Values
Invoke Application
Render Response
Using the loaded Property
• Loaded = true – Not in component tree or
memory
• Loaded = false – Control is not created – Can never be rendered
or accessed – Saves memory too
45
Loaded only computed once in the createView phase
Life Cycle Performance Suggestions
• Most properties, like CSS “style” are only computed in the RenderResponse phase
• Watch and minimize: – Rendered property (when dynamic)
• Computed multiple times! • Use dataContexts or scoped variables
when able
• Use both Partial Refresh (Update) and Partial Execute when able
46
Watch Out for @DbLookup
• @DbLookup about 3-4 times slower than SSJS – res = @DbLookup(db,"CustomersByNameView",names[i], "phone");
vs. – doc = vw.getDocumentByKey(names[i], true);
res = doc.getItemValueString("phone");
• Five lookups repeated 100 times – @DbLookup averaged about 1728ms – getDocumentByKey averaged 510ms
• Other @Functions not tested
47
Next Up:
#XPages
48
Ulrich Krause IBM Champion Senior Software
Architect BCC
@Eknori, @BCCFFM
Images
• Use correct file type depending on content – JPEG for complex and detailed images – PNG/GIF for simple images, fonts, transparencies
• Use the HTML <img> tag “width” and “height” attributes
• For faster HTML layout in the browser
– Size the image to size you intend to use • Resizing using html attributes height and width will delay the
rendering of your page • Images larger than necessary will waste bandwidth
49
Image Sprites
• Use CSS Image Sprites – If you have multiple small images, make a single larger
image containing the smaller images – Use CSS to display only the relevant subset image at a
location in the page – For semantically significant sprites, provide an
accessibility “title” attribute (as sprites don't use the IMG “alt” attribute, but you still want to assist blind users)
– There's no specific XPages support for sprites, but they're used in the XPages OneIU themes
50
CSS Image Sprite Sample
http://www.w3schools.com/css/tryit.asp?filename=trycss_sprites_img
51
XPages Toolbox
• XPages based Application – Runs on the Domino server or the Notes client – An NSF needs to be installed on the server/Notes client – A profiler jar file should be added to the JVM launch options
• Measures CPU performance and memory allocation • Available from OpenNTF.org
– Free open source project • http://www.openntf.org/internal/home.nsf/project.xsp?action=open
Document&name=XPages%20Toolbox
• Extended in 8.5.2 to support backend classes profiling
52
XPages Toolbox
53
XPages Toolbox
• Generate a heap dump of the JVM running in the HTTP task
– A button in the XPages profiler generates the heap dump – From the Domino console
• tell http xsp heapdump (triggers com.ibm.jvm.Dump.HeapDump()) • tell http xsp javadump (triggers com.ibm.jvm.Dump.JavaDump())
• Analyze the heap dump using the Eclipse memory analyzer
– http://www.eclipse.org/mat/ – http://www.ibm.com/developerworks/java/jdk/tools/dtfj.html
54
Heapdump / Javadump Analyzer
55
More Tools
• Print statements – In rendered/visible computations to see how often executed
• print("panel2 evaluating rendered property");
– In the XPages root control events: • before/afterPageLoad, afterRestoreView,
before/afterRenderResponse
– Custom control root events: • before/afterPageLoad
– In the document data source events: • queryNewDocument, postSaveDocument, etc.
• Task Manager and/or Process Explorer – Shows CPU usage & process memory usage as it happens
56
More Tools
• Browser developer tools – for watching network transactions, partial updates,
response times – BROWSER: Firebug, Developer Tools – XPiNC: FirebugLite from ExtLib
• Java / Javascript Debugging – Degrades performance but can inspect objects
• Use the Eclipse Java debugger – In Domino\notes.ini add these 2 options:
• JavaEnableDebug=1 • JavaDebugOptions=transport=dt_socket,server=y,suspend=n,add
ress=8000
57
Optimization – Step By Step
58
Step 1: Original Code From Sample
• Read all Contacts into a NotesDocumentCollection, loop the collection and build the JSON by reading the values from items in the document
59
Step 1: Result
60
Step 2: Store UNID in an item
• Get all Contacts into a NotesDocumentCollection, loop the collection and build the JSON by reading the values from items in the document. Also UNID is stored in document
61
Step 2: Result
62
Step 3: Build JSON on document save
• Get all Contacts into a NotesDocumentCollection, loop the collection and get the JSON from an item on the document. JSON is calculated on document save
63
Step 3: Result
64
Step 4: Read JSON from view with ViewNavigator
65
Step 4: Result
66
StringBuilder vs String.concat
• Concatenation of Strings is very easy in Java - all you need is a +
• Each time you append something via + (String.concat()) a new String is created, the old stuff is copied, the new stuff is appended, and the old String is thrown away. The bigger the String gets the longer it takes - there is more to copy and more garbage is produced.
• Accordingly to Arno Unkrig the optimal strategy is to use String.concat() for 2 or 3 operands, and StringBuilder for 4 or more operands
67
StringBuilder vs String.concat
• Use StringBuilder whenever you assemble a String in a loop
– Keep in mind that + isn't always a good idea
68
Step 5: Use a StringBuilder to concat the JSON
69
Step 5: Result
70
Step 6: Use Java instead of SSJS
71
Xpage SSJS Code
Java Code
Step 6: Result
72
• IBM article on JSF (non XPages) • Paul Withers blog (each link below is different)
– Part 1, Part 2, Part 3
• Tony McGuckin’s Video - XPages Master class – 4 videos plus sample applications
73
Homework Time – Further References
Questions????
74
Use the Q&A pane in WebEx to ask questions We will answer your questions verbally
Question and Answer Time!
75
Teamstudio Questions? [email protected] 877-228-6178
TLCC Questions?
[email protected] [email protected] 888-241-8522 or 561-953-0095
Howard Greenberg Taline Badrikian
Upcoming Events:
TLCC Fall Sale – ends 10/31
IBM Connect 2014 Registration is now open
#XPages
@Eknori
@TLCCLtd
@Teamstudio
@PaulDN
@BCCFFM
Paul Della-Nebbia Ulrich Krause