Package uptimerobot. October 22, 2015



Similar documents
Package retrosheet. April 13, 2015

Package OECD. R topics documented: January 17, Type Package Title Search and Extract Data from the OECD Version 0.2.

Package searchconsoler

Package TSfame. February 15, 2013

Package urltools. October 11, 2015

Package sjdbc. R topics documented: February 20, 2015

Package pinnacle.api

Package sendmailr. February 20, 2015

Package WikipediR. January 13, 2016

Package dsmodellingclient

Package AzureML. August 15, 2015

Package cgdsr. August 27, 2015

Package dsstatsclient

Package R4CDISC. September 5, 2015

Package jrvfinance. R topics documented: October 6, 2015

Package RCassandra. R topics documented: February 19, Version Title R/Cassandra interface

Cloud Elements ecommerce Hub Provisioning Guide API Version 2.0 BETA

orrelog SNMP Trap Monitor Software Users Manual

Package packrat. R topics documented: March 28, Type Package

Package bizdays. March 13, 2015

SnapLogic Salesforce Snap Reference

Package tagcloud. R topics documented: July 3, 2015

Package httprequest. R topics documented: February 20, 2015

Package benford.analysis

Wave Analytics Data Integration

Package translater. R topics documented: February 20, Type Package

THE CHALLENGE OF ADMINISTERING WEBSITES OR APPLICATIONS THAT REQUIRE 24/7 ACCESSIBILITY

Package hive. July 3, 2015

Package pdfetch. R topics documented: July 19, 2015

Package empiricalfdr.deseq2

Package fimport. February 19, 2015

Coveo Platform 7.0. Oracle Knowledge Connector Guide

VMware vcenter Log Insight User's Guide

IBM Tivoli Composite Application Manager for Microsoft Applications: Microsoft Internet Information Services Agent Version Fix Pack 2.

Wave Analytics External Data API Developer Guide

Informatica Cloud Connector for SharePoint 2010/2013 User Guide

API Reference Guide. API Version 1. Copyright Platfora 2016

Package brewdata. R topics documented: February 19, Type Package

API Endpoint Methods NAME DESCRIPTION GET /api/v4/analytics/dashboard/ POST /api/v4/analytics/dashboard/ GET /api/v4/analytics/dashboard/{id}/ PUT

Package HadoopStreaming

Package LexisPlotR. R topics documented: April 4, Type Package

Package erp.easy. September 26, 2015

Programming Autodesk PLM 360 Using REST. Doug Redmond Software Engineer, Autodesk

Package missforest. February 20, 2015

Deploying Microsoft Operations Manager with the BIG-IP system and icontrol

Cloud Elements! Marketing Hub Provisioning and Usage Guide!

Package RIGHT. March 30, 2015

VMware vcenter Log Insight User's Guide

vcloud Air Platform Programmer's Guide

e11 Help Desk User Manual

VoIP Probe 3.4. Functions, Parameters & Metrics for integration with HP Business Availability Center via HP Business Process Monitor

CLC Server Command Line Tools USER MANUAL

There are numerous ways to access monitors:

Package decompr. August 17, 2016

Data Mailbox. support.ewon.biz. Reference Guide

Package hive. January 10, 2011

NewsletterAdmin 2.4 Setup Manual

Package neuralnet. February 20, 2015

HireDesk API V1.0 Developer s Guide

The ECL Scheduler. Boca Raton Documentation Team

Manage Workflows. Workflows and Workflow Actions

Napster and Gnutella: a Comparison of two Popular Peer-to-Peer Protocols. Anthony J. Howe Supervisor: Dr. Mantis Cheng University of Victoria

Analytics Configuration Reference

Field Properties Quick Reference

SAP InfiniteInsight Explorer Analytical Data Management v7.0

SRFax Fax API Web Services Documentation

DiskPulse DISK CHANGE MONITOR

Sample- for evaluation purposes only. Advanced Crystal Reports. TeachUcomp, Inc.

Package hoarder. June 30, 2015

Package date. R topics documented: February 19, Version Title Functions for handling dates. Description Functions for handling dates.

Getting Started with STATISTICA Enterprise Programming

AusCERT Remote Monitoring Service (ARMS) User Guide for AusCERT Members

Package RedditExtractoR

Package TimeWarp. R topics documented: April 1, 2015

Availability Monitoring using Http Ping

Creating SOAP and REST Services and Web Clients with Ensemble

New Mexico State University. AiM 8.X Basic AiM

PageR Enterprise Monitored Objects - AS/400-5

Windows Scheduled Task and PowerShell Scheduled Job Management Pack Guide for Operations Manager 2012

Package franc. R topics documented: November 12, Title Detect the Language of Text Version 1.1.1

Package changepoint. R topics documented: November 9, Type Package Title Methods for Changepoint Detection Version 2.

WNMS Mobile Application

Infinitel HotSpotWeb User Manual

How To Use Saml 2.0 Single Sign On With Qualysguard

Commerce Services Documentation

Package pxr. February 20, 2015

Package SHELF. February 5, 2016

Aras Corporation Aras Corporation. All rights reserved. Notice of Rights. Notice of Liability

Installing, Uninstalling, and Upgrading Service Monitor

Human Resources (HR) Query Basics

Integrating VoltDB with Hadoop

Package whoapi. R topics documented: June 26, Type Package Title A 'Whoapi' API Client Version Date Author Oliver Keyes

Spectrum Technology Platform. Version 9.0. Administration Guide

Content Filtering Client Policy & Reporting Administrator s Guide

FileMaker Server 15. Custom Web Publishing Guide

Transcription:

Type Package Version 1.0.0 Title Access the UptimeRobot Ping API Package uptimerobot October 22, 2015 Provide a set of wrappers to call all the endpoints of UptimeRobot API which includes various kind of ping, keep-alive and speed tests. See <https://uptimerobot.com/> for more information. Date 2015-10-21 URL https://gabrielebaldassarre.com/r/uptimerobot BugReports https://github.com/theclue/uptimerobot/issues Depends R (>= 3.0) Imports rjson, RCurl, plyr Suggests testthat License MIT + file LICENSE NeedsCompilation no BuildKeepEmpty TRUE Author [aut, cre] Maintainer <gabriele@gabrielebaldassarre.com> Repository CRAN Date/Publication 2015-10-22 15:23:18 R topics documented: uptimerobot.account.details................................. 2 uptimerobot.contact.delete................................. 3 uptimerobot.contact.new.................................. 4 uptimerobot.contacts.................................... 5 uptimerobot.fields...................................... 6 uptimerobot.monitor.contacts................................ 7 uptimerobot.monitor.delete................................. 8 uptimerobot.monitor.edit.................................. 9 1

2 uptimerobot.account.details uptimerobot.monitor.logs.................................. 11 uptimerobot.monitor.new.................................. 12 uptimerobot.monitor.reset.................................. 14 uptimerobot.monitor.responses............................... 15 uptimerobot.monitors.................................... 16 Index 19 uptimerobot.account.details Get the account details for who is linked to the given API key uptimerobot.account.details returns a list or a vector with the account details connected to the given api key. uptimerobot.account.details(, unlist = FALSE) unlist string with a valid key for connecting to Uptimerobot API. logical. Set to TRUE to unlist the output to a named vector, FALSE to get a named list. A list or a vector with the account details. # Let s assume the is available into the environment variable KEY # Returns details as a list details.list <- uptimerobot.account.details() # Returns details as a vector details.num <- uptimerobot.account.details(, unlist = TRUE)

uptimerobot.contact.delete 3 uptimerobot.contact.delete Delete an alert contact uptimerobot.contact.delete removes an alert contanct, unlinking from all the registered monitors. uptimerobot.contact.delete(, id) id string with a valid key for connecting to Uptimerobot API. numeric or integer with the ID of the contact to delete. The function returns TRUE in case success. An error is thrown otherwise. # Let s assume the is available into the environment variable KEY # Delete the contact with id=12345678 if(uptimerobot.contact.delete(, 12345678){ message("alert contact successfully deleted!") }

4 uptimerobot.contact.new uptimerobot.contact.new Add a new alert contact uptimerobot.contact.new creates a new alert contact with the given properties. uptimerobot.contact.new(, type, value, friendly.name) type value friendly.name string with a valid key for connecting to Uptimerobot API. string or numeric with the type of the contact. You can use both the value (string) or the index (numeric) here. string with the value of the contact (ie. the email address). string the friendly (screen) name of the contact. Details The alert contacts are whom to be notified when the monitor goes up/down. The index lookup keys and values are available on the Uptimerobot API page on https://uptimerobot. com/api The function returns the ID of the newly created contact in case success. An error is thrown otherwise. See Also uptimerobot.contacts, uptimerobot.contact.delete # Let s assume the is available into the environment variable KEY # Create a new contact and get the ID contact.new <- uptimerobot.contact.new(, type = "email", value = "foo@bar.com", "John Doe")

uptimerobot.contacts 5 # Get informations about this new contact contact.detail <- uptimerobot.contacts(, contacts = contact.new) uptimerobot.contacts Get general informations about the alert contacts uptimerobot.contacts extracts a dataset with general informations for a set of contacts used to be alert in case of up/down of the given monitors. uptimerobot.contacts(, contacts = NULL, limit = 50, offset = 0, fields = uptimerobot.fields("contact")$typical) contacts limit offset fields A valid key for connecting to UptimeRobors public API. vector or comma-delimited string with the IDs of the contacts to get. If the argument is NULL or missing, all the available contacts will be returned. An integer value used for pagination. Defines the max number of records to return in each page. Default and max. is 50. An integer value to set the index of the first monitor to get (used for pagination). vector or comma-delimited string with the general informations to include in the output dataset. You may use the helper function uptimerobot.fields if you don t want to manually compile the list of fields. Details The alert contacts are whom to be notified when the monitor goes up/down. If a vector of contact IDs is not given, the function will return data for all the available contacts. The API uses pagination and returns no more than 50 contacts on each page. Use limit and offset to set a different number of monitors to get on each page and to move between pages. Leave default values to get all the data. A dataset with general informations about the contacts.

6 uptimerobot.fields See Also uptimerobot.monitors # Let s assume the is available into the environment variable KEY # Returns all the contacts with a default set of attributes contacts.df <- uptimerobot.contacts() # Returns all the contacts and all the attributes contacts.full.df <- uptimerobot.contacts(, fields=uptimerobot.fields("contact")$full)) # Returns only the two contacts with ID: 1234, 5678 contacts.df <- uptimerobot.contacts(, c("1234", "5678")) uptimerobot.fields Get a list of the available fields for various endpoints uptimerobots.fields returns a list of vectors of available fields for commodity uses. Use it to avoid manually typing long list of fields in vectors or comma-delimited strings when used in various endpoints. uptimerobot.fields(type) type string with the type of fields to be reported. Only monitor and contact are currently supported. Details Use the type parameter to choose which set of fields to return in a list of vectors. These endpoints are currently supported: monitor and contact.

uptimerobot.monitor.contacts 7 The function returns a list of 3 elements which in turn contains a vector of available fields for a given set each. The returned elements are: See Also 1. typical returns a typical set of fields, used in most situations; 2. full returns the full set of available fields, including passwords and other potentially confidential data; 3. compact return a minimal set of fields. uptimerobot.monitors, uptimerobot.contacts uptimerobot.monitor.contacts Get contacts informations for one or more monitors uptimerobot.monitor.contacts return a dataset with all the alert contacts that will be triggered when a log is collected for the given monitors IDs. uptimerobot.monitor.contacts(, monitors, limit = 50, offset = 0) monitors limit offset A valid key for connecting to UptimeRobors public API. vector or comma-delimited string with the IDs of the monitors to get. An integer value used for pagination. Defines the max number of records to return in each page. Default and max. is 50. An integer value to set the index of the first monitor to get (used for pagination). Details The API uses pagination and returns no more than 50 monitors on each page. Use limit and offset to set a different number of monitors to get on each page and to move between pages. Leave default values to get all the data. A dataset with the alert contacts.

8 uptimerobot.monitor.delete See Also uptimerobot.monitors, uptimerobot.monitor.logs, uptimerobot.monitor.responses # Let s assume the is available into the environment variable KEY # Returns all the monitors IDs. Since the function always return a data.frame # (even if you ask only for a column), you have to reference the column to get a character vector. monitors.id <- uptimerobot.monitors(, fields="id")$id # Returns all the contacts registered for the given monitors logs.df <- uptimerobot.monitor.contacts(, monitors=monitors.id) uptimerobot.monitor.delete Delete a monitor uptimerobot.monitor.delete remove a monitor and all existing statistics of it. uptimerobot.monitor.delete(, id) id string with a valid key for connecting to Uptimerobot API. numeric or integer with the ID of the monitor to delete. The function returns TRUE in case success. An error is thrown otherwise.

uptimerobot.monitor.edit 9 # Let s assume the is available into the environment variable KEY # Create a monitor and get its monitor.id monitor.id <- uptimerobot.monitor.new(, friendly.name="open Analytics", url="https://gabrielebaldassarre.com", type="http" ) # Change the friendly name of the monitor if(uptimerobot.monitor.edit(, monitor.id, friendly.name="open Analytics - gabrielebaldassarre.com" ){ message("monitor has been successfully edited!") } # Delete the just-made monitor if(uptimerobot.monitor.delete(, monitor.id){ message("monitor has been successfully deleted!") } uptimerobot.monitor.edit Edit a monitor uptimerobot.monitor.edit edits the properties for an existing monitor. uptimerobot.monitor.edit(, id, friendly.name = NULL, url = NULL, activate = TRUE, subtype = NULL, port = NULL, interval = NULL, keyword.type = NULL, keyword.value = NULL, HTTP.username = NULL, HTTP.password = NULL, alert.contacts = NULL) id friendly.name url string with a valid key for connecting to Uptimerobot API. numeric or integer with the ID of the monitor to edit. string the friendly (screen) name of the monitor. string with the URL/IP of the monitor.

10 uptimerobot.monitor.edit activate subtype port Details interval keyword.type keyword.value HTTP.username HTTP.password logical to set the status of the monitor. Set to TRUE to start the monitor or FALSE to put it in paused state. string used only for "Port monitoring" to set which pre-defined port/service is monitored or if a custom port is monitored. You can use both the friendly name (string) or the index (integer) here. string used only for "Port monitoring" to set the port monitored. integer with the interval for the monitoring check (in minutes). required string in Keyword monitoring". string with the value of the keyword (required for keyword monitoring). string used for password-protected web pages (HTTP Basic Auth). Set to empty string to erase the current username. Available for HTTP and keyword monitoring. string used for password-protected web pages (HTTP Basic Auth). Set to empty string to erase the current password.available for HTTP and keyword monitoring. alert.contacts character vector or data frame with the IDs to alert each with their threshold and recurrence values. If a property has not to be updated, just omit it from the parameters or set to NA. To erase the value of a property, set it to an empty string, ie "", instead (not NA or NULL!). The type of a monitor can not be edited (like changing a HTTP monitor into a Port monitor). The alert contacts are whom to be notified when the monitor goes up/down. Multiple alert contact IDs can be sent in a character vector or in a data frame. If you pass alert contact IDs in a vector, each element must be formatted in the form <id>_<threshold>_<recurrence> (note the underscores). If you prefer to format it as a data.frame, it must have these three columns: id, threshold, recurrence, numeric or integer. Order of the columns doesn t matter. Please note that thresholds and recurrences can be omitted (default to zero) and, as they are only available in the Pro Plan, they are always 0 in the Free Plan. The function returns TRUE in case success. An error is thrown otherwise. # Let s assume the is available into the environment variable KEY # Create a monitor and get its monitor.id

uptimerobot.monitor.logs 11 monitor.id <- uptimerobot.monitor.new(, friendly.name="open Analytics", url="https://gabrielebaldassarre.com", type="http" ) # Change the friendly name of the monitor if(uptimerobot.monitor.edit(, monitor.id, friendly.name="open Analytics - gabrielebaldassarre.com" ){ message("monitor has been successfully edited!") } # Delete the just-made monitor if(uptimerobot.monitor.delete(, monitor.id){ message("monitor has been successfully deleted!") } uptimerobot.monitor.logs Get log records for one or more monitors uptimerobot.monitor.logs return a dataset with all logged messages for the given monitors IDs. uptimerobot.monitor.logs(, monitors, limit = 50, offset = 0) monitors limit offset A valid key for connecting to UptimeRobors public API. vector or comma-delimited string with the IDs of the monitors to get. An integer value used for pagination. Defines the max number of records to return in each page. Default and max. is 50. An integer value to set the index of the first monitor to get (used for pagination). Details The API uses pagination and returns no more than 50 monitors on each page. Use limit and offset to set a different number of monitors to get on each page and to move between pages. Leave default values to get all the data. A dataset with the log events for the given monitors.

12 uptimerobot.monitor.new See Also uptimerobot.monitors, uptimerobot.monitor.responses, uptimerobot.monitor.contacts # Let s assume the is available into the environment variable KEY # Returns all the monitors IDs. Since the function always return a data.frame # (even if you ask only for a column), you have to reference the column to get a character vector. monitors.id <- uptimerobot.monitors(, fields="id")$id # Returns all the log events for the given monitors logs.df <- uptimerobot.monitor.logs(, monitors=monitors.id) uptimerobot.monitor.new Add a new monitor uptimerobot.monitor.new creates a new monitor with the given properties. uptimerobot.monitor.new(, friendly.name, url, type, subtype = NULL, port = NULL, interval = 5, keyword.type = NULL, keyword.value = NULL, HTTP.username = NULL, HTTP.password = NULL, alert.contacts = NULL) friendly.name url type subtype port string with a valid key for connecting to Uptimerobot API. string the friendly (screen) name of the monitor. string with the URL/IP of the monitor. string or integer with the type of the monitor. You can use both the friendly name (string) or the index (integer) here. string used only for "Port monitoring" to set which pre-defined port/service is monitored or if a custom port is monitored. You can use both the friendly name (string) or the index (integer) here. string used only for "Port monitoring" to set the port monitored.

uptimerobot.monitor.new 13 Details interval keyword.type keyword.value HTTP.username HTTP.password integer with the interval for the monitoring check (in minutes). required string in Keyword monitoring". string with the value of the keyword (required for keyword monitoring). string used for password-protected web pages (HTTP Basic Auth). Available for HTTP and keyword monitoring. string used for password-protected web pages (HTTP Basic Auth). Available for HTTP and keyword monitoring. alert.contacts character vector or data frame with the IDs to alert each with their threshold and recurrence values. The alert contacts are whom to be notified when the monitor goes up/down. Multiple alert contact IDs can be sent in a character vector or in a data frame. If you pass alert contact IDs in a vector, each element must be formatted in the form <id>_<threshold>_<recurrence> (note the underscores). If you prefer to format it as a data.frame, it must have these three columns: id, threshold, recurrence, numeric or integer. Order of the columns doesn t matter. Please note that thresholds and recurrences can be omitted (default to zero) and, as they are only available in the Pro Plan, they are always 0 in the Free Plan. A numeric with the ID of the newly created monitor in case of success. An error is thrown otherwise. # Let s assume the is available into the environment variable KEY # Create a monitor and get its monitor.id monitor.id <- uptimerobot.monitor.new(, friendly.name="open Analytics", url="https://gabrielebaldassarre.com", type="http" ) # Change the friendly name of the monitor if(uptimerobot.monitor.edit(, monitor.id, friendly.name="open Analytics - gabrielebaldassarre.com" ){ message("monitor has been successfully edited!") } # Delete the just-made monitor

14 uptimerobot.monitor.reset if(uptimerobot.monitor.delete(, monitor.id){ message("monitor has been successfully deleted!") } uptimerobot.monitor.reset Reset a monitor uptimerobot.monitor.reset remove all the statistics and logs associated to a monitor ID. uptimerobot.monitor.reset(, id) id string with a valid key for connecting to Uptimerobot API. numeric or integer with the ID of the monitor to delete. The function returns TRUE in case success. An error is thrown otherwise. # Let s assume the is available into the environment variable KEY # Get a list of all available monitors, and take the first id monitors.id <- uptimerobot.monitors(, fields="id")[1,1] # Reset the stats for that monitor uptimerobot.monitor.reset(, monitor.id)

uptimerobot.monitor.responses 15 uptimerobot.monitor.responses Get response times for one or more monitors uptimerobot.monitor.responses returns a dataset with all the response times for the given monitors IDs. uptimerobot.monitor.responses(, monitors, limit = 50, offset = 0) monitors limit offset A valid key for connecting to UptimeRobors public API. vector or comma-delimited string with the IDs of the monitors to get. An integer value used for pagination. Defines the max number of records to return in each page. Default and max. is 50. An integer value to set the index of the first monitor to get (used for pagination). Details The API uses pagination and returns no more than 50 monitors on each page. Use limit and offset to set a different number of monitors to get on each page and to move between pages. Leave default values to get all the data. A dataset with the response times for the given monitors. See Also uptimerobot.monitors, uptimerobot.monitor.logs, uptimerobot.monitor.contacts # Let s assume the is available into the environment variable KEY # Returns all the monitors IDs. Since the function always return a data.frame # (even if you ask only for a column), you have to reference the column to get a character vector. monitors.id <- uptimerobot.monitors(, fields="id")$id

16 uptimerobot.monitors # Returns all the ping events for the given monitors logs.df <- uptimerobot.monitor.responses(, monitors=monitors.id) uptimerobot.monitors Get general informations about monitors uptimerobots.monitors.responses return a dataset with general informations for a set of monitors. uptimerobot.monitors(, monitors = NULL, types = NULL, statuses = NULL, search = NULL, summary = list(), limit = 50, offset = 0, fields = uptimerobot.fields("monitor")$typical) monitors types statuses search summary limit offset fields A valid key for connecting to UptimeRobors public API. vector or comma-delimited string with the IDs of the monitors to get. If not used or set to NULL, will return all monitors in an account. vector or comma-delimited string of monitor types. If not used or set to NULL, the function will return all monitors types (HTTP, keyword, ping..) in an account. Else, it is possible to define any number of monitor types. You can use both the friendly name (string) or the index (integer) here. vector or comma-delimited string of monitor statuses. If not used or set to NULL, the function will return all monitors statuses (up, down, paused) in an account. Else, it is possible to define any number of monitor statuses. You can use both the friendly name (string) or the index (integer) here. An optional keyword of to search within monitor URL or friendly name to get filtered results. list of logical values to flag summary indicators to add to the output dataset. An integer value used for pagination. Defines the max number of records to return in each page. Default and max. is 50. An integer value to set the index of the first monitor to get (used for pagination). vector or comma-delimited string with the general informations to include in the output dataset. You may want to use the helper function uptimerobot.fields if you don t want to manually compile the list of fields.

uptimerobot.monitors 17 Details If a vector of monitor is not given, the function will return data for all the available monitors. summary parameter expect a lists of three named logic values that set which columns of additional statistics for each monitor must be added to output dataset for each available monitor. These are summary values only, as the instances are obtained using a set of dedicated functions. 1. response.times set to TRUE to add a column with the number of pings with response times available for the monitor to the output. These values can be queried using uptimerobot.monitor.responses function. 2. log.records set to TRUE to add a column with the number of log entries recorded for the monitor to the output. These records can be queried using uptimerobot.monitor.logs function. 3. alert.contacts set to TRUE to add a column with the number of alert contacts binded to the monitor to the output. Detailed informations about these contacts can be queried using uptimerobot.monitor.contacts function. You may just add the elements you want to include into the list, as they default to FALSE if missing. Set an empty list to exclude all the summary statistics from the output. The API uses pagination and returns no more than 50 monitors on each page. Use limit and offset to set a different number of monitors to get on each page and to move between pages. Leave default values to get all the data. A dataset with general informations about the given monitors See Also uptimerobot.monitor.responses, uptimerobot.monitor.logs, uptimerobot.monitor.contacts # Let s assume the is available into the environment variable KEY # Returns all the monitors with a default set of attributes monitors.df <- uptimerobot.monitors() # # Returns all the monitors of keyword type monitors.kwd..df <- uptimerobot.monitors(, type="keyword") # Returns all the monitors and all the attributes monitors.full.df <- uptimerobot.monitors(, fields=uptimerobot.fields("monitor")$full)) # Returns only the two monitors with ID: 1234, 5678

18 uptimerobot.monitors monitors.df <- uptimerobot.monitors(, c("1234", "5678"))

Index uptimerobot.account.details, 2 uptimerobot.contact.delete, 3, 4 uptimerobot.contact.new, 4 uptimerobot.contacts, 4, 5, 7 uptimerobot.fields, 5, 6, 16 uptimerobot.monitor.contacts, 7, 12, 15, 17 uptimerobot.monitor.delete, 8 uptimerobot.monitor.edit, 9 uptimerobot.monitor.logs, 8, 11, 15, 17 uptimerobot.monitor.new, 12 uptimerobot.monitor.reset, 14 uptimerobot.monitor.responses, 8, 12, 15, 17 uptimerobot.monitors, 6 8, 12, 15, 16 19