Dochazka Code
Generic attendance/time tracking system
Status: Pre-Alpha
Brought to you by:
smithfarm
NAME
App::Dochazka::REST - Dochazka REST server
VERSION
Version 0.145
Development status
Dochazka is currently a Work In Progress (WIP). Do not expect it to do
anything useful.
SYNOPSIS
This is the top-level module of the Dochazka REST server.
use App::CELL qw( $CELL $log $meta $site );
use App::Dochazka::REST;
use Carp;
my $REST = App::Dochazka::REST->init( sitedir => '/etc/dochazka' );
croak( $REST->{init_status}->text ) unless $REST->{init_status}->ok;
Read on for documentation.
DESCRIPTION
This is `App::Dochazka::REST', the Perl module that implements the REST
interface, data model, and underlying database of Dochazka, the
open-source Attendance/Time Tracking (ATT) system.
Dochazka as a whole aims to be a convenient, open-source ATT solution.
Its reference implementation runs on the Linux platform.
Dochazka architecture
There is more to Dochazka than `App::Dochazka::REST', of course.
Dochazka REST is the "server component" of Dochazka, consisting of a
Plack/PSGI web server (implemented using Web::Machine) and a data model.
Once `App::Dochazka::REST' is installed, configured, and running, a
client will be need in order to actually use Dochazka.
Though no client yet exists, two are planned: a command-line interface
(App::Dochazka::CLI) and a web front-end (App::Dochazka::WebGUI).
Stand-alone report generators and other utilities that may or may not
ever be implemented can also be thought of as clients.
REST INTERFACE
App::Dochazka::REST attempts to present a *REST*ful interface to
potential clients. To learn more about REST, its meaning and
implications, see ....
One of those implications is that clients communicate with the server
using the HTTP protocol, which is described ....
Basic parameters
UTF-8
The server assumes all incoming requests are encoded in UTF-8, and it
encodes all of its responses in UTF-8 as well.
HTTP(S)
In order to protect user passwords from network sniffing and other
nefarious activities, the server may be set up to accept HTTPS requests
only. Such a setup may use a reverse proxy or a dedicated SSL-capable
server. Since HTTP-over-SSL is a complex topic, this document ignores it
by assuming that all client-server communications take place in plain
text. If this bothers you, you can read all occurrences of 'HTTP' in
this document as meaning 'HTTP and/or HTTPS'.
Self-documenting
Another implication of REST is that the server provides "resources" and
that those resources are, to some extent at least, self-documenting.
App::Dochazka::REST provides 'help' resources whose only purpose is to
provide information about the resources available to the client at a
particular base level. For example, the top-level help resource provides
a list of resources available at that level, some of which are
lower-level 'help' resources.
For each resource, the 'help' resource provides a 'link' attribute with
the full URI of the resource and a 'description' attribute with a terse
description of what the resource is good for.
Exploring the server
With a web browser
Only some of App::Dochazka::REST's resources (i.e, those that use the
GET method) are accessible using a web browser. That said, if we are
only interested in displaying information from the database, GET
requests are all we need and using a web browser can be convenient.
To start exploring, fire up a standard web browser and point it to the
base URI of your App::Dochazka::REST installation:
http://dochazka.site
and entering one's credentials in the Basic Authentication dialog.
With a command-line HTTP client
To access all the resources, you will need a client that is capable of
generating POST, PUT, and DELETE requests as well as GET requests. Also,
since some of the information App::Dochazka::REST provides is in the
response headers, the client needs to be capable of displaying those as
well.
One such client is Daniel Stenberg's curl.
In the HTTP request, the client may provide an `Accept:' header
specifying either HTML (`text/html') or JSON (`application/json'). For
the convenience of those using a web browser, HTML is the default.
Here are some examples of how to use curl (or a web browser) to explore
resources. These examples assume a vanilla installation of
App::Dochazka::REST with the default root password. The same commands
can be used with a production server, but keep in mind that the
resources you will see may be limited by your ACL privilege level.
* GET resources
The GET method is used to search for and display information. The
top-level GET resources are listed at the top-level URI, either
using curl
$ curl -v -H 'Accept: application/json' http://demo:demo@dochazka.site/
Similarly, to display a list of sub-resources under the
'privhistory' top-level resource, enter the command:
$ curl http://demo:demo@dochazka.site/employee -H 'Accept: application/json'
Oops - no resources are displayed because the 'demo' user has only
passerby privileges, but all the privhistory resources require at
least 'active'. To see all the available resources, we can
authenticate as 'root':
$ curl http://root:immutable@dochazka.site/employee -H 'Accept: application/json'
* POST resources
With the GET method, we could only access resources for finding and
displaying information: we could not add, change, or delete
information. For that we will need to turn to some other client than
the web browser -- a client like curl that is capable of generating
HTTP requests with methods like POST, PUT and DELETE.
Here is an example of how we would use curl to display the top-level
POST resources:
curl -v http://root:immutable@dochazka.site -X POST -H "Content-Type: application/json"
The "Content-Type: application/json" header is necessary because the
server only accepts JSON in the POST request body -- even though in
this case we did not send a request body, most POST requests will
have one. For best results, the request body should be a legal JSON
string represented as a sequence of bytes encoded in UTF-8.
* PUT resources
The PUT method is used to . . .
PUT resources can be explored using a curl command analogous to the
one given for the POST method.
* DELETE resources
Any time we need to delete information -- i.e., completely wipe it
from the database, we will need to use the DELETE method.
DELETE resources can be explored using a curl command analogous to
the one given for the POST method.
Keep in mind that the data integrity constraints in the underlying
PostgreSQL database may make it difficult to delete a resource if
any other resources are linked to it. For example, an employee
cannot be deleted until all intervals, privhistory records,
schedhistory records, locks, etc. linked to that employee have been
deleted. Intervals, on the other hand, can be deleted as long as
they are not subject to a lock.
Request-response cycle
Incoming HTTP requests are handled by App::Dochazka::REST::Resource,
which inherits from Web::Machine::Resource. The latter uses Plack to
implement a PSGI-compliant stack.
Web::Machine takes a "state-machine" approach to implementing the HTTP
1.1 standard. Requests are processed by running them through a state
machine, each "cog" of which is a Web::Machine::Resource method that can
be overridden by a child module. In our case, this module is
App::Dochazka::REST::Resource.
The behavior of the resulting web server can be characterized as
follows:
* Allowed methods test
One of the first things the server looks at, when it receives a
request, is the method. Only certain HTTP methods, such as 'GET' and
'POST', are accepted. If this test fails, a "405 Method Not Allowed"
response is sent.
* Internal and external authentication
After the Allowed methods test, the request is subject to HTTP Basic
Authentication. The credentials entered by the user can be
authenticated against an external database (LDAP), an internal
database (PostgreSQL 'employees' table), or both. For details, see
"AUTHENTICATION". If authentication fails, a "401 Unauthorized"
response is sent. This should not be confused with the next step
("Authorization/ACL check").
In a web browser, repeated failed authentication attempts are
typically associated with repeated display of the credentials dialog
(and no other indication of what is wrong, which can be confusing to
users but is probably a good idea, because any error messages could
be abused by attackers).
* Authorization/ACL check
After the request is authenticated (i.e. associated with a known
employee), the server examines the resource being requested and
compares it with the employee's privilege level. If the privilege
level is too low for the requested operation, a "403 Forbidden"
response is sent.
* Test for resource existence
The next test a request undergoes on its quest to become a response
is the test of resource existence. If the request is asking for a
non-existent resource, e.g. http://dochazka.site/employee/curent, it
cannot be fulfilled and a "404 Not Found" response will be sent.
For GET requests, this is the last cog in the state machine: if the
test passes, a "200 OK" response is sent, along with a response
body. Requests using other methods (POST, PUT, DELETE) are subject
to further processing as described below.
Additional processing (POST and PUT)
Because they are expected to have a request body, incoming POST and PUT
requests are subject to the following additional test:
* malformed_request
This test examines the request body. If it is non-existent, the test
passes. If the body exists and is valid JSON, the test passes.
Otherwise, it fails.
* known_content_type
Test the request for the 'Content-Type' header. POST and PUT
requests should have a header that says:
Content-Type: application/json
If this header is not present, a "415 Unsupported Media Type"
response is sent.
Additional processing (POST)
* post_is_create
This test examines the POST request and places it into one of two
categories: (1) generic request for processing, (2) a request that
creates or otherwise manipulates a resource.
# FIXME: more verbiage needed
DATA MODEL
This section describes the `App::Dochazka::REST' data model.
Conceptually, Dochazka data can be seen to exist in the following
classes of objects:
* Policy (parameters set when database is first created)
* Employee (an individual employee)
* Privhistory (history of changes in an employee's privilege level)
* Schedule (a schedule)
* Schedhistory (history of changes in an employee's schedule)
* Activities (what kinds of work are recognized)
* Intervals ("work", "attendance", and/or "time tracked")
* Locks (determining whether a reporting period is locked or not)
These classes are described in the following sections.
Policy
Dochazka is configurable in a number of ways. Some configuration
parameters are set once at installation time and, once set, can never be
changed -- these are referred to as "site policy" parameters. Others,
referred to as "site configuration parameters" or "site params", are set
in configuration files such as `Dochazka_SiteConfig.pm' (see SITE
CONFIGURATION) and can be changed more-or-less at will.
The key difference between site policy and site configuration is that
site policy parameters cannot be changed, because changing them would
compromise the referential integrity of the underlying database.
Site policy parameters are set at installation time and are stored, as a
single JSON string, in the `SitePolicy' table. This table is rendered
effectively immutable by a trigger.
For details, see App::Dochazka::REST::Model::Policy.
Employee
Users of Dochazka are referred to as "employees" regardless of their
legal status -- in reality they might be independent contractors, or
students, or even household pets, but as far as Dochazka is concerned
they are employees. You could say that "employee" is the Dochazka term
for "user".
Employees are distinguished by an internal employee ID number (EID),
which is assigned by Dochazka itself when the employee record is
created. For the convenience of humans using the system, employees are
also distinguished by a unique nickname, or 'nick'.
Other than the EID and the nick, which are required, Dochazka need not
record any other employee identification data. That said, Dochazka has
two additional employee identification fields (fullname, email), which
some sites may wish to use, but these are optional and can be left
blank. Dochazka does not verify the contents of these fields other than
enforcing a UNIQUE constraint to ensure that two or more employees
cannot have the exact same fullname or email address.
For details, see App::Dochazka::REST::Model::Employee.
Privhistory
Dochazka has four privilege levels: `admin', `active', `inactive', and
`passerby':
* `admin' -- employee can view, modify, and place/remove locks on her
own attendance data as well as that of other employees; she can also
administer employee accounts and set privilege levels of other employees
* `active' -- employee can view her own profile, attendance data, modify
her own unlocked attendance data, and place locks on her attendance data
* `inactive' -- employee can view her own profile and attendance data
* `passerby' -- employee can view her own profile
Dochazka's `privhistory' object is used to track changes in an
employee's privilege level over time. Each time an employee's privilege
level changes, a Dochazka administrator (i.e., an employee whose current
privilege level is 'admin'), a record is inserted into the database (in
the `privhistory' table). Ordinary employees (i.e. those whose current
privilege level is 'active') can read their own privhistory.
Thus, with Dochazka it is possible not only to determine not only an
employee's current privilege level, but also to view "privilege
histories" and to determine employees' privilege levels for any date
(timestamp) in the past.
For details, see App::Dochazka::REST::Model::Privhistory and When
history changes take effect.
Schedule
In addition to actual attendance data, Dochazka sites may need to store
schedules. Dochazka defines the term "schedule" as a series of
non-overlapping "time intervals" (or "timestamp ranges" in PostgreSQL
terminology) falling within a single week. These time intervals express
the times when the employee is "expected" or "supposed" to work (or be
"at work") during the scheduling period.
Example: employee "Barb" is on a weekly schedule. That means her
scheduling period is "weekly" and her schedule is an array of
non-overlapping time intervals, all falling within a single week.
In its current form, Dochazka is only capable of handling weekly
schedules only. Some sites, such as hospitals, nuclear power plants,
fire departments, and the like, might have employees on more complicated
schedules such as "one week on, one week off", alternating day and night
shifts, "on call" duty, etc.
Dochazka can still be used to track attendance of such employees, but if
their work schedule cannot be expressed as a series of non-overlapping
time intervals contained within a contiguous 168-hour period (i.e. one
week), then their Dochazka schedule should be set to NULL.
For details, see App::Dochazka::REST::Model::Schedule.
Schedhistory
The `schedhistory' table contains a historical record of changes in the
employee's schedule. This makes it possible to determine an employee's
schedule for any date (timestamp) in the past, as well as (crucially)
the employee's current schedule.
Every time an employee's schedule is to change, a Dochazka administrator
must insert a record into this table. (Employees who are not
administrators can only read their own history; they do not have write
privileges.) For more information on privileges, see AUTHORIZATION.
For details, see App::Dochazka::REST::Model::Schedhistory.
Activity
While on the job, employees "work" -- i.e., they engage in various
activities that are tracked using Dochazka. The `activities' table
contains definitions of all the possible activities that may be entered
in the `intervals' table.
The initial set of activities is defined in the site install
configuration (`DOCHAZKA_ACTIVITY_DEFINITIONS') and enters the database
at installation time. Additional activities can be added later (by
administrators), but activities can be deleted only if no intervals
refer to them.
Each activity has a code, or short name (e.g., "WORK") -- which is the
primary way of referring to the activity -- as well as an optional long
description. Activity codes must be all upper-case.
For details, see App::Dochazka::REST::Model::Activity.
Interval
Intervals are the heart of Dochazka's attendance data. For Dochazka, an
interval is an amount of time that an employee spends doing an activity.
In the database, intervals are represented using the `tsrange' range
operator introduced in PostgreSQL 9.2.
Optionally, an interval can have a `long_desc' (employee's description
of what she did during the interval) and a `remark' (admin remark).
For details, see App::Dochazka::REST::Model::Interval.
Lock
In Dochazka, a "lock" is a record in the "locks" table specifying that a
particular user's attendance data (i.e. activity intervals) for a given
period (tsrange) cannot be changed. That means, for intervals in the
locked tsrange:
* existing intervals cannot be updated or deleted
* no new intervals can be inserted
Employees can create locks (i.e., insert records into the locks table)
on their own EID, but they cannot delete or update those locks (or any
others). Administrators can insert, update, or delete locks at will.
How the lock is used will differ from site to site, and some sites may
not even use locking at all. The typical use case would be to lock all
the employee's attendance data within the given period as part of
pre-payroll processing. For example, the Dochazka client application may
be set up to enable reports to be generated only on fully locked
periods.
"Fully locked" means either that a single lock record has been inserted
covering the entire period, or that the entire period is covered by
multiple locks.
Any attempts (even by administrators) to enter activity intervals that
intersect an existing lock will result in an error.
Clients can of course make it easy for the employee to lock entire
blocks of time (weeks, months, years . . .) at once, if that is deemed
expedient.
For details, see App::Dochazka::REST::Model::Lock.
CAVEATS
Weekly schedules only
Unfortunately, the weekly scheduling period is hard-coded at this time.
Dochazka does not care what dates are used to define the intervals --
only that they fall within a contiguous 168-hour period. Consider the
following contrived example. If the scheduling intervals for EID 1 were
defined like this:
"[1964-12-30 22:05, 1964-12-31 04:35)"
"[1964-12-31 23:15, 1965-01-01 03:10)"
for Dochazka that would mean that the employee with EID 1 has a weekly
schedule of "WED/22:05-THU/04:35" and "THU/23:15-FRI/03:10", because the
dates in the ranges fall on a Wednesday (1964-12-30), a Thursday
(1964-12-31), and a Friday (1964-01-01), respectively.
When history changes take effect
The `effective' field of the `privhistory' and `schedhistory' tables
contains the effective date/time of the history change. This field takes
a timestamp, and a trigger ensures that the value is evenly divisible by
five minutes (by rounding). In other words,
'1964-06-13 14:45'
is a valid `effective' timestamp, while
'2014-01-01 00:00:01'
will be rounded to '2014-01-01 00:00'.
INSTALLATION
Installation is the process of creating (setting up, bootstrapping) a
new Dochazka instance, or "site" in Dochazka terminology.
It entails the following steps:
* Server preparation
Dochazka REST needs hardware (either physical or virtualized) to run
on. The hardware will need to have a network connection, etc.
Obviously, this step is entirely beyond the scope of this document.
* Software installation
Once the hardware is ready, the Dochazka REST software and all its
dependencies are installed on it. This could be accomplished by
downloading and unpacking the tarball (or running `git clone') and
following the installation instructions, or, more expediently, by
installing a packaged version of Dochazka REST if one is available
(see
https://build.opensuse.org/package/show/home:smithfarm/perl-App-Doch
azka-REST).
* PostgreSQL setup
One of Dochazka REST's principal dependencies is PostgreSQL server
(version 9.2 or higher). This needs to be installed (should happen
automatically when using the packaged version of
App::Dochazka::REST). Steps to enable it:
bash# chkconfig postgresql on
bash# systemctl start postgresql.service
bash# su - postgres
bash$ psql postgres
postgres-# ALTER ROLE postgres WITH PASSWORD 'mypass';
ALTER ROLE
At this point, we exit `psql' and, still as the user `postgres', we
edit `pg_hba.conf'. Using our favorite editor, we change the METHOD
entry for `local' so it looks like this:
# TYPE DATABASE USER ADDRESS METHOD
local all all password
Then, as root, we restart the postgresql service:
bash# systemctl restart postgresql.service
* Site configuration
Before the Dochazka REST database can be initialized, we will need
to tell App::Dochazka::REST about the PostgreSQL superuser password
that we set in the previous step. This is done via a site parameter.
There may be other site params we will want to set, but the
following is sufficient to run the test suite.
First, create a sitedir:
bash# mkdir /etc/dochazka
and, second, a file therein:
# cat << EOF > /etc/dochazka/Dochazka_SiteConfig.pm
set( 'DBINIT_CONNECT_AUTH', 'mypass' );
EOF
#
(NOTE: Strictly speaking, this sitedir setup is only needed for
database initialization. During normal operation,
App::Dochazka::REST connects to the database using the default user
`dochazka' and password `dochazka'. These are taken from the site
parameters `DOCHAZKA_DBUSER' and `DOCHAZKA_DBPASS'.)
* Syslog setup
It is much easier to administer a Dochazka instance if `syslog' is
running and configured properly to place Dochazka's log messages
into a separate file in a known location. In the future,
App::Dochazka::REST might provide a `syslog_test' script to help the
administrator complete this step.
* Database initialization
In the future, there might be a nifty `dochazka-dbinit' script to
make this process less painful, but for now the easiest way to
initialize the database is to clone the git repo from SourceForge
and run the test suite:
bash# cd ~/src
bash# git clone git://git.code.sf.net/p/dochazka/code dochazka
...
bash# cd dochazka
bash# perl Build.PL
bash# ./Build test
Assuming the previous steps were completed correctly, all the tests
should complete without errors.
* Start the server
The last step is to start the Dochazka REST service. Maybe, in the
future, this will be possible using a command like `systemctl start
dochazka.service'. Right now, though, an executable is run, as root,
manually from the bash prompt:
bash# dochazka-rest --host [HOST] --port 80 --access-log /var/log/dochazka-rest.log
or, as any user:
bash$ dochazka-rest
* Take it for a spin
Point your browser to the hostname you entered in the previous step,
or to http://0:5000/ if you didn't enter a hostname.
The above procedure only includes the most basic steps. Sites with
reverse proxies, firewalls, load balancers, connection pools, etc. will
need to set those up, as well.
AUTHENTICATION
Since employees do not access the database directly, but only via the
`App::Dochazka::REST' web server, the web server needs to tie all
incoming requests to an EID.
All incoming requests are subject to HTTP Basic Authentication. The
credentials entered by the user can be authenticated against an external
database (LDAP), and internal database (PostgreSQL 'employees' table),
or both.
This yields the following possible combinations: internal auth only,
external auth only, internal auth followed by external auth, and
external auth followed by internal auth. The desired combination can be
set in the site configuration.
Current implementation
At the moment, this is accomplished via Web::Machine using HTTP Basic
Authentication with a single hardcoded username/password combination
`demo/demo'.
This allows us to use, e.g., `curl' like this:
$ curl http://demo:demo@0:5000/
Possible future implementation
This is done when the session is established (see Session management).
In the site configuration, the administrator associates an LDAP field
with either EID or nick. When an employee initiates a session by
contacting the server, `App::Dochazka::REST' first looks up the employee
in the LDAP database and determines her EID, either directly or via the
employee's nick. If the EID is valid, the password entered by the
employee is checked against the password stored in the LDAP database.
Alternatively, `App::Dochazka::REST' can be configured to authenticate
employees against passwords stored in the Dochazka database.
When the REST server registers an incoming request, it first checks to
see if it is associated with an active session. If it is, the request is
processed. If it is not, the incoming request is authenticated.
Authentication consists of:
* a check against Dochazka's own list (database) of employees
* an optional, additional check against an LDAP database
Depending on how the REST server is configured, one of these will
include a password check. The server will send the client a session key,
etc.
REPORTING
Reporting is a core functionality of Dochazka: for most sites, the
entire point of keeping attendance records is to generate reports, at
regular (or irregular) intervals, based on those records. One obvious
use case for such reports is payroll.
That said, the REST server and its underlying database are more-or-less
"reporting neutral". In other words, care was taken to make them as
general as possible, to enable Dochazka to be useful in many different
site and reporting scenarios.
Thus, in Dochazka a report generator is always implemented either a
separate client or as part of a client. Never as part of the server.
METHODS
init
Load site configuration, set up logging, and connect to the database.
init_no_db
Load site configuration and set up logging. Intended for use from the
`init' method as well as from App::Dochazka::REST unit tests that need
to connect to the pristine database using `connect_db_pristine'.
Takes an optional PARAMHASH which is passed to `$CELL->load'. The
App::Dochazka::REST distro sharedir is loaded as the first sitedir,
before any sitedir specified in the PARAMHASH is loaded. Call examples:
my $status = $REST->init_no_db;
my $status = $REST->init_no_db( verbose => 1 );
my $status = $REST->init_no_db( sitedir => '/etc/fooapp' );
connect_db_pristine
Connect to a pristine database. This function should be used only for
newly created databases. Takes a PARAMHASH with 'dbname', 'dbuser', and
'dbpass'. For username and password, DBINIT_CONNECT_USER and
DBINIT_CONNECT_AUTH are used. Returns status object which, on success,
will contain the database handle in the payload.
connect_db
Connect to a pre-initialized database and initialize site params. This
is the function that should be used in production. Database name,
username and password are taken from DOCHAZKA_DBNAME, DOCHAZKA_DBUSER
and DOCHAZKA_DBPASS, respectively.
reset_db
Drop and re-create a Dochazka database. Takes database name. Do not call
when connected to an existing database. Be very, _very_, _VERY_ careful
when calling this function.
create_tables
Takes a database handle, on which it executes all the SQL statements
contained in DBINIT_CREATE param.
eid_of_root
Instance method. Returns EID of the 'root' employee.
GLOSSARY OF TERMS
In Dochazka, some commonly-used terms have special meanings:
* employee -- Regardless of whether they are employees in reality, for
the purposes of Dochazka employees are the folks whose attendance/time
is being tracked. Employees are expected to interact with Dochazka using
the following functions and commands.
* administrator -- In Dochazka, administrators are employees with
special powers. Certain REST/CLI functions are available only to
administrators.
* CLI client -- CLI stands for Command-Line Interface. The CLI client is
the Perl script that is run when an employee types `dochazka' at the
bash prompt.
* REST server -- REST stands for ... . The REST server is a collection
of Perl modules running on a server at the site.
* site -- In a general sense, the "site" is the company, organization,
or place that has implemented (installed, configured) Dochazka for
attendance/time tracking. In a technical sense, a site is a specific
instance of the Dochazka REST server that CLI clients connect to.
AUTHOR
Nathan Cutler, `<presnypreklad@gmail.com>'
BUGS
Please report any bugs or feature requests to `bug-dochazka-rest at
rt.cpan.org', or through the web interface at
http://rt.cpan.org/NoAuth/ReportBug.html?Queue=App-Dochazka-REST. The
author will be notified, and then you'll automatically be notified of
progress on your bug as he makes changes.
SUPPORT
The full documentation comes with the distro, and can be comfortable
perused at metacpan.org:
https://metacpan.org/pod/App::Dochazka::REST
You can also read the documentation for individual modules using the
perldoc command, e.g.:
perldoc App::Dochazka::REST
perldoc App::Dochazka::REST::Model::Activity
Other resources:
* RT: CPAN's request tracker (report bugs here)
http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Dochazka-REST
* AnnoCPAN: Annotated CPAN documentation
http://annocpan.org/dist/App-Dochazka-REST
LICENSE AND COPYRIGHT
Copyright (c) 2014, SUSE LLC All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SUSE LLC nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.