“Monitoring” SQL Server - netways
“Monitoring” SQL Server - netways
“Monitoring” SQL Server - netways
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
<strong>“Monitoring”</strong> <strong>SQL</strong><br />
<strong>Server</strong><br />
Workshop<br />
Open Source Monitoring Conferrence<br />
Presentation © Michael Medin
Disclaimer!<br />
These slides represent the work and opinions<br />
of the author and do not constitute official<br />
positions of any organization sponsoring the<br />
author’s work<br />
This material has not been peer reviewed and<br />
is presented here as-is with the permission of<br />
the author.<br />
The author assumes no liability for any<br />
content or opinion expressed in this<br />
presentation and or use of content herein.
My Background<br />
Developer (not system manager)<br />
Not working with Nagios<br />
Accidentally ended up in our NOC<br />
Hated BB<br />
2003: The birth of NSClient++<br />
NSClient sucked (Broke Exchange)<br />
NRPE_NT was to hard to use<br />
2004: The open source of NSClient++<br />
“just for fun”
Agenda<br />
Introduction<br />
Part 1: Remote access<br />
Part 2: Tools of the Trade<br />
Break<br />
Part 3: Monitoring<br />
Part 4: Scripting<br />
Conclusion<br />
5 minutes<br />
15 minutes<br />
40 minutes<br />
20 minutes<br />
20 minutes<br />
10 minutes<br />
0 minutes
Introductions…<br />
Who are you<br />
What are your experiences with monitoring<br />
What are your experiences with <strong>SQL</strong> <strong>Server</strong><br />
What are your expectations<br />
…
Split into groups<br />
2-3 persons
Assignment<br />
Where do we start
Task/Question<br />
When you manage a <strong>SQL</strong> <strong>Server</strong>:<br />
What’s the most important thing to monitor
Hint 1<br />
It is not something I will speak about…
Hint 2<br />
It is not something I will speak about…<br />
It is not <strong>SQL</strong> <strong>Server</strong> related
(My) Answer<br />
If the infrastructure goes down<br />
so will <strong>SQL</strong> <strong>Server</strong><br />
Always start by monitoring the infrastructure<br />
Hardware<br />
●<br />
●<br />
●<br />
●<br />
●<br />
Software<br />
Clusters<br />
Raid arrays<br />
Network infrastructure<br />
Temperature/HW Status<br />
…
Monitoring Infrastructure<br />
This depends on what environment you have<br />
NOT related to <strong>SQL</strong> <strong>Server</strong><br />
Thus... Your on your own…
Part 1: Remote access<br />
Click to edit Master text styles<br />
Second level<br />
●<br />
Third level<br />
●<br />
Fourth level<br />
●<br />
Fifth level
Remote access<br />
<strong>SQL</strong> <strong>Server</strong> from perl
●<br />
Perl and <strong>SQL</strong> <strong>Server</strong><br />
Perl<br />
Install perl and DBI with ODBC (and TDS<br />
driver)<br />
●<br />
You need (for debian):<br />
– perl<br />
– unixodbc unixodbc-dev tdsodbc<br />
●<br />
Then you need to configure a odbc driver<br />
(/etc/odbcinst.ini)<br />
– [FreeTDS]<br />
– Description = TDS driver (Sybase/MS <strong>SQL</strong>)<br />
– Driver = /usr/lib/odbc/libtdsodbc.so<br />
– Setup = /usr/lib/odbc/libtdsS.so<br />
– CPTimeout =<br />
– CPReuse =
Perl and <strong>SQL</strong> <strong>Server</strong><br />
On Windows:<br />
Install ActiveState perl<br />
●<br />
Everything you need comes included<br />
Install a ODBC driver for <strong>SQL</strong> <strong>Server</strong><br />
●<br />
Verify:<br />
http://www.microsoft.com/downloads/en/details.aspx<br />
familyid=78CAC895-EFC2-4F8E-A9E0-3A1AFBD5922E&displaylang=en<br />
●<br />
perl -e "use DBI 1.6;"<br />
●<br />
●<br />
●<br />
perl –e "use DBD::ODBC;"<br />
perl -MDBD::ODBC -e "print $DBD::ODBC::VERSION;"<br />
perl -MDBI -e "DBI->installed_versions;"
Add a datasource<br />
Unix:<br />
Edit: /etc/odbc.ini<br />
●<br />
●<br />
●<br />
[osmc]<br />
Driver = FreeTDS<br />
<strong>Server</strong> = <br />
Windows:<br />
Data sources -> System data source<br />
●<br />
Add -> {next, next, next} -> done<br />
Name: osmc<br />
<strong>Server</strong>:
Connecting to a database<br />
#!/usr/bin/perl -w<br />
use strict;<br />
use DBI;<br />
my $dbh = DBI->connect('dbi:ODBC:osmc','osmc','osmc') or die "Can't connect to osmc: $DBI::errstr";<br />
my $sql = "SELECT 1 AS test_col";<br />
my $sth = $dbh->prepare($sql) or die "Can't prepare statement: $DBI::errstr";<br />
$sth->execute();<br />
print "$sth->{NAME}->[0]\n";<br />
while ( my @row = $sth->fetchrow_array ) {<br />
print "@row\n";<br />
}<br />
$dbh->disconnect;<br />
$ perl test.pl<br />
test_col<br />
1
Assignment<br />
Setting up perl
Task/Question<br />
Configure perl for database connectivity<br />
Connect to the following database<br />
Database = osmc<br />
Ip= ...
Hint 1<br />
●<br />
●<br />
●<br />
apt-get install perl<br />
apt-get install unixodbc unixodbc-dev<br />
apt-get install tdsodbc<br />
●<br />
cat /usr/share/tdsodbc/odbcinst.ini >> /etc/odbcinst.ini<br />
●<br />
echo -e '[osmc]\nDriver = FreeTDS\n<strong>Server</strong> = ...' >><br />
/etc/odbc.ini cpan –i DBI<br />
●<br />
●<br />
cpan –i DBI<br />
cpan –i DBD::ODBC
Hint 2<br />
$ cat > test.pl prepare(\$sql) or
(My) Answer<br />
Hopefully you can now connect
Remote access<br />
Performance counters
check_nrpe<br />
We will mainly use this for counters<br />
check_nrpe<br />
●<br />
–H -c -a <br />
Or if you are on windows:<br />
nsclient++ -noboot NRPEClient<br />
●<br />
–H -c -a <br />
Command:<br />
CheckCounter
Assignment<br />
Checking performance<br />
counters
Task/Question<br />
Access performance counters from <br />
Command is:<br />
CheckCounter<br />
Counter is:<br />
\Processor(_Total)\% Processor Time
Hint 1<br />
Command is:<br />
CheckCounter<br />
Counter is:<br />
\Processor(_Total)\% Processor Time<br />
Unix:<br />
●<br />
●<br />
check_nrpe<br />
–H -c -a <br />
Or if you are on windows:<br />
●<br />
nsclient++ -noboot NRPEClient
Hint 2<br />
Command is:<br />
CheckCounter<br />
Counter is:<br />
\Processor(_Total)\% Processor Time<br />
Unix:<br />
●<br />
●<br />
check_nrpe<br />
–H -c CheckCounter -a ‘\Processor(_Total)\% Processor Time’<br />
Or if you are on windows:<br />
●<br />
nsclient++ -noboot NRPEClient
(My) Answer<br />
Hopefully you can now connect <br />
OK all counters within bounds.<br />
|'\Processor(_Total)\% processortid'=14.204358
Running <strong>SQL</strong> Queries<br />
perl run.pl <br />
For instance:<br />
perl run.pl “SELECT 1 AS test_col”<br />
Or<br />
perl test.pl "sp_monitor“<br />
Or<br />
perl test.pl "SELECT r.session_id, r.wait_type<br />
AS wait_category, r.wait_type, r.wait_time<br />
FROM sys.dm_exec_requests AS r INNER JOIN
Part 2: The tools of the<br />
Trade<br />
Click to edit Master text styles<br />
Second level<br />
●<br />
Third level<br />
●<br />
Fourth level<br />
●<br />
Fifth level
Useful tools in <strong>SQL</strong> <strong>Server</strong><br />
DML Triggers<br />
Fires T-<strong>SQL</strong> code on table events<br />
PerfMon/SysMon<br />
Listens for hundreds of Windows/<strong>SQL</strong><br />
<strong>Server</strong> events<br />
<strong>SQL</strong> Trace and Profiler<br />
Monitors internal events<br />
Wait States<br />
Tracks system waits (processes waiting<br />
for resources)
DML Triggers<br />
A trigger is a custom “event” which fires when<br />
data changes.<br />
For instance:<br />
You want to be notified when someone does:<br />
●<br />
insert into orders (…)
Monitoring DML Triggers<br />
Nothing “out of the box”.<br />
Can be extended (via external stored<br />
procedures) and submit to for instance NSCA<br />
or what not.<br />
There are probably better/simpler ways unless<br />
you really need this…
Performance Counters<br />
PDH (Performance Data Helper)<br />
A framework with metrics for “various things”<br />
Format:<br />
\Group(Instance)\Metric<br />
●<br />
●<br />
●<br />
Group = “area”<br />
Instance = “instance identifier”<br />
Metric = “value”<br />
\Processor(_Total)\% Processor Time
Performance Viewer<br />
Click to edit Master text styles<br />
Second level<br />
●<br />
Third level<br />
●<br />
Fourth level<br />
●<br />
Fifth level
Monitoring Performance<br />
Two (ish) options:<br />
Counters<br />
PDH Counters<br />
●<br />
nsclient++, nc_net, nsclient, and everything else<br />
WMI (Windows Management Instrumentation)<br />
●<br />
nsclient++ and modern solutions (including<br />
agentless)<br />
Many ways to monitor<br />
We will use nsclient++ for simplicity
<strong>SQL</strong> <strong>Server</strong> Trace Profiler<br />
<strong>SQL</strong> <strong>Server</strong> Profiler shows how <strong>SQL</strong> <strong>Server</strong><br />
resolves queries internally<br />
This allows administrators to see exactly what<br />
statements are submitted to the server and<br />
how the server accesses the database to<br />
return result sets.<br />
Used to find an error or resolve a problem<br />
Not monitor the server
Monitoring Trace Profiler<br />
<br />
<br />
Nothing you should monitor though…<br />
Can be viewed from the database (normal sql)<br />
SELECT TextData, Duration, CPU<br />
<br />
<br />
FROM trace_table_name<br />
WHERE EventClass = 12 AND CPU < (Duration*1000)<br />
Normal way to use it though is from inside the<br />
tool
Wait States<br />
System view with statuses for processes<br />
running<br />
Deprecated in 2005 (and beyond)<br />
Shows;<br />
processes waiting for resources<br />
deadlocks<br />
etc
Monitoring Wait States<br />
Can be viewed from the database (normal sql)<br />
select * from sysprocesses
C2 Auditing<br />
configured through;<br />
<strong>SQL</strong> <strong>Server</strong> Management Studio<br />
c2 audit mode option in sp_configure<br />
the server records both failed and successful<br />
attempts to access statements and objects<br />
Can help profile system activity and track possible<br />
security policy violations<br />
Superseded by Common Criteria Certification
Monitoring C2 Auditing<br />
Nothing out of the box.<br />
Generates “log files” (unsure of format)<br />
Can be viewed from the database (normal sql)<br />
SELECT * FROM ::fn_trace_gettable('C:\Program Files\Microsoft <strong>SQL</strong><br />
<strong>Server</strong>\MS<strong>SQL</strong>\Data\audittrace_20040822191554.trc', default)
Summary<br />
Good stuff:<br />
PerfMon/SysMon<br />
●<br />
System metrics<br />
Wait States<br />
●<br />
<strong>SQL</strong> Process metrics (ish)<br />
Useful:<br />
DML Triggers<br />
●<br />
Database events<br />
Not very usefull (for monitoring):<br />
<strong>SQL</strong> Trace and Profiler
Assignment<br />
<strong>Server</strong> Performance
Task/Question<br />
Do we have a problem
Hint 1<br />
What’s the server CPU load
Hint 2<br />
What’s the server CPU load<br />
Check PDH (counter) object:<br />
\Processor(_Total)\% Processor Time
Hint 3<br />
What’s the server CPU load<br />
Check PDH (counter) object:<br />
\Processor(_Total)\% Processor Time<br />
Use check_nrpe (or NSClient++)<br />
check_nrpe –H -c CheckCounter<br />
●<br />
-a ”\Processor(_Total)\% Processor Time”
(My) Answer<br />
No, but most will say so<br />
Why do you buy that expensive server<br />
●<br />
If not to use it<br />
But beware!<br />
If load increases you will be in trouble!
New tools added in 2005<br />
Common Criteria Compliance<br />
Combines <strong>SQL</strong> Trace and security settings for<br />
compliance<br />
DMVs<br />
dynamic management views, catalog views<br />
(metadata details and current status)<br />
Management Studio Reports<br />
●<br />
easy way to view DMV data<br />
Performance Dashboard<br />
●<br />
downloadable add-on with extra reports
Common Criteria<br />
Builds Compliance<br />
on c2 audit mode and is mainly a<br />
certification thing as I understand it
Monitoring “C3”<br />
I don’t really know :P<br />
But I think it is much same as before…
Dynamic management<br />
Database views views with metrics about server<br />
status<br />
Can be combined with reports to form a nice<br />
monitoring/management view<br />
In short:<br />
This is the god stuff!
Monitoring DMVs<br />
Regular database view (normal sql)<br />
For instance listing waiting sessions<br />
SELECT<br />
r.session_id, r.wait_type AS wait_category, r.wait_type, r.wait_time<br />
FROM sys.dm_exec_requests AS r<br />
INNER JOIN sys.dm_exec_sessions AS s ON r.session_id = s.session_id<br />
WHERE<br />
r.wait_type IS NOT NULL AND s.is_user_process = 0x1
DDL Triggers<br />
Same as DML triggers but for DDL<br />
Can show you;<br />
When/if someone alters the database<br />
(structure)
Monitoring DDL triggers<br />
Same as with DML triggers<br />
Nothing “out of the box”.<br />
Can be extended (via external stored<br />
procedures) and submit to for instance NSCA<br />
or what not.
Summary<br />
Good stuff:<br />
DMVs<br />
●<br />
●<br />
●<br />
Lots of <strong>SQL</strong> <strong>Server</strong> metrics<br />
Really nice reports<br />
Downloadable add-on with extra reports<br />
Somewhat useful:<br />
DDL Triggers<br />
●<br />
Database events<br />
Not very useful (for monitoring):<br />
<strong>SQL</strong> Trace and Profiler
Assignment<br />
Dynamic Management Views
Task/Question<br />
Does the server have a problem<br />
Use your new found skills to diagnose the<br />
system and find any errors and/or problems
Hint 1<br />
Use Dynamic Management Views
Hint 2<br />
Use Dynamic Management Views<br />
For instance:<br />
run_sql<br />
SELECT status, wait_type, wait_time<br />
FROM sys.dm_exec_requests<br />
WHERE wait_type IS NOT NULL<br />
(or)<br />
SELECT<br />
r.session_id, r.wait_type AS wait_category, r.wait_type, r.wait_time<br />
FROM sys.dm_exec_requests AS r<br />
WHERE<br />
INNER JOIN sys.dm_exec_sessions AS s ON r.session_id = s.session_id
(My) Answer<br />
Absolutely!<br />
Now we see we have tasks waiting!<br />
Waiting means slow clients: not good!
More goodies from 2008<br />
Change Tracking<br />
synchronously records which rows have been<br />
updated<br />
Change Data Capture<br />
asynchronously reads T-Log and records data<br />
changes<br />
Extended Events<br />
lightweight windows monitoring technology<br />
(similar to <strong>SQL</strong> Trace Event)<br />
<strong>SQL</strong> Auditing
Part 3: Monitoring<br />
Click to edit Master text styles<br />
Second level<br />
●<br />
Third level<br />
●<br />
Fourth level<br />
●<br />
Fifth level
Monitoring<br />
Existing tools
Existing Nagios scripts<br />
MS<strong>SQL</strong> Job Monitoring<br />
Monitors “scheduled jobs”<br />
Written in java (server)<br />
DBTuna<br />
Some commercial thing<br />
Haven’t checked<br />
check_mssql_nt<br />
Monitors “many things” (w32 binary)<br />
Written in debian (called via nrpe)
Existing Nagios scripts<br />
check mssql databases status by snmp<br />
Queries status via snmp<br />
Check MS<strong>SQL</strong> Database Mirroring<br />
Queries specific tables (sys schema)<br />
Written in perl<br />
check_mssql_health<br />
Queries many aspects of the server<br />
Written in perl<br />
check_mssql_write.py
Existing Nagios scripts<br />
check_mssql_sproc<br />
Monitors “things” by executing a procedure<br />
Written in perl<br />
check_mssql_monitor<br />
Wrapper for sp_monitor<br />
Written in perl<br />
check_sql<br />
Runs various queries and checks various things<br />
Written in perl
Existing Nagios scripts<br />
Best ones:<br />
check_sql<br />
Good ones:<br />
check_sql<br />
Check MS<strong>SQL</strong> Database Mirroring<br />
check_mssql_health<br />
check_mssql_write.py<br />
check_mssql_sproc<br />
check_mssql_monitor
WARNING!<br />
If you are using ODBC<br />
check_sql is sort of broken (I think) <br />
At least I do this to connect<br />
my $cs = "DBI:$driver:$hostname";<br />
#my $cs = "DBI:$driver:" . ($database "database=$database;" : '') .<br />
"host=$hostname" . ($port ";port=$port" : '');<br />
But I am not a Perl DBI expert…
Don’t do this from<br />
There are nice tools to work with this…<br />
“Nagios”<br />
use them…<br />
Ask you DBA and your developers<br />
They know what requires monitoring<br />
Don’t believe there is a “boxed solution”<br />
There seldom is<br />
Don’t “finish” once the server is monitored.<br />
Monitor your application as well!<br />
Don’t forget “non-events”
Assignment<br />
Existing scripts
Task/Question<br />
Use check_sql to check that<br />
select count(*) from orders is 0
Hint 1<br />
perl check_sql -h
Hint 2<br />
perl check_sql -h<br />
perl check_sql<br />
-H osmc -d ODBC -U osmc -P osmc<br />
●<br />
-q "select count(*) from orders“<br />
●<br />
-e 0
(My) Answer<br />
Hopefully it worked out…
Monitoring<br />
Performance Counters
A few Good Counters<br />
IO<br />
Pages / second<br />
●<br />
\Memory\Pages/sec<br />
Physical disk time<br />
●<br />
\PhysicalDisk(_Total)\% Disk Time<br />
Database files:<br />
Database file size<br />
●<br />
\<strong>SQL</strong><strong>Server</strong>:Databases()\Data File(s) Size (KB)<br />
Database log file size<br />
●<br />
\<strong>SQL</strong><strong>Server</strong>:Databases()\Log File(s) Size (KB)
Monitoring<br />
DMVs
Dynamic Management<br />
dm_db_*:<br />
Views<br />
Databases and database objects<br />
dm_exec_*:<br />
Execution of user code and associated<br />
connections<br />
dm_os_*:<br />
Memory, locking, and scheduling<br />
dm_tran_*:<br />
Transactions and isolation
A few good DMVs<br />
CPU<br />
sys.dm_exec_query_stats<br />
Memory:<br />
sys.dm_os_sys_info<br />
I/O:<br />
sys.dm_os_wait_stats<br />
Blocked sessions:<br />
sys.dm_os_waiting_tasks<br />
Technet link with sample queries:
Monitoring<br />
The art of stealing...
Remember, remember,<br />
…the fifth of november<br />
One of the best things about DVM:<br />
..are the reports…<br />
●<br />
Management Studio Reports<br />
– easy way to view DMV data<br />
●<br />
Performance Dashboard<br />
– downloadable add-on with extra reports<br />
These are premade reports with a nice gui<br />
●<br />
●<br />
Something like what your “friends” with that “big expensive<br />
alternative” to OSS keep selling right<br />
Why not steal it
Management Studio<br />
Are;<br />
Reports<br />
XML files (*.rdl)<br />
With predefined queries (good)<br />
And a lot of nice boxes and what not (crappy)<br />
Look for:<br />
//DataSets/DataSet<br />
Or if you prfer:<br />
●<br />
<br />
–
Assignment<br />
Dissecting a report
Task/Question<br />
Open a report and steal the query…<br />
For instance the historical_io.rdl report
Hint 1<br />
The PDB (Performance Dash Board) folder has<br />
the reports…
Hint 2<br />
The PDB (Performance Dash Board) folder has<br />
the reports…<br />
The file I called historical_io.rdl
Hint 3<br />
The PDB (Performance Dash Board) folder has<br />
the reports…<br />
The file I called historical_io.rdl<br />
Look for DataSet (and then Query)
Hint 4<br />
The PDB (Performance Dash Board) folder has<br />
the reports…<br />
The file I called historical_waits.rdl<br />
Look for DataSet (and then Query)<br />
No it is not CHECK_DEPENDENCIES
(My) Answer<br />
Master thief I dub thee
Monitoring<br />
Applications
Applications!<br />
Dont forget to monitor your applications<br />
Check that tables and columns are ”writable”<br />
Check that counts (rows)<br />
Check that new rows ”are coming”<br />
●<br />
(recent item count)<br />
Check that ”things” work.<br />
Talk to your DBA and developers!
Assignment<br />
Monitoring my order system
Task/Question<br />
Create a query which makes sure that orders<br />
are coming in<br />
For instance:<br />
Select count(*) from orders<br />
●<br />
●<br />
(in real life you probably want;<br />
– WHERE order_date > DATEADD(DD,-<br />
1,CONVERT(CHAR(8),CURRENT_TIMESTAMP,112))<br />
Or something similar)
Hint 1<br />
Use the “run.pl” perl script
Hint 2<br />
Use the “run.pl” perl script<br />
perl run.pl "select count(*) from orders"
(My) Answer<br />
Whoops… we are not gonna be rich afterall
Part 4: Scripting<br />
Click to edit Master text styles<br />
Second level<br />
●<br />
Third level<br />
●<br />
Fourth level<br />
●<br />
Fifth level
Client or <strong>Server</strong> side<br />
<strong>Server</strong> side;<br />
Remote access from the monitoring server<br />
Requires more ”firewall openings”<br />
More configuration server side<br />
Your DBA might disprove<br />
Client side;<br />
Local access to <strong>SQL</strong> <strong>Server</strong> (remote access to agent)<br />
Requires less firewall openings<br />
●<br />
And you probably require this anyway<br />
More configuration client side<br />
More work ”distributing” your scripts
Which language (<strong>Server</strong><br />
Perl is a good candidate<br />
side)<br />
Support <strong>SQL</strong> queries<br />
Fairly simple driver handling (via ODBC)<br />
Has “helpers” for database access<br />
What we have been using all this time<br />
Most languages can be used though<br />
Used by various existing scripts<br />
●<br />
●<br />
Python, PHP<br />
Java (but it has a very high overhead)
Which language (Client<br />
Perl is (still) a good candidate<br />
side)<br />
Makes your compatible<br />
Requires installation (ActiveState or similar)<br />
VB is a popular choice<br />
With the Library from op5 you get much “for free”<br />
PowerShell<br />
Probably your best bet if you wanna do cool stuff<br />
Many other choices as well
Perl (Client side)<br />
The good;<br />
Support <strong>SQL</strong> queries<br />
Fairly simple driver handling (via ODBC)<br />
Has “helpers” for database access<br />
Makes your compatible<br />
The bad;<br />
Requires installation (ActiveState or similar)<br />
Some issues with 64bit and databases<br />
●<br />
Requires the SAME as the ODBC libraries
VB (VisualBasic)<br />
The good;<br />
Support <strong>SQL</strong> queries - <br />
Simple driver handling - <br />
Has helpers “Nagios API”<br />
Can do a lot of “other things”<br />
●<br />
Ie. a “check_all” is possible<br />
The bad;<br />
No “Nagios API” available<br />
Script will not run on Linux
PowerShell<br />
The good;<br />
Support <strong>SQL</strong> queries<br />
Simple driver handling<br />
Has helpers for database (<strong>SQL</strong>) access<br />
Can (re)configure the database<br />
The bad;<br />
Somewhat arcane syntax<br />
No “Nagios API” available<br />
Script will not run on Linux
Just a quick PowerShell<br />
<strong>SQL</strong> <strong>Server</strong> Management Objects (SMO)<br />
slide<br />
Replication Management Objects (RMO)<br />
Analysis Services Management Objects (AMO)
Click to edit Master text styles<br />
Second level<br />
●<br />
Third level<br />
●<br />
Fourth level<br />
●<br />
Fifth level
Thank You!<br />
Michael Medin<br />
michael@medin.name<br />
http://www.linkedin.com/in/mickem<br />
Information about NSClient++<br />
http://nsclient.org<br />
Slides, and examples at: