Browse Guide and Reaserch Trip.
I thought him the queerest old Quaker I ever saw, especially as Peleg, his friend and old shipmate, seemed such.
Choose a Guide.
I thought him the queerest old Quaker I ever saw, especially as Peleg, his friend and old shipmate, seemed such.
Get live updates within the trip.
I thought him the queerest old Quaker I ever saw, especially as Peleg, his friend and old shipmate, seemed such.
Jan Van La LouEverything was all right. The room was clean and nice and Adele is very kind person. She recommended us what we needed to know.
XtinaThis was our first time using buggl and it was a great experience! The arrangements were easy to make and all went smoothly. Adele was a wonderful host. What a sweet person and very helpful and interesting. Her apartment is in a great location.. show more
MattThis was our first time using buggl and it was a great experience! The arrangements were easy to make and all went smoothly. Adele was a wonderful host. What a sweet person and very helpful and interesting. Her apartment is in a great location.. show more


you have seconds left.
How many championships have the Chicago Bears won?
0 1 2 3 4How many World Series have the Cubs won in the last century?
All of them 0 1 2 Who?Who wore #23 for the Chicago Bulls?
Scottie Pippen
Vlade Divac
Michael Jordan
Horace Grant
Luc Longley


Hello User! What should I call you going forward?
I'm going to ask you some questions (name); are you ready?
(name) do you think I like apples?
Would you believe me if I told you that I've been to Mongolia?
I have 3 pets. Can you guess one of their names? **HINT** Two are named after food.
Have you enjoyed these questions (name)?


There are three primary ways to interact with DataBus
This section discusses and provides examples of working with DataBus via the API. Each example contains the general blueprint for the request followed by a specifc example using your specific authentication credentials.
First, let's revisit the parameters for communication with DataBus that were introduced in the Provisioning DataBus section. The DataBus API uses JSON as the mechanism for transferring data to and from the DataBus server. All API calls require the POST payload of a request to be in the JSON format. The following information is relevant to making DataBus API calls.
The request method header should always specify a Content-Type of JSON:
Header: Content-Type:application/json
We will use your DataBus User account and API Key to authenticate with the DataBus Server:
| User Name: | {user's name} |
| DataBus API Key: | {user's api key} |
In this documentation, we will refer to the URL of the DataBus Server as:
URL: https://databus.nrel.gov/
All of the provided examples will use this URL. If you are not using NREL's DataBus server for your installation, please replace the above URL with the one for your server in the examples below.
Each type of request has a different path associated with it. The examples below provide the full URL path needed to perform the request.
Use the GET method to fetch data. Here is an example of how a GET request to DataBus should be constructed:
$ curl GET -i -H "Accept: application/json" -H "Content-Type: application/json" --user your_username:your_api_key https://databus.nrel.gov/api/{moduleName}/{tableName}
The examples used in this documentation place the authentication in the curl arguments. An alternative way to structure the request that is not dependent on the curl command is to put the credentials within the url itself:
$ curl GET -i -H "Accept: application/json" -H "Content-Type: application/json"<EMAIL_ADDRESS>GET requests can be used with modules to pre-process raw data before a download. The module is defined in the URL path:
$ curl GET -i -H "Accept: application/json" -H "Content-Type: application/json" --user your_username:your_api_key https://databus.nrel.gov/api/{moduleName}/{tableName}
Modules can be "stacked" in a sequence within the URL path to refine results:
$ curl GET -i -H "Accept: application/json" -H "Content-Type: application/json" --user your_username:your_api_key https://databus.nrel.gov/api/{module1}/{module2}/{module3}/{tableName}
See the DataBus Modules section and examples below for more information about using modules.
Use the POST method to create tables or insert data. Here is an example of how a POST request to DataBus should be constructed:
$ curl -X POST -w "\nRESULT CODE:%{http_code}\n" --insecure --header "Content-Type:application/json" --user your_username:your_api_key -d @yourJSONdefinition.txt https://databus.nrel.gov/api/registerV1
The examples used in this documentation place the authentication in the curl arguments. An alternative way to structure the request that is not dependent on the curl command is to put the credentials within the url itself:
$ curl -X POST -w "\nRESULT CODE:%{http_code}\n" --insecure --header "Content-Type:application/json" -d @yourJSONdefinition.txt<EMAIL_ADDRESS>The DataBus server will respond to your request. If your request was successful, you will receive a RESULT CODE of 200:
$ curl -X POST -w "\nRESULT CODE:%{http_code}\n" --insecure --header "Content-Type:application/json" --user your_username:your_api_key -d @yourJSONdefinition.txt https://databus.nrel.gov/api/registerV1
{"modelName":"ExampleTable","groups":[]}
RESULT CODE:200
If your request was unsuccessful, the response message and RESULT CODE from the server will provide you with information describing what the error was:
$ curl -X POST -w "\nRESULT CODE:%{http_code}\n" --insecure --header "Content-Type:application/json" --user your_username:your_api_key -d @yourJSONdefinition.txt https://databus.nrel.gov/api/registerV1
Sorry, table with tablename='ExampleTable' is already in use
RESULT CODE:400
Before data is able to be uploaded (written) to DataBus, the data must be provisioned. A simple example is provided here that demonstrates creating a database and a table. Please refer to the Provisioning DataBus in the Getting Started section for complete details on creating databases and tables.
$ curl -X POST -w "\nRESULT CODE:%{http_code}\n" --insecure --header "Content-Type:application/json" --user your_username:your_api_key -d @ExampleTable.txt https://databus.nrel.gov/api/registerV1
{"datasetType":"TIME_SERIES", "modelName":"ExampleTable", "schema":"ExampleDatabase", "createschema":"true", "columns":[ {"name":"time","dataType":"BigInteger","isIndex":true,"isPrimaryKey":true}, {"name":"value","dataType":"BigDecimal","isIndex":false,"isPrimaryKey":false} ] }
After creating a database and table, you can start inserting data. To upload (write) data to the DataBus server make sure the data is formatted correctly for DataBus and use a POST request to insert it.
There are a few key things to keep in mind when preparing to upload data
You can upload data in JSON or CSV format.
If uploading a CSV, be sure the format of the file meets the following criteria:
https://databus.nrel.gov/api/postdataV1
Here is an example of how a POST request to upload data should be constucted:
!!!--TEST POST--this resulted in an error at the time of writing...Multiple entries can be uploaded to a table in a single POST request. This is done by simply adding more entries to the JSON file.
This example demonstrates uploading JSON data to a TIME_SERIES table. It is presumed that a table named ExampleTable already exists and belongs to the database ExampleDatabase.
Recall that TIME_SERIES data should only contain two columns, time and value. Also recall that the time column should contain time and date values as an epoch timestamp. Refer to the Time Specification section for more details about time and date format in DataBus.
{"datasetType":"TIME_SERIES", "modelName":"ExampleTable", "schema":"ExampleDatabase", "columns":[ {"name":"time", "dataType":"BigInteger", "isIndex":true, "isPrimaryKey":true}, {"name":"value", "dataType":"BigDecimal", "isIndex":true, "isPrimaryKey":false} ] }
The JSON to send a single entry to this table should look like this:
{"_dataset":[ {"_tableName":"ExampleTable","time":1360006291000,"value":162.6911} ] }
Save the JSON to a file: SingleExampleData.txt
Send multiple entries to a table in the same POST. Add more entries to the JSON file:
{"_dataset":[ {"_tableName":"ExampleTable","time":1360006292000,"value":162.6911}, {"_tableName":"ExampleTable","time":1360006293000,"value":163.6911}, {"_tableName":"ExampleTable","time":1360006294000,"value":164.6911}, {"_tableName":"ExampleTable","time":1360006295000,"value":165.6911}, {"_tableName":"ExampleTable","time":1360006296000,"value":166.6911}, {"_tableName":"ExampleTable","time":1360006297000,"value":167.6911} ] }
Save the JSON to a file: SingleExampleData.txt
Here is an example of how a POST request to upload data should be constucted:
This example demonstrates uploading JSON data to a RELATIONAL_TABLE table. It is presumed that a table named ExampleRelationalTable already exists and belongs to the database ExampleDatabase.
{"datasetType":"RELATIONAL_TABLE", "modelName":"ExampleRelationalTable", "schema":"ExampleDatabase", "columns":[ {"name":"time","dataType":"BigInteger","isIndex":true,"isPrimaryKey":true}, {"name":"color","dataType":"string","isIndex":false,"isPrimaryKey":false}, {"name":"volume","dataType":"BigDecimal","isIndex":false,"isPrimaryKey":false} ] }
The JSON to send a multiple entries to a relational table should look like this:
{"_dataset":[ {"_tableName":"ExampleRelationalTable", "time":10,"color":"grey","volume":23.2}, {"_tableName":"ExampleRelationalTable", "time":0,"color":"grey","volume":23.2}, {"_tableName":"ExampleRelationalTable", "time":53,"color":"grey","volume":23.2} ] }
Save the JSON to a file: RelationalExampleData.txt
Here is an example of how a POST request to upload data should be constucted:
It is possible to upload multiple sets of data to multiple tables at once with the DataBus API. This is done by defining the multiple tables and entries in the JSON file.
This example demonstrates a JSON data file that uploads data to 5 different tables in a single POST. It is presumed that the tables already exist and belong to a common existing database.
The JSON to send a multiple entries to a relational table should look like this:
{"_dataset":[ {"_tableName":"ExampleRelationalTable", "time":75,"color":"purple","volume":741.66}, {"_tableName":"ExampleTable","time":1360006298000,"value":2.0}, {"_tableName":"ExampleTable2", "lat":39.741201, "long":-105.168514, "description":"This is where NREL is."}, {"_tableName":"AnotherRelationalTableExample", "depth":432.03, "depth_units":"meters", "temp":5.6, "temp_units":"C"}, {"_tableName":"AnotherTimeSeriesExample","time":1360006299000,"value":563.22} ] }
Save the JSON to a file: MultiTableExampleData.txt
Here is an example of how a POST request to upload data should be constucted:
Data from DataBus can be accessed with a GET request. You can also view data in a web browser by placing the URL provided in the following examples in the address bar.
There are a few key things to have prepared when getting ready to download (read) data:
Your GET request will need to contain the following in order to read data from DataBus:
Header: Content-Type:application/json
your_username:your_api_keyOR
robot_name:robot_api_key
The URL for a GET request has two primary parts, the server location (host name) and request parameters (path name). The server location is where you are storing your tables. The path name will contain the parameters for your query.
The minimum requirements for a path name are:Using the minimum requirements, the most basic URL for a GET request is:
https:databus.nrel.gov/api/{rawdataV1 OR getdataV1}/{tableName}
The basic URL will return all results for the queried table. In some cases this may be exactly what you need. In most cases, users are searching for specific data from a table, to refine the returned results you'll want to use some of the optional parameters.
The startTime and endTime parameters can be added after the table name to specify specific date ranges (formatted as epoch). Also, additional modules can be used in sequence within the path name to better refine the results you are searching for. See the Modules section below to learn more.
Here is an example of what a URL may look like using optional parameters:
The most basic method of reading data from DataBus is to simply input the constructed URL into the address bar of a web browser. the browser will perform the GET request (it may open a dialog box requesting credentials) and display the results in your browser window.
The construced URL may also be used in the command line with an application such as curl. This is an example of a raw data request with curl, using the example URL from above. Results will be displayed in your command line interface.
You can use the command line interface to download and save the GET request results locally. This is an example of using curl to save a raw data request to a local file. The file will be saved to the directory you were in when the command was executed.
If you have a very large result set you want to download, you should code the client to download in chunks and download subset ranges of the data as our load balancer can do the retries for you if there is a failure when we do our rolling upgrade so that you get all your data.
The JSON response is STREAMED back to you such that very large datasets can be sent back without running out of memory. The result format will be similar to the following example (depending on your table's meta data):
{ "data": [ {"time":"0", "color":"grey","volume":"23.2"}, {"time":"10","color":"grey","volume":"23.2"}, {"time":"11","color":"grey","volume":"23.2"}, {"time":"30","color":"pink","volume":"34.5"}, {"time":"51","color":"grey","volume":"23.2"}, {"time":"53","color":"grey","volume":"23.2"} ] }
GET requests can be used with modules to pre-process raw data before a download. Modules are defined in the URL path. Modules can also be "stacked" in the URL path, allowing you to use multiple modules to further refine your results. The following examples provide a description of each module and provide an example URL of it in use.
The data source is based on the type of table that is being queried. A data source module is required. There are two available modules:
The Raw Data module works with TIME_SERIES and RELATIONAL_TIME_SERIES
/rawdataV1/
Copy
The raw data module allows users to get raw data from a time series or relational time series table. Most of the other modules can be combined in sequence with this module.
Because DataBus is optimized for time series data, most GET requests will utilize this module.
The Get Data module works with RELATIONAL_TABLE
/getdataV1/{sqlQuery}
Copy
The get data module allows users to get data from a relational table. It uses an SQL query format to define the table rather than simply listing the table name like the raw module example does. The query structure in the DataBus API requires that all spaces from a standard SQL query be replaced with + characters.
The most basic URL structure for using this module is:
https://databus.nrel.gov/api/getdataV1/select+t+from+{tableName}+as+t
The get data module can utilize other SQL statements, such as using the WHERE clause to only return filtered results that occur after a certain start time:
https://databus.nrel.gov/api/getdataV1/select+t+from+{tableName}+as+t+where+t.{columnName}>1359763200000
Where {columnName} has to be the primary key for the table. Or, within a range:
https://databus.nrel.gov/api/getdataV1/select+t+from+{tableName}+as+t+where+t.{columnName}>1359763200000+and+t.{columnName}<=1364083200000
Or performing a join. Since the SQL query follows more of an object query language, you can use c.owner knowing owner is a foreign key.
https://databus.nrel.gov/api/getdataV1/select+c+from+{tableName}+as+c+left+join+c.owner+as+table+where+table.{columnName}='joinExample'
This module is only compatible with a few of the other modules:
Data can be returned in one of two different formats:
The default format type is JSON, if a download type is not defined your GET request will be formatted as JSON.
/json/
Copy
The json module allows users to receive JSON back. This module is installed by default, and is not requried to be specified. However, if you would like to specify it to maintain consistency among your requests, it can be explicitly defined.
https://databus.nrel.gov/api/json/{other modules}/{tableName}
is the same as
https://databus.nrel.gov/api/{other modules}/{tableName}
To return data as a CSV, it must be specified within the URL path.
/csv/
Copy
The csv module allows users to receive data in CSV format instead of the default JSON format.
Recall that the time column contains time and date values as an epoch timestamp. Refer to the Time Specification section for more details about time and date format in DataBus.
/dateformatV1(dateFormat={parameters})/
Copy
All dates in DataBus (in and out) are in the form of 'epoch offset' in milliseconds. This module converts the epoch timestamp to a human readable output.
https://databus.nrel.gov/api/dateformatV1/{dataSource}/{tableName}
The basic use of the date format module will return dates in the following format:20130203T065700Z
The results are displayed as single strings. Breaking the string apart we find it contains the following values in this order:
YearMonthDayTime(T)HourMinuteSecondZone(Z)
20130203T065700Z
= 20130203T065700Z
While this is certainly easier to read than the epoch timestamp, the time and date results can be formatted in a variety of ways using additional parameters that make them even easier to read.
Formatted Date Structure:https://databus.nrel.gov/api/dateformatV1(dateFormat={time and date parameters})/{dataSource}/{tableName}
-
as the seperator for date variables
:
as the seperator for time variables
%20
as the seperator between variable types
By default, GET request results are returned in order from earliest to latest. All of the examples in the documentation to this point return the oldest data in the table first and display it in ascending order. To retrieve the most recent data first, use the the reverse parameter in your URL.
?reverse=true
Copy
The reverse parameter sorts the time column in descending order before returning your GET request results. Using this parameter displays the most recent data in your table first.
?reverse=true
If this parameter is not defined, results will be displayed in order from oldest to newest by default. This parameter can be defined as false, which will also list results from oldest to newest.
https://databus.nrel.gov/api/rawdataV1/{tableName}?reverse=false
is the same as
https://databus.nrel.gov/api/rawdataV1/{tableName}
The basic GET request structure will return all available results when performed. In some cases this is ideal, but often a user might be interested in more specific results, such as data recorded during a certain period of time or the most recent values. GET request results can be limited by defining a start and end time and/or by using the first values module.
/{tableName}/{startTime}/{endTime}
Copy
Querying a time range does not require a specific module, it is a set of parameters that are defined after the table in the URL. The values for the start and end times must be an epoch timestamp, with a time precision in milliseconds. If no data matches the defined start and end timestamps, no values will be returned.
/firstvaluesV1/{n}/
Copy
The fist values module retrieves the first n values from the table defined in your GET request. Specify n with the number of values you would like returned. The value for n must be greater than zero.
If n is set to 2000, the first 2000 results from the query will be returned. The order will be based on whether or not the ?reverse parameter is set. If ?reverse=true
, the most recent 2000 values will be returned. If ?reverse=false
, or the reverse parameter is not defined, the oldest 2000 values will be returned.
You do not need to provide the {start} and {end} times when using this module. However, they can be defined. If you choose to use a time range, the module will return the first n results within the specified time range. Again, the returned order will be determined by the reverse parameter.
As mentioned above, DataBus modules can be used in a sequence within a single GET request. This allows a user to filter and format data for their individual needs. In this example, we will provide a basic sequence structure that uses several modules to give you an idea of how the URL might be constructed.
For this example, let's return the 200 most recent points from the ExampleTable in a CSV format. Also, we want to format the date so we can easily read the results.
This request will use the first values module along with the reverse parameter to return the most recent 200 data points from ExampleTable. The request uses the csv module to return those results in a CSV format. The date format module will convert the time column in the CSV from epoch offset to a Month-Day-Year Hour:Minute:Second TimeZone format.
Modules UsedNow, let's consider that we are interested in data from the ExampleTable that were recorded between Jan.1 2013 and March 1 2013.
We will modify the request from the above example, and remove the first values module from the URL. Our updated request will continue to use the date format module and the csv module, and we will add a {startTime} and {endTime} to the request, just after the table name, but before the reverse parameter.
Modules UsedThere are modules that allow you to format the results of a GET request. This might include renaming or aliasing a column name or only returning specific columns from a RELATIONAL_TIME_SERIES or RELATIONAL_TABLE.
/columnselect/{column1},{column2}/
Copy
The column select module can be used to "narrow" the GET request results. For example, it can be used to reduce the number of columns displayed from a RELATIONAL_TIME_SERIES table to make it appear more like a simple TIME_SERIES table, with only time and value columns. This module may also be used to return specified columns from a RELATIONAL_TABLE.
The module doesn't make any changes to the actual table, it just formats the data being returned to match the GET request.
Basic StructureUse with TIME_SERIES or RELATIONAL_TIME_SERIES
https://databus.nrel.gov/api/columnselect/{column1},{column2}/rawdataV1/{tableName}
Or, use with RELATIONAL_TABLE
https://databus.nrel.gov/api/columnselect/{column1},{column2}/getdataV1/select+t+from+{tableName}+as+t
The displayed results will only include those columns defined after the module declaration.
Column AliasThis module can also be used to rename or alias a column name using the following structure:
https://databus.nrel.gov/api/columnselect/time as startTime,value as aliasName/rawdataV1/{tableName}
The module can be used with an aggregation rather than a table. To use with an aggregation replace the {dataSource}/{tableName} with the aggregation module along with the {aggregationID} and a {startTime} and {endTime}:
https://databus.nrel.gov/api/columnselect/time as startTime,value as aliasName/aggregation/{aggregationID}/{startTime}/{endTime}
See the aggregation section for more details about using the aggregation module.
/linebreak/
Copy
The rollup module involves summarizing data along a dimension.
The time average module allows users to average intervals of points in a request. The interval is specified in milliseconds and then aligned with the {epochOffset}. For example, if you want a point every 24 hours at midnight in Mountain Time, you will need to supply the GMT offset from Mountain Time as the {epochOffset} in milliseconds. The output time point is the start of the interval being averaged.Time Average Module
/timeaverageV2/{interval}/{epochOffset}/
Copy
https://databus.nrel.gov/api/timeaverageV2/{interval}/{epochOffset}/{other modules}/{tableName}
https://databus.nrel.gov/api/timeaverageV2/{86400000}/{-25200000}/{other modules}/{tableName}
There are modules available to remove data points that are outside of a given set of parameters.
/rangecleanV1/{min}/{max}/
Copy
The range clean module allows users to remove data points that have values outside of a given range.
Basic Structurehttps://databus.nrel.gov/api/rangecleanV1/{min}/{max}/{other modules}/{tableName}
For example, if you were to query a TIME_SERIES table that contained thermostat temperature values, you may only want to view data points that are between 50 degrees and 85 degrees:
https://databus.nrel.gov/api/rangecleanV1/50/85/{other modules}/{tableName}
All values that are outside of that range will be removed from the results.
/variabilityclean(correctionMethod={method},comparison={type})/{allowedVariation}
Copy
The variability clean module allows users to remove data points that are outside an allowed variation. It has options to define an allowed variation for the data values. If any values are outside of the allowed varition, there are options on what to do with it (correctionMethod). There are also options for define the type of comparison to be performed (comparison).
Basic Structurehttps://databus.nrel.gov/api/variabilityclean(correctionMethod={method},comparison={type})/{allowedVariation}/{other modules}/{tableName}
For example, to remove all values that are more than 20% different:
https://databus.nrel.gov/api/variabilityclean(correctionMethod=REMOVE,comparison=PERCENT)/0.2/{other modules}/{tableName}
DataBus has several modules available to perform interpolations and time alignment.
/linearV1/(interval={interval},epochOffset={epochOffset}/
Copy
The linear interpolation module allows users to perform linear interpolations on data points.
Basic Structurehttps://databus.nrel.gov/api/linearV1/(interval={interval},epochOffset={epochOffset}/{other modules}/{tableName}
The epochOffset parameter is useful if you want every value returned to be MST midnight instead of GMT midnight (GMT midnight would be an offset of 0). This will automatically default to a number using the start time and interval. All returned times then line up beginning with the start time as the first point, the start time + the set interval value for the second point, the second point time + the interval for the third point and so on for all consecutive returned data points.
https://databus.nrel.gov/api/linearV1(interval=60000,epochOffset=300)/{other modules}/{tableName}/{startTime}/{endTime}
Not specifying epochOffset is for situations where you may not want the points returned to line up with start time at all.
https://databus.nrel.gov/api/linearV1(interval=60000)/{other modules}/{tableName}/{startTime}/{endTime}??? - is this correct? the existing explanation is terrible...
/splinesV3(type={type},interval={interval},epochOffset={epochOffset},maxToStopSplining={max},bufferSize={bufferSize})/
Copy
The splines module is another module for performing interpolations on data points. You select an interval for the spline to return. The default interval is 60000 ms (1 minute). Using the default interval value, the spline will return a data point every 60 seconds.
Basic Structurehttps://databus.nrel.gov/api/splinesV3/(type={type},interval={interval},epochOffset={epochOffset}/{other modules}/{tableName}/{startTime}/{endTime}
This module has several options, which are set using the listed parameters. Not all options are required, and some have defaults if they are not defined.
Need Basic vs limit derivative content...
The max to stop splining option is a multiple of the interval of when to stop splining and return null values instead. For small cases of missing data like one interval of data was missing, most users want to still spline but for a long outage like 6 hours, users can use this value to make sure we return nulls during the outage so your graphs still show the outage.
The buffer size option will not be used by most users. It is for a case when data coming back has multiple columns and 2 or more of those columns are being splined. The default of 20 rows. In the case of one column having an outage(ie. no data) and another having data, we need to keep buffering the rows due to the outage and can't return a row until we this buffer is full or we get some rows with valid data such that we can spline the column with the outage (as long as outage time < maxToStopSplining time)
??? - is this correct? the existing explanation is terrible.../relationalsummaryV1(columnsToSummarize={summaryColumn1};{summaryColumn2})/{summaryInterval}/{epochOffset}/
Copy
The relational summary module summarizes columns from RELATIONAL_TIME_SERIES tables or aggregations. You select the columns to be summarized. The default interval is 60000 ms (1 minute).
Basic Structurehttps://databus.nrel.gov/api/relationalsummary/(columnsToSummarize={summaryColumn1};{summaryColumn2})/{summaryInterval}/{epochOffset}/{other modules}/{tableName}/{startTime}/{endTime}
This module has several options, which are set using the listed parameters.
DataBus has several modules for performing mathematical operations in requests.
/relational/{new value}={value}{operation}{n}/
Copy
The relational module is can perform two primary functions. It can be used to simply return many columns in a RELATIONAL_TIME_SERIES table and it can be used to perform basic mathematical operations on table columns.
Basic Structurehttps://databus.nrel.gov/api/relational/{new value}={value}{operation}{n}/{other modules}/{tableName}/{startTime}/{endTime}
This module can be used to perform simple operations, such as addition, subtraction, multiplication or division. The module will perform the operation on the specified original value and then introduce a new column containing the results of the operation. This module can also be used to overwrite an existing column value or simply duplicate a column. It can be used multiple times within the same URL for performing several basic operations, or more complex calculations.
Duplicate a ColumnTo duplicate a column value, use the following example for guidance:
https://databus.nrel.gov/api/relational/{duplicate value}={value}/{other modules}/{tableName}Overwrite a Column
To overwrite a column value, use the following example for guidance:
https://databus.nrel.gov/api/relational/{value}={value}{operation}{n}/{other modules}/{tableName}Basic Operations
Addition
https://databus.nrel.gov/api/relational/{new value}={value}+{n}/{other modules}/{tableName}
Subtraction
https://databus.nrel.gov/api/relational/{new value}={value}-{n}/{other modules}/{tableName}
Multiplication
https://databus.nrel.gov/api/relational/{new value}={value}*{n}/{other modules}/{tableName}
Division
https://databus.nrel.gov/api/relational/{new value}={value}÷{n}/{other modules}/{tableName}
(Note the use of the ÷ symbol, use of this symbol helps to maintain a clean URL and it is easier to identify what is being done. To type the ÷ symbol on Windows, hold down the ALT key and type 0247. To type the ÷ symbol on Mac OS, hold down the Option key and press / (backslash))
Multiple OperationsTo perform multiple operations, and add multiple result columns:
https://databus.nrel.gov/api/relational/value2=value*1000/relational/value3=value*.5/relational/value4=÷2/{other modules}/{tableName}
/stddevV1/{rowCount}/{factor}/
Copy
The standard deviation (stddev) module is used to remove data points with values that are outside of a given multiplier of the standard deviation.
Basic Structurehttps://databus.nrel.gov/api/stddevV1/{rowCount}/{factor}/{other modules}/{tableName}/{startTime}/{endTime}
The standard deviation (stddev) module removes data points that are outside of supplied mutliplier of the standard deviation.
Modules UsedFor this example, the stddev module will remove all values that are outside of half of a standard deviation of the entire dataset, to that point (infinite window).
In example 2, the stddev module will remove all values that are outside of one standard deviation of the of 200 values.
/invertV1/
Copy
The invert module is used to negate all data points in a request. Negative values become positive (-5 becomes 5) and positive values become negative (10 becomes -10)
Basic Structurehttps://databus.nrel.gov/api/invertV1/{other modules}/{tableName}/{startTime}/{endTime}
The log module is a way for users save modified results that are generated by using other modules. this is an easy way to access the data from the request results directly without having to regenerate the data again using a new request. Before using this module, another table must be registered with an additional attribute in the JSON that states: "isForLogging":true
.
/logV1/{loggingTable}
Copy
https://databus.nrel.gov/api/logV1/{loggingTable}/{other modules}/{tableName}/{startTime}/{endTime}
Using the (log) module is a practice that will save data from a request so it is easily accessible without having to run the request again to regenerte the data. As noted in the module description, the log module requires that a table has been registered that has "isForLogging":true
set. This is the location where the log module will save the data.
Before using the log module, we need to create the table it will save data to.
$ curl -X POST -w "\nRESULT CODE:%{http_code}\n" --insecure --header "Content-Type:application/json" --user your_username:your_api_key -d @LoggingTable.txt https://databus.nrel.gov/api/registerV1
Table register payload:
{"datasetType":"TIME_SERIES", "modelName":"ExampleTable", "schema":"ExampleDatabase", "isForLogging":"true", "columns":[ {"name":"time","dataType":"BigInteger","isIndex":true,"isPrimaryKey":true}, {"name":"value","dataType":"BigDecimal","isIndex":false,"isPrimaryKey":false} ] }
Save the JSON to a file: LoggingTable.txt
After creating the table, we can begin the GET request and define the log module along with the newly registered table name in the URL. For this example, we will build a request that applies logic to the results. Rather than run this request every time we want to see the data, we can run it once and save it to the log table.
Let's build a URL that will return data from our ExampleTable, that have values between -100 and 100, are interpolated using a minutely interval, are within one standard deviation of 200 values and are within a specified time range of<PHONE_NUMBER>000 to<PHONE_NUMBER>000.
An aggregation can be created to group table columns. The aggregation groups can then be queried using the API and modules. There are several ways to query aggregated data, and depending on what is desired, different ways to use aggregations.
There are two different aggregation concepts, one requires values to be time aligned and one that does not. The aggregation module requires values to be time aligned and should be used in most situations, especially where calculations are being performed. The aggregation pipe (aggregationpipe) module does not require values to be time aligned, and is useful for graphing or other situations where it is not essential if the different values are time aligned. If aggregations are used with the spline module, they will be time aligned.
There are also two types of aggregation modules, basic and dynamic. The basic aggregation modules (aggregation and aggregationpipe) are used to query a single aggregation group. The dynamic aggregation modules (dynamicaggregationV1 and dynamicaggregationpipeV1) are used to build 'sub' URLs that can be placed in a single request. This allows a user to query multiple aggregation groups in that single request.
To use these modules, you must create or use an existing aggregation. In this section, we will cover creating an aggregation, listing available aggregations and usage of the aggregation modules.
This is an example of how to create, or modify, an aggregation. An aggregation takes all values from the included time streams at time n and adds them together. Basically, the aggregation will take all the values for time 1 from the specified data streams and add them together. Likewise, it will do this for all values at time 2, time 3, etc. An aggregation POST requires using the sumstream module, see below for specification on this module.
https://databus.nrel.gov/api/sumstreamsV1/registerV1Example Structure
The JSON for an aggregation:
{"name":"{AggregationID}", "group":"{GroupID}", "urls":[ "{URL1}", "{URL2}" ] }
Save the JSON to a file: ExampleAggregation.txt
A JSON example, using modules, to create an aggregation.
{"name":"TEST_AGGREGATION", "group":"testgroup", "urls":["timveaverageV2/60000/rangecleanV1/-2000/2000/rawdataV1/ExampleTable ] }
Here is an example of how a POST request to upload data should be constucted:
You can use a GET request to list the aggregations you have created, or that are available to you. The request will return the each available aggregation along with info about the database it belongs to. Paste the URL into a browser address bar or use it in the command line with an application such as curl.
https://databus.nrel.gov/api/sumstreamsV1/listaggregations/
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" --user your_username:your_api_key https://databus.nrel.gov/api/sumstreamsV1/listaggregations/
You can use a GET request to view data from an aggregation you have created, or that is available to you. This request is similar to getting data from a table. You can use most API modules with aggregated data. In most of the previous examples, you can switch the table name with an aggregation.
https://databus.nrel.gov/api/sumstreamsV1/aggregation/{AggregationID}
To delete an aggregation you have created, use the POST method. Do not use a GET request. There is no body required, simply perform a POST that is similar to the basic structure.
https://databus.nrel.gov/api/sumstreamsV1/deleteagg/{AggregationID}
The basic modules are used to create, modify or view aggregation data.
/aggregation/{aggregationID}
Copy
The aggregation module tells the request to query an aggregation rather than a table. It is used to view specific aggregations, and can be used in combination with other modules to return results from available aggregations. Basically, it replaces the rawdata and getdata modules in a URL. Values should be time aligned with this module.
The following URL structure will return all of the aggregation values:
Basic Structurehttps://databus.nrel.gov/api/aggregation/{aggregationID}/{startTime}/{endTime}
/aggregationpipe/{aggregationID}
Copy
The aggregation pipe module tells the request to query an aggregation rather than a table. It is similar to the aggregation module, except that values are not required to be time aligned with aggregation pipe. This module is most useful if the returned data will be used for graphing purposes.
Basic Structurehttps://databus.nrel.gov/api/aggregationpipe/{aggregationID}/{startTime}/{endTime}
/sumstreamsV1/{aggregationID}
Copy
The sumstreams module takes all values from the included time streams at time n and adds them together. Basically, the aggregation will take all the values for time 1 from the specified data streams and add them together. Likewise, it will do this for all values at time 2, time 3, etc. This module can be used to POST or GET data.
The following URL structure will return the sum of the aggregation values:
Basic Structurehttps://databus.nrel.gov/api/sumstreamsV1/{aggregationID}/{startTime}/{endTime}
/sumstreamsV2(aggregation={aggregationID},enableNulls={true or false})
Copy
The sumstreams version 2 module is a beta version of the sumstreams module with enhanced capability. It works similarly to sumstreamsV1, except that it has an option to disable null values. If enableNulls is set to true, this module will return null values in cases where one of the streams from the aggregation has no data. This will enable a graph to go null when at least one stream is returning null values. If enableNulls is set to false, then the module will return all streams added up (explained in sumstreamsV1), except for the stream with no or null data.
The following URL structure will return the sum of the aggregation values:
Basic Structurehttps://databus.nrel.gov/api/sumstreamsV2/(aggregation={aggregationID},enableNulls={true or false})
Here are a few simple examples of working with aggregations.
Modules UsedLet's start by viewing the data for a specific aggregation. The sumstreams and aggregation modules will be used.
Now, let's just view the sum of the ExampleAggregation values within a specific time range. The sumstreams and time range query modules are used.
For this example, let's view all of the ExampleAggregation values that are within a specific time range. The aggregation and time range query modules are used.
For the last basic example, let's do an hourly summary of the columns in the ExampleAggregation within a specific time range. The relational summary, aggregation and time range query modules are used.
Here are a few simple examples of using relational operations with aggregations.
Modules UsedIn this example, let's add a new column named TestSum to the results that is the sum of the components from the ExampleAggregation. The relational and aggregation modules will be used.
Just like using the relational module with tables, it is possible to modify the data being returned. Let's modify the results to overwrite an existing column with a value that might be a bit more useful for us, taking the original value and multiplying by 1000. The relational and aggregation modules will be used.
Here are a few simple examples of modifying the results returned from an aggregation.
Modules UsedIn this example, let's consider that ExampleAggregation is a RELATIONAL_TIME_SERIES but we want our results to appear narrow, like a TIME_SERIES. The column select, aggregation and time range query modules will be used.
The column names can also be modified using the column select module.
The above example output can be used as the input of another module. This is particularly useful if the input for the other module is a column name that is not named the same. For this example, let's use a column from a RELATIONAL_TIME_SERIES aggregation as an input for a range clean module.
The dynamic modules are used to work with multiple tables and URLs in a single request.
/dynamicaggregationV1/rawdataV1/{startTime}/{endTime}?src1={source1}&src2={source2}...
Copy
The dynamic aggregation module can query a series of URLs and return them in a single request. This module can get results for up to 8 tables in a single request. Values should be time aligned with this module.
The following URL structure will return all of the aggregation values:
Basic Structurehttps://databus.nrel.gov/api/dynamicaggregationV1/rawdataV1/{startTime}/{endTime}?src1={source1}&src2={source2}&src3={source3}&src4={source4}&src5={source5}&src6={source6}&src7={source7}&src8={source8}
/dynamicaggregationpipeV1/rawdataV1/{startTime}/{endTime}?src1={source1}&src2={source2}
Copy
The dynamic aggregation pipe module can query a series of URLs and return them in a single request. This module can get results for up to 8 tables in a single request. It is similar to the dynamic aggregation module, except that values are not required to be time aligned with dynamic aggregation pipe. This module is most useful if the returned data will be used for graphing purposes.
The following URL structure will return all of the aggregation values:
Basic Structurehttps://databus.nrel.gov/api/dynamicaggregationpipeV1/rawdataV1/{startTime}/{endTime}?src1={source1}&src2={source2}&src3={source3}&src4={source4}&src5={source5}&src6={source6}&src7={source7}&src8={source8}
This is a simple example of returning data from multiple tables using the dynamic aggregation modules.
Modules UsedA simple request to get raw data from 3 different tables for a specified time range. There is no need for the data to be time aligned. The example tables we will be working with are: ExamplePower, ExampleSpeed and ExampleTemp.
The above URL will return results that look like this:
{"data": [{"ExamplePower": 0.4, "ExampleSpeed": 40, "ExampleTemp": 71.6044, "time":<PHONE_NUMBER>000 }, {"ExamplePower": 0.4, "ExampleSpeed": 40, "ExampleTemp": 71.6044, "time":<PHONE_NUMBER>000 }, ... ] }
The dynamic aggregation is really building three sub-URLs that look something like this:
.../rawdataV1/ExamplePower/... .../rawdataV1/ExampleSpeed/... .../rawdataV1/ExampleTemp/...
You can use other modules to apply logic to a dynamic aggregation request. To do this, include the desired modules in the URL after the dynamic aggregation declaration.
Modules UsedThis request will get data from 3 different tables that is interpolated using a minutely interval with values between a specified range during a specified time range. Again, there is no need to time align the values and the example tables we will be working with are: ExamplePower, ExampleSpeed and ExampleTemp.
This example will yield similar to results as the previous example, but will exclude any values that met the logic criteria from the splines and range clean modules:
{"data": [{"ExamplePower": 0.4, "ExampleSpeed": 40, "ExampleTemp": 71.6044, "time":<PHONE_NUMBER>000 }, {"ExamplePower": 0.4, "ExampleSpeed": 40, "ExampleTemp": 71.6044, "time":<PHONE_NUMBER>000 }, ... ] }
This aggregation request is applying the logic to the three sub-URLs, and looks something like this:
.../splinesV2/limitderivative/60000/0/rangecleanV1/-20000000/20000000/rawdataV1/ExamplePower/... .../splinesV2/limitderivative/60000/0/rangecleanV1/-20000000/20000000/rawdataV1/ExampleSpeed/... .../splinesV2/limitderivative/60000/0/rangecleanV1/-20000000/20000000/rawdataV1/ExampleTemp/...
You can rename the tables in a dynamic aggregation request. To do this, supply a new parameter in the URL structure.
Modules UsedThis is the same request from the last example. However, consider that there might be a reason to rename one (or all) of the tables in the query. After specifying a source in the URL, you can also specify an alias to rename the table in your results. Again, there is no need to time align the values and the example tables we will be working with are: ExamplePower, ExampleSpeed and ExampleTemp.
This example will yield similar to results as the previous example, but will rename all values from the ExamplePower to MorePower.
Results display as:
{"data": [{"MorePower": 0.4, "ExampleSpeed": 40, "ExampleTemp": 71.6044, "time":<PHONE_NUMBER>000 }, ... ] }
Instead of:
{"data": [{"ExamplePower": 0.4, "ExampleSpeed": 40, "ExampleTemp": 71.6044, "time":<PHONE_NUMBER>000 }, ... ] }
The sub-URLs still appear the same as in the previous example, no change to the table name here:
.../splinesV2/limitderivative/60000/0/rangecleanV1/-20000000/20000000/rawdataV1/ExamplePower/... .../splinesV2/limitderivative/60000/0/rangecleanV1/-20000000/20000000/rawdataV1/ExampleSpeed/... .../splinesV2/limitderivative/60000/0/rangecleanV1/-20000000/20000000/rawdataV1/ExampleTemp/...
You can apply different types of logic to different tables in a dynamic aggregation request. To do this, supply the table specific logic in the URL structure where the source tables are defined. You can even have two sources that are from the same table with different logic applied to them.
Modules UsedThis example continues to build on the request from the previous examples. This time we will want to apply different logic to each table. This example also shows how to have two sources from the same table, but each having different logic applied to them. The ExampleSpeed
The URL example above is becoming complex and starting to get difficult to read. Let's break it down so it is more clear what is happening here.
This includes the URL for the DataBus server and the logic (modules) that will be applied to all of the tables in the dynamic aggregation:
https://databus.nrel.gov/api/dynamicaggregationpipeV1/splinesV2/limitderivative/60000/0/rangecleanV1/-20000000/20000000/rawdataV1/-20000000/20000000/rawdataV1/1388534400000/1391212800000?
Then, we are defining the first source/table and renaming it:
src1=ExamplePower&srcName1=MorePower
Next, the second source/table is defined. We are using the ExamplePower table again, but we want to apply the range clean module to this set of results:
&srcName2=MorePowerCleaned&src2=/rangecleanV1/0/100/ExamplePower
The third source/table will use the relational to multiply the values from the ExampleSpeed table by 1000 and add those new values to the results using the a new name, ExampleSpeedScaled:
&src3&srcName3=ExampleSpeedScaled&src3=relational/value=value*1000/ExampleSpeed
The last source/table is still the ExampleTemp, there is additional logic applied to this table. Recall though, that the logic from the first part of the URL path is still being applied (/splinesV2/limitderivative/60000/0/rangecleanV1/-20000000/20000000):
&src4=ExampleTemp
This example will yield the scaled and cleaned logic to results.
Results display as:
{"data": [{"MorePower": 0.4, "MorePowerCleaned": 0.4, "ExampleSpeedScaled": 40000, "ExampleTemp": 71.6044, "time":<PHONE_NUMBER>000 }, ... ] }
The sub-URLs are also getting more complex, and now appear similar to this:
.../splinesV2/limitderivative/60000/0/rangecleanV1/-20000000/20000000/rawdataV1/ExamplePower/... .../splinesV2/limitderivative/60000/0/rangecleanV1/-20000000/20000000//rangecleanV1/0/100/rawdataV1/ExamplePower/... .../splinesV2/limitderivative/60000/0/rangecleanV1/-20000000/20000000/relational/value=value*1000/rawdataV1/ExampleSpeed/... .../splinesV2/limitderivative/60000/0/rangecleanV1/-20000000/20000000/rawdataV1/ExampleTemp/...


The Green Web Foundation Api Service
Currently available services
-
Greencheck api service: With the Green Web Foundation greencheck api service it is possible to check if a website is green against our Green Web database.
Example
Results
Fill in a website and click the check button to check it
Usage
The greencheck api service can be used by calling the /greencheck/{url} script at this url. http://api.thegreenwebfoundation.org/greencheck/{url}
The greencheck api service expects only one parameter : "url".
This should be the url of a website without the "http://" part, so just "www.example.com".
http://api.thegreenwebfoundation.org/greencheck/www.example.com
This url parameter is checked and the result is returned to the calling script.
The result contains a couple of fields:
- If the url was not valid, then only an error field is returned
- For a correct url, both the url and the green field are returned. Green is either true or false.
For websites that are hosted on a known hosting provider
we return a "hostedby" and "hostedbywebsite" with either the Name and website of the hosting provider.
Looking up "www.thegreenwebfoundation.org" with the greencheck api
http://api.thegreenwebfoundation.org/greencheck/www.thegreenwebfoundation.org
returns the following json result
{
"green":true,
"url":"www.thegreenwebfoundation.org",
"hostedby":"LEASEWEB",
"hostedbywebsite":"www.leaseweb.com"
}
Jquery example
View the source of this webpage to see how you can call the greencheck api service by using jquery
The Green Web add-ons
There are add-ons that use this api, available at The Green Web Foundation webiste, called
The Green Web.
It shows you for every website you visit if it is green, and if so the hosting party.
Widgets
In the future, we will add some widgets to this page, so that you can easily put a greencheck widget on your site,
without the need to code it yourself


There are code styles that I just can’t bring myself to look at without having a major urge to hit re-format keys.
There are design styles that create in me such an overwhelming negative reaction that I want to hit… umm… there isn’t a “re-design” key, is there?
I am probably not the only software designer to react this way.
Design is a very vivid manifestation of a person’s way of thinking. Taking it in is like an attempt to transplant a part of someone’s mind into my own. And, just like immune system of a transplant patient would, in case of incompatibility, reject a donated liver, the immune system of my mind rejects the foreign design.
Now, I do have to work with other people’s designs all the time, despite this rejection. I know they give recent transplant patients immune-suppressants. I wonder if something like that could be arranged for me on the next project.
* * *
One could also think of this in terms of acute toxicity: the result of other designer’s intellectual metabolism may send me into anaphylactic shock.
Fragile little me


Beginnings
- from Berlin to Indonesia
- Successful mobile e-commerce
- Legacy developed
in death march 💀
Plan
- New features in Golang
- Move to Kubernetes (GCP)
- Get team on board
We mostly like
- Standard library
- Composition
- ...
- Idiomatic way
- go proverbs
Next stop
SaaS and ML Fintech
Culture shock
- No mocks?
- No DSLs
- No lib for X
- JSON parsing :)
- Not flexible
Golden mean
- Guidelines,
not rules
[Dave Cheney]
- Hard to find
- It moves all the time
https://www.flickr.com/photos/bruno_brujah/
How to find it?
- Team
- Inclusion
- Diversity
https://www.flickr.com/photos/bruno_brujah/
Methods?
- One-on-ones
- Engineering hour
- Moderate discussions
- Communication is everybody responsibility
More inspiration: golang conduct
Stuck? Let us know
- Lower the threshold
- Time-boxing
- Trigger-based [1]
[1] Cooper Code
Assume good intentions
Always
Strong opinions
weekly hold
Ship it
- Ship it
- ...
- The rest
- Finding balance
Kick Butt, Have Fun
Sun Microsystems
Photo by Nasa
version 1
- Understand
- Validate
- Avoid over-engineering
version 2
- Restructure
- Fix
- Re-factor
version 1 → version 2
- Will take more time
- Find answers faster
- Might give us more time
Idea?
- Demonstrate it without negative effect on your work
- Make it Real!
Heroku Values
Problem?
- come with a possible solution
- Powerful language
- and tools (k8s, cloud)
- combined experience
https://www.flickr.com/photos/bruno_brujah/
Thank you. Questions?
https://github.com/wojciech12
Doing good
- Jetbrains:
most promising
- IEEE:
5th fastest growing
- Kubernetes
- CloudNative
- Next enterprises?
Community
- Gopher Warsaw
- GoCracow
- Gopher Silesia
- Golang UG Gdańsk
Ideas
- Talks
- Workshops
- Speed get-know each other
- ...


Eleanor of Aquitaine lived in the 12th Century. She was the Duchess of Aquitaine, the Queen of France and the Queen of England. Her real name was Alienor.
Sections
Early Days
She was born in Aquitaine (now part of France) When her father died, she was the richest heiress in the known world. She had to escape men looking to kidnap her, and force her to marry them, so they would become rich, and a duke of the largest and most prosperous dukedom.
Queen of France
Eventually, the prince of France succeeded in kidnapping her and marrying her(she was 13). When the king and queen of France died, she became queen of France. When she couldn’t bear boy children, the Prince of France annulled their marriage.
Queen of England
Yet again, people tried kidnapping her. Eventually she fell in love with the heir of England, Henry. She had four sons. Eventually, her husband started hating her, and shut her away in prison until she was 62. She was let out when her husband died.
Regent
When Henry died, she led an army against the French to secure her son Richard’s claim to the throne. When her son Richard was taken captive, she raised a ransom of 150,000 marks. When Richard died, she acted as regent until her youngest son was ready to rule.


{% extends 'base.html'%} {% load bootstrap3%} {% block content%}
We check the uniqueness of the design,The caption that it attracts and the charisma that it arouses.
We check the simplicity of been used,the friendliness to the user and the sense of intaractivity
Content its all about what the app is about,the problem it solves and the repulsion it antagonises.
This is done following the creteria of the three core most guidance.The design of the app must be catchy.The usability of the app must be easy to use and the content of the app must be relevant to the users.


PROJECT: Internship Diary
This portfolio provides an overview of my contributions to the software engineering project Internship Diary.
Overview
Internship Diary is a desktop-based internship application tracking software.
The idea for this software came about when we realised that the nature of a computer science degree is internship-driven; in the sense that having the best possible internship experience during candidature will greatly improve your chance of landing a good first job. Having said that, internship application is often a tedious process as companies having different hiring processes and requirements.
We set out to tackle this pain point — by coming up with a solution to help computer science students manage and streamline their internship application journey. We aim to make every student’s internship hunt during their four years as a computer science undergraduate a pleasant one, and hopefully maximise their chances of landing the best possible internship.
Internship Diary offers a one-stop solution for users to organise and track their internship applications. It enables users to retrieve any information about their internship applications easily so that they can keep themselves updated with the companies they have applied to. This will motivate students to freely apply for many different companies and roles because they know that Internship Diary is always keeping their applications organized. Consequently, this may improve their chance of landing an internship.
Summary of Contributions
Enhancements
-
Implemented the Archival System
-
What it does: Allows users to move their internship applications between the main list and the archival list.
-
Justification: This feature is important as it helps users to keep their internship applications organized. Whenever there are internship application(s) that are no longer relevant, the user can archive those internship applications so that it "de-clutters" their main list. This allows them to focus on the internship application(s) that are more important.
-
Highlights: The archival feature seems trivial as it is usually a staple feature in many tracking applications. However, it was challenging to decide on a design implementation for our use case such that the feature is sustainable and extensible. Due to the chosen design, there was a need to implement a form of observer pattern to handle reactivity issues — this became another important design consideration.
-
-
Implemented the Observer Pattern Design
-
What it does: Provides a robust solution to keep UI in sync with the state of backend data.
-
Justification: As we started to introduce many UI elements that require various data and reference from the backend, it became difficult to manage the delivery of such data to the UI. To prevent coupling between the elements with our backend, and to ensure the UI can be updated with the latest data changes, we needed to implement the observer pattern.
-
Highlights: Researching about and implementing the observer pattern design. I had to find out exactly how the mechanism works and the options out there for us to integrate it into our project. There was quite a bit of trial-and-error in testing out the options so that we can find the best implementation / library for our situation.
-
-
Implemented Multi-Execution Type functionality for Removal-Based Commands
-
What it does: Allows users to execute removal-based commands like
archive
,unarchive
,delete
on multiple internship applications (by index, indices, or field). -
Justification: This would greatly aid users in organising their internship applications. Having to archive your internship applications one-by-one would not be a pleasant experience for the user.
-
Highlights: To design and implement this feature well is not easy. There were extensive discussions with the team regarding the most suitable implementation (not the best) to go ahead with. We had to consider aspects like timeline, amount of refactoring, conflicts with existing implementations, and other issues.
-
-
Implemented the Statistics feature
-
What it does: The statistics feature dynamically generates relevant metrics from the list of internship application(s) in the current view.
-
Justification: The hunt for internship can be seen as a journey of growth in terms of personal and professional development. The statistics feature provides users with important information about their internship application journey in terms of numbers, which the user can interpret and generate insights.
-
Highlights: Implementing the Statistics feature on its own was straightforward. The difficulty lies in how it can be implemented in an extensible manner. For example, the addition of a new status would not require the refactoring of model. This required careful design considerations.
-
Code Contribution
All of my contributions can be found here: RepoSense Report
Other Contributions
-
Project Management:
-
Actively managed team repository’s issue panel by adding, assigning, labeling, and closing issues.
-
Ensured that the team is heading in the right direction by monitoring the development progress and bringing up important issues.
-
-
Documentation
-
Contributed extensively to both the User Guide (UG) and Developer Guide (DG).
-
-
Major Refactoring of the Original Codebase
-
Allowed the team to proceed morphing the product and implementing features (PR #54)
-
-
Bug Fixes
-
Community:
Contributions to the User Guide
Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users. |
Viewing unarchived internship applications: list
Displays unarchived internship applications. This is known as your main list.
Format: list
Viewing archived internship applications: archival
Displays archived internship applications. This is known as your archival list.
Format: archival
Deleting internship application: delete
Deletes internship application from the current list.
Formats:
-
delete INDEX
-
delete INDEX, [INDEX],…
-
delete s/STATUS [STATUS]…
Example(s):
-
list
delete 2
Deletes the 2nd internship application from the main list. -
list
delete 1, 2, 3
Deletes the 1st, 2nd, and 3rd internship applications from the main list. -
archival
delete s/applied
Deletes all the internship application(s) with theapplied
status from the archival list. -
archival
delete s/applied rejected
Deletes all the internship application(s) with theapplied
orrejected
status from the archival list.
Archiving internship application: archive
Moves internship application from the main list to the archival list.
Formats:
-
archive INDEX
-
archive INDEX, [INDEX],…
-
archive s/STATUS [STATUS]…
Example(s):
-
list
archive 2
Archives the 2nd internship application in the main list. -
list
archive 1, 2, 3
Archives the 1st, 2nd, and 3rd internship application in the main list. -
list
archive s/applied
Archives all the internship application(s) with theapplied
status in the main list. -
list
archive s/applied rejected
Archives all the internship application(s) with theapplied
orrejected
status in the main list.
Unarchiving internship application: unarchive
Moves internship application from the archival list to the main list.
Formats:
-
unarchive INDEX
-
unarchive INDEX, [INDEX],…
-
unarchive s/STATUS [STATUS]…
Example(s):
-
archival
unarchive 2
Unarchives the 2nd internship application in the archival list. -
archival
unarchive 1, 2, 3
Unarchives the 1st, 2nd, and 3rd internship application in the archival list. -
archival
unarchive s/applied
Unarchives all the internship application(s) with theapplied
status in the archival list. -
archival
unarchive s/applied rejected
Unarchives all the internship application(s) with theapplied
orrejected
status in the archival list.
Retrieving statistics: stats
Displays the statistics about your internship application(s) on the current list.
It will open a separate window that contains a bar chart and a pie chart.
The statistics will dynamically update as you update the current list (e.g. switching between main and archival list).
Format: stats
stats
is executed|
Tip
|
Alternatively, you may use your mouse to click on "Statistics" and then "View Statistics" to bring up the statistics window. |
Contributions to the Developer Guide
Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project. |
Archival System
This feature allows users to store chosen internship application(s) into the archival.
The entire system is driven by two mechanisms:
-
the ability to switch views between the archived and unarchived list of internship application(s)
-
the ability to move internship application(s) into the archived list and vice-versa
The two mechanisms can be further broken down into the following four commands: list
, archival
, archive
, and unarchive
.
List & Archival
To handle the ability for a user to switch views, we implemented the commands list
and archival
:
-
list
allows the user to view the unarchived internship application(s) -
archival
allows the user to view the archived internship application(s)
From here on, we will refer to the list of unarchived internship application(s) as the main list, and the list of archived internship application(s) as the archival list.
Beyond the primary purpose of allowing users to switch between their view of main and archived list of internship application(s),
list
and archival
also helps to verify that the archive
and unarchive
commands are used appropriately.
This means that a user should not archive
an internship application when it is already in the archival — doing so will raise an exception.
This is identical for the unarchive
command in the main list as well.
Implementation
The class diagram below depicts the important methods and attributes that provide us the ability to switch views between the main list and the archival list.
InternshipDiary
that showcases the methods and attributes required for view-switchingThe object diagram below illustrates the three UniqueInternshipApplicationList
objects maintained by InternshipDiary
:
-
displayedInternships
-
archivedInternships
-
unarchivedInternships
UniqueInternshipApplicationList
objects maintained by InternshipDiary
As the name suggests, displayedInternships
is the list that is shown to the user in the GUI. It references either
archivedInternships
or unarchivedInternships
at any one time.
When a user is viewing the main list, displayedInternships
references unarchivedInternships
.
And when a user is viewing the archival list, displayedInternships
references archivedInternships
.
The following sequence diagram illustrates how an archival
command is executed.
The list
command is similar to archival
.
You may use the same sequence diagram for the list
command.
archival
CommandThe following code snippet is retrieved from the InternshipDiary
class.
It illustrates the internal workings of how we switch the view between the archived list and the main list.
public void viewArchivedInternshipApplicationList() { this.displayedInternships = archivedInternships; this.currentView = InternshipApplicationViewType.ARCHIVED; firePropertyChange(DISPLAYED_INTERNSHIPS, getDisplayedInternshipList()); }
It can be seen explicitly from the code snippet that we make use of referencing to switch between the views of archival and main list.
However, such implementation brings about issues with reactivity — where elements that reference displayedInternships
will not be aware of the reference change in displayedInternships
whenever the user executes archival
or list
.
Therefore, in the above scenario, users would still see the main list after executing the archival
command.
In order to resolve this issue, we need to employ the observer pattern design.
The broad idea is to assign each UI element to be an observer and InternshipDiary
to be the observable.
Consequently, whenever there is a state change to InternshipDiary
, the list of observers will be notified and updated automatically.
To achieve this observer pattern, we made use of the PropertyChangeSupport
class and the PropertyChangeListener
interface.
PropertyChangeSupport
is a utility class to support the observer pattern by managing a list of listeners (observers) and firing PropertyChangeEvent
to the listeners.
A class that contains an instance of PropertyChangeSupport
is an observable.
On the other hand, a class that implements the PropertyChangeListener
interface is an observer.
The class diagram above showcases our implementation of a two-tier observer-observable structure:
-
InternshipDiary
is an observable -
ModelManager
is both an observable and observer-
It observes any changes to
displayedInternships
contained inInternshipDiary
-
-
StatisticsWindow
is an observer-
It observes any changes to
filteredInternshipApplications
contained inModelManager
-
|
Note
|
|
We will briefly discuss how the observer pattern works in our implementation.
Whenever an object wants to observe changes in another object, it will call the addPropertyChangeListener
function of the PropertyChangeSupport
instance from the appropriate object that it wishes to observe.
It will also have to specify which property of that object it wants to observe.
In our case, when ModelManager
is created, it will call the addPropertyChangeListener
function of the PropertyChangeSupport
instance belonging to InternshipDiary
.
The function call will look like this: addPropertyChangeListener("displayedInternships", this)
where this
is a reference to ModelManager
itself (so that it can be registered as a listener of the displayedInternships
property of InternshipDiary
).
The process is similar for any UI element that wants to observe the filteredInternshipApplications
property of ModelManager
.
As a result, whenever there is a change to the property displayedInternships
in InternshipDiary
, the PropertyChangeSupport
instance of
InternshipDiary
will call firePropertyChange
to emit a PropertyChangeEvent
to ModelManager
.
The emitted event will trigger the propertyChange
function of ModelManager
.
ModelManager
can then retrieve the new reference from the event and update its filteredInternshipApplications
accordingly.
It will then repeat the event emission process to any UI element (e.g. StatisticsWindow
) that is observing the
filteredInternshipApplications
property.
The following activity diagram gives a high-level overview of the above event-driven process.
archival
command|
Note
|
The two-tier observer-observable structure is necessary.
This is because list and archival only changes the reference of displayedInternships . |
When 'ModelManager' updates its property filteredInternshipApplications
with the new reference, UI elements that reference filteredInternshipApplications
will not be aware of the reference update to filteredInternshipApplications
.
Thus, ModelManager
has to notify and update the UI elements as well.
As an extension, our team also implemented enumeration for each property that is being observed. This modification ensures type safety and a way for us to track what properties are observed. This is especially important when many properties are being observed.
Below is the updated class diagram with the implementation of ListenerPropertyType
enumeration.
ListenerPropertyType
As seen from the diagram above, each observable will implement two additional methods to use ListenerPropertyType
enumeration as parameters:
-
addPropertyChangeListener(ListenerPropertyType propertyType, PropertyChangeListener l)
-
firePropertyChange(ListenerPropertyType propertyType, Object newValue)
This forms a layer of abstraction as we would not be allowed to call the addPropertyChangeListener
and firePropertyChange
methods of
PropertyChangeSupport
directly.
Design Considerations
Aspect: How to implement the Archival View system on the backend
-
Alternative 1 (current choice): Maintain three
UniqueInternshipApplicationList
:displayedInternships
,unarchivedInternships
, andarchivedInternships
.displayedInternships
will be used as the reference for other elements to retrieve the list of internship application(s) for usage. Whenever the user executesarchival
, we will update the reference ofdisplayedInternships
toarchivedInternships
and vice-versa. In terms of storage, we will use only one list. This means that whenever we load the list of internship application(s) from the JSON save file, we will filter the internship application(s) appropriately intoarchivedInternships
andunarchivedInternships
inInternshipDiary
. When saving, we will combine botharchivedInternships
andunarchivedInternships
into a single list for storage.-
Pros: No need to modify the storage and its relevant test cases. This provides stability in the refactoring process.
-
Cons: Potentially expensive in terms of computation. Furthermore, we will have to implement observer pattern to handle the reference changes.
-
-
Alternative 2 (previous choice): Manipulate the current view of the internship application list by using Predicate and FilteredList, along with the boolean isArchived variable in
InternshipApplication
. This will easily help us determine which internship application should be rendered.-
Pros: Very easy to implement and less expensive in terms of memory and computation. No need to implement observer pattern as there will be no reference updates.
-
Cons: Potentially unsustainable as conflicts are likely to arise with commands that make heavy use of predicates (e.g.
Find
command).
-
Aspect: How to implement the Observer Pattern
-
Alternative 1 (current choice): Use
PropertyChangeSupport
class andPropertyChangeListener
interface from thejava.beans
package to support our implementation.-
Pros: Easy and intuitive to use. Good built-in support. Seems to be highly recommended by other users.
-
Cons: Seemingly negligible for our usage.
-
-
Alternative 2: Use Java’s
Observable
class andObserver
interface.-
Pros: Seemingly negligible for our usage.
-
Cons: The package is deprecated. Harder to understand and implement.
-
Archive & Unarchive
To allow users to move internship application(s) between the main and archival list of internship application(s), we implemented the commands archive
and unarchive
:
-
archive
allows a user to move internship application(s) from the main list to the archival list. -
unarchive
allows a user to move internship application(s) from the archival list to the main list.
The following activity diagram depicts the behaviour of an archive
command.
You may use it as a reference for unarchive
as well.
The activity diagrams for both are very similar.
archive
CommandWhile implementing the archive
and unarchive
commands, we realised that users may sometimes want to cherry-pick multiple internship application(s) to execute on or mass-execute on certain types of internship application(s).
For example, a user may want to archive all the internship application(s) that have the status of "rejected".
Commands like archive
, unarchive
, and delete
can be seen as removal-based commands.
This is because the utility of such functions are very similar; in that they serve to modify the list by removing items.
Therefore, we specifically created a new class, RemovalBasedCommand
, to extend the functionality of removal-based commands like archive
, unarchive
, and delete
.
Through this new class, users will be able to execute the commands on multiple internship applications.
In the following section, we will delve slightly deeper and discuss about the lower-level implementation of the extended functionality.
Implementation
The following class diagram depicts our implementation of the extended functionality.
RemovalBasedCommand
and RemovalBasedCommandExecutionTypeParser
with its associated classesThe idea of the implementation can be summarized as follows:
-
The purpose of
RemovalBasedCommandExecutionTypeParser
is solely to determine the execution type of the command by parsing the user input and callingRemovalBasedCommandExecutionType#getExecutionType
. -
On the other hand,
RemovalBasedCommand
is responsible for creating and executing the appropriate command based on thecommandWord
that was generated from the user input and passed down fromInternshipDiaryParser
.
Users are able to execute removal-based commands like archive
according to the execution types we have in the enumeration class RemovalBasedCommandExecutionType
.
We have implemented the following execution types: BY_INDEX
, BY_INDICES
, and BY_FIELD
.
For the execution type BY_FIELD
, users can only execute by the Status
field of an internship application currently.
The format of a removal-based command can take on any of the following forms:
-
command
INDEX -
command
INDEX, [INDEX], [INDEX], …
(where INDEX within the bracket is optional and there can only be as many INDEX as the number of internship application(s) displayed) -
command
s/STATUS
(where STATUS refers to a valid internship application status)
Note that command
can be any one of the removal-based commands.
It is important to note that each RemovalBasedCommandExecutionType
works similarly.
At the core, all of them involves retrieving the index of an internship application to execute on.
The difference lies in the pre-processing stage — the steps an execution type takes to retrieve all the required indices.
Therefore, to ensure succinctness, we will only be illustrating the usage of the command archive
with the execution type BY_FIELD
.
Other variations of removal-based commands and execution types are similar.
The following sequence diagram provides a high-level overview of how the archive
command with the execution type of BY_FIELD
is executed in our application.
archive s/rejected
commandAs illustrated in the diagram above, the pre-processing steps of BY_FIELD
involves applying the appropriate predicate to filter the internship applications and then converting these internship applications to their respective index.
This provides us with required indices that we will execute the removal-based command archive
on.
|
Note
|
We have implemented the mechanism to be reusable and extensible for new commands and execution types. |
This is evident in the sequence diagram above, where the different kinds of removal-based commands are abstracted from the diagram and referred to simply as RemovalBasedCommand
.
This means that the above diagram is applicable to archive
, unarchive
, delete
, and any other removal-based commands that we may wish to introduce in the future.
Furthermore, if we ever wish to create a new RemovalBasedCommandExecutionType
(on top of BY_INDEX
, BY_INDICES
, and BY_FIELD
), we may simply add a new alternative path to the diagram (or a new switch condition in terms of code).
The following sequence diagram captures how RemovalBasedCommandExecuteTypeParser
parses the input and determines the execution type of the command.
It also shows how a RemovalBasedCommand
is created with the appropriate RemovalBasedCommandExecutionType
and command word.
RemovalBasedCommandExecuteTypeParser
parses input and determines the execution type of commandAs seen from the diagram above, the parser determined the execution type to be BY_FIELD
and generated the appropriate predicate to construct a RemovalBasedCommand
instance.
Based on the command word passed in to construct the RemovalBasedCommand
instance, RemovalBasedCommand
creates a lazy lambda function that can be called to construct the appropriate removal-based command for execution.
The following sequence diagram depicts the above behaviour.
RemovalBasedCommand
instanceAs the command word is archive
, a lazy lambda function to construct an ArchiveCommand
is returned.
The following sequence diagram captures the process of executing the lazy removal-based command on one index. This particular index allows us to retrieve the appropriate internship application.
archive
, on one indexIt can be seen that the previously-generated lazy command is executed in the above sequence diagram.
ArchiveCommand
is constructed and subsequently executed on the index provided, by making the appropriate function call to the model to execute on the internship application.
In this case, archiveInternshipApplication
is called.
The following sequence diagram captures the process of executing the lazy ArchiveCommand
on indices.
archive
, on indicesAs seen above, executeLazyCommandOnIndices
merely reuses the function executeLazyCommandOnIndex
(from the previous sequence diagram) by running it on every index provided.
The feedback from each execution is cumulatively concatenated to form a single feedback.
The following sequence diagram captures the process of re-creating the command result in RemovalBasedCommand
by using the feedback obtained from the specific command execution, which is ArchiveCommand
in our example.
RemovalBasedCommand
Design Considerations
Aspect: How to implement Multiple Execution Types for Removal-Based Commands
-
Alternative 1 (current choice): Use encapsulation to hold the appropriate command word, which will then be used to generate the removal-based command that will execute based on the execute type provided.
RemovalBasedCommand
will store the command word of the appropriate removal-based command and create the command whenRemovalBasedCommand
is executed. This removal-based command will then be executed on the index/indices provided according to the execution type.-
Pros: Easier to implement and convey the idea to team members.
-
Cons: Will require multiple case handling (e.g. switch cases). Polymorphism may be a better solution in terms of code extensibility and elegance.
-
-
Alternative 2: Use polymorphism where each removal-based command extends the class
RemovalBasedCommand
and inherit the appropriate execution type methods.-
Pros: Code will likely be more extensible and elegant.
-
Cons: Likely to require major redesigning and refactoring of existing logic codebase because we will have to modify
Command
class. Furthermore, the changes may affect areas that we may not have considered. This is risky and will take a lot of time, effort, and team discussion.
-
Statistics Feature
This feature allows users to view relevant metrics about their internship application(s).
Currently, the tracked metrics include:
-
the amount of internship applications in each status
-
the percentage of internship applications in each status
Implementation
The following class diagram gives an overview of our implementation of the statistics feature.
Statistics
and its associated classesUsers will be able to view the metrics from two areas:
-
StatisticsBarFooter
-
found at the bottom of the application in the form of a bar footer
-
serves as a quick view of the metrics in terms of counters
-
-
StatisticsWindow
-
displayed on a separate window that is opened upon the command
stats
-
serves as an additional graphical statistics interface for users to get a visual breakdown of the metrics
(currently in the form of a bar chart and a pie chart)
-
The Statistics
object is used to generate statistics for any internship application list that it is given.
StatisticsWindow
and StatisticsBarFooter
each contains an instance of Statistics
that helps them compute the relevant statistics whenever there is any update to the internship application list.
The internship application list can be updated either due to a change in reference in displayedInternships
from InternshipDiary
(e.g. archival
and list
) or any modifications to the current internship application list (e.g. add
, delete
, edit
, archive
, unarchive
, find
).
The following activity diagram illustrates how StatisticsWindow
(StatisticsBarFooter
shares the same workflow) is notified of the updates in the internship application list and how it subsequently updates the statistics.
StatisticsWindow
is notified of updates in the internship application list and how statistics is updated accordinglyUpon creation of the StatisticsWindow
and StatisticsBarFooter
, each of them will attach an event listener to the internship application list that it was given.
This event listener will notify them of any internal modifications to the internship application list.
On the other hand, both StatisticsWindow
and StatisticsBarFooter
will register themselves as observers as well.
This is so that the implemented observer pattern can notify them of any changes in the internship application list reference and update them with the new reference accordingly.
Any of the two updates above will trigger the Statistics
to recompute with the updated internship application list.
StatisticsWindow
and StatisticsBarFooter
will then retrieve the required computed metrics from Statistics
and re-bind the them to the UI accordingly.
Design Considerations
Aspect: Which list to retrieve data from to generate statistics
-
Alternative 1 (current choice): Use filtered ObservableList. The filtered list is dynamically updated by
find
andsort
command. The statistics model will generate statistics based on the dynamic filtering changes that occur in either the main list or archival list (the current view selected by user).-
Pros: Users will be able to choose which list they want to view the relevant statistics for. Works well with
archival
,list
, andfind
commands that dynamically changes the list. -
Cons: Often re-computation upon changes in the filtered list may cause some performance bottleneck.
-
-
Alternative 2: Use the base list that contains all of the internship application(s). The base list is not filtered according to predicate(s) set by users.
-
Pros: Require less re-computation compared to using filtered ObservableList, as it only re-computes upon addition(s), deletion(s), or changes in an internship application stored in the list.
-
Cons: May be unintuitive to some extent for users when the statistics do not tally with the current view of the list.
-
Aspect: How to store the statistics generated from data
A list of internship application(s) will be passed into the statistics model and upon function call, the statistics model will iterate through the list and generate/update the latest statistics accordingly.
-
Alternative 1 (current choice): Store the mapping between each status and count using a HashMap. The idea is to retrieve all the statuses available from the enum (whenever the statistics model is created) and create a HashMap with those status as the key and respective count as the value.
-
Pros: Extensible and reusable. Regardless of any changes, this system can dynamically handle the addition, deletion, or changes in statuses.
-
Cons: Seemingly negligible cons for our usage.
-
-
Alternative 2 (previous choice): Store each status count in separate variables that are initialized upon the creation of statistics model.
-
Pros: Straightforward and very easy to understand for future developers.
-
Cons: Very inextensible as we need to create new variables for new statuses each time.
-


Awesome Standard
Documenting the explosion of packages in the standard
ecosystem!
standard
- standard - JavaScript Standard Style. One Style to Rule Them All!
usage stats
- modules that use standard - stats from the npm registry
- npm-stat.com - download count graphs
- standard-packages - List of packages that use
standard
packages used by standard
- eslint - AST-based pattern checker for JavaScript
- standard-engine - standard's guts, extracted into a reuseable package. build your own!
- eslint-config-standard - standard eslint rules, as a shareable config
- eslint-config-standard-react - standard eslint rules for React and JSX
- eslint-plugin-standard - standard custom eslint rules (not part of eslint core)
automatic code formatters
- standard-format - standard automatic code formatter
- "unix commands" gist - A list of search and replace unix commands to help make a node repository 'standard' compliant
editor snippets
- Sublime: sublime-js-snippets
- Atom: standardjs-snippets
pretty terminal output (reporters)
- snazzy - Format JavaScript Standard Style as Stylish (i.e. snazzy) output
- standard-tap - Format JavaScript Standard Style as TAP output
- standard-json - Format JavaScript Standard Style output to a JSON array
- standard-reporter - Reporters for feross/standard via unix pipes, many options
build tools
- grunt-standard - Grunt plugin for standard
- gulp-standard - Gulp plugin for standard
- gulp-any-standard - Gulp plugin that supports standard and its forks
- mocha-standard - Integrates standard into your mocha tests
- standard-loader - Lint webpack builds with standard
- generator-babel-standard - Yeoman generator for new packages with babel and standard
forks
- semistandard - standard, with semicolons
- uber-standard - fork by the Uber team
- videojs-standard - fork by the video.js team
- yodlr-standard - fork by the yodlr team
- happiness - standard customized to make @JedWatson happy
- doublestandard - standard, with even more semicolons
- xo - "JavaScript happiness style"
- jsw - "the spec doesnt care about semicolons and neither should you"
- obama - Move forward and standardize with Obama
- aStandard - A stricter standard made for babel and es7
PRs welcome!
License
To the extent possible under law, Feross Aboukhadijeh has waived all copyright and related or neighboring rights to this work.


The MIT License (MIT)
Copyright (c) 2016 Rafael Corrêa Gomes, https://rafaelstz.github.io/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


<attributedef>
The <attributedef>
element specifies the attribute that is bound to a
set of controlled values. This binding restricts the permissible values for the attribute
to those that are contained in the set of controlled values.
Category: Subject scheme elements


--- layout: post permalink: sequentialt.html Tags: Array NameOfCoupon: SequentialT Cash Back Summary: See our SequentialT Coupon Code, SequentialT Rebate, SequentialT Promo Code, SequentialT Discount, SequentialT Coupon Cash Back Rebate here. MetaKeywords: SequentialT Coupon Code, SequentialT Rebate, SequentialT Promo Code, SequentialT Cash Back Rebate, SequentialT Discount, SequentialT Coupon Image: images/26055.com/images/ LinkURL: http://www.shareasale.com/r.cfm?b=216184&u=412002&m=26055 affiliate_url_link: http://www.icouponblog.com/jane.php?id=121 thesis_readmore: See the SequentialT Coupon thesis_thumb: http://www.icouponblog.com/tn.php?merchantURL=sequentialt.com Title: Save 5% - SequentialT Coupon Code for sequentialt.com. SequentialT Rebate & Discount thesis_description: Our SequentialT Discount Coupon Code for sequentialt.com. We have the best SequentialT Rebate anywhere. thesis_keywords: SequentialT, SequentialT Coupon Code, SequentialT Discount, SequentialT Rebate product_name: SequentialT hop_url: http://www.icouponblog.com/hop.php?id=121 ---
Connect to someone pulling a rickshaw in India, or sipping coffee in Paris. Feel a sense of solidarity and connection with the world when you put on a SequentialT shirt. SequentialT is a global unity organization that strives to connect people around the world with an expression of solidarity. This connection is represented through sequentially-numbered shirts, each one unique for every person. Get 5% cash back with our SequentialT coupon.
SequentialT is a global, social experiment. SequentialT shirts will be worn from Azerbaijan to Zimbabwe and from Uruguay to the Maldives. Proceeds from these SequentialT shirts will benefit charities selected by SequentialT members. These charities are for people, animal or earth causes. SequentialT shirts are 100% organic and climate neutral. SequentialT are the most progressively ethical clothing on earth. They are manufactured solely using sustainable energy generated from wind and solar power. Buy SequentialT shirt using our 5% cash back coupon and save money.
Be part of the world. Feel connected to people you wouldn’t otherwise know. Feel solidarity in the common cause of making the world a better, ecologically, safe and environmentally place SequentialT has taken up the exciting and unique task of uniting the world through a shirt. Join the cause. Buy SequentialT shirt with our discount coupon and save money while serving a good cause.


acos
, acosf
—arc cosine#include <math.h> double acos(double x); float acosf(float x);
Description
acos
computes the inverse cosine (arc cosine) of the input value.
Arguments to acos
must be in the range −1 to 1.
acosf
is identical to acos
, except that it performs
its calculations on floats
.
Returns
acos
and acosf
return values in radians, in the range of 0 to pi.
If x is not between −1 and 1, the returned value is NaN
(not a number), and the global variable errno
is set to EDOM
.


--- layout: post title: "REST lesson learned: Consider a home link on all resources" description: "Add home links on RESTful resources." date: 2013-05-02 10:51 UTC tags: [Software Design, Services, REST] --- {% include JB/setup %}
{{ page.description }}
This suggestion is part of my REST lessons learned series of blog posts. Contrary to the previous posts, this advice doesn't originate from a lesson learned the hard way, but is more of a gentle suggestion.
When designing a level 3 RESTful API, I've found that it's often helpful to think about design issues in terms of: how would you design it if it was a web site? On web sites, we don't ask users to construct URLs and enter them into the browser's address bar. On web sites, users follow links (and fill out forms). Many well-designed web sites are actually HATEOAS services, so it makes sense to learn from them when designing RESTful APIs.
One almost universal principle for well-designed web sites is that they always have a 'home' link (usually in the top left corner). It makes sense to transfer this principle to RESTful APIs.
All the RESTful APIs that I've helped design so far have had a single 'home' resource, which acts as a starting point for all clients. This is the only published URL for the entire API. From that starting page, clients must follow (semantic) links in order to accomplish their goals.
As an example, here's a 'home' resource on a hypothetical product catalog API:
<home xmlns="http://fnaah.ploeh.dk/productcatalog/2013/05" xmlns:atom="http://www.w3.org/2005/Atom"> <atom:link href="http://catalog.api.ploeh.dk/products/1234" rel="http://catalog.api.ploeh.dk/docs/rels/products/discounted" /> <atom:link href="http://catalog.api.ploeh.dk/products/5678" rel="http://catalog.api.ploeh.dk/docs/rels/products/discounted" /> <atom:link href="http://catalog.api.ploeh.dk/products/1337" rel="http://catalog.api.ploeh.dk/docs/rels/products/discounted" /> <atom:link href="http://catalog.api.ploeh.dk/categories" rel="http://catalog.api.ploeh.dk/docs/rels/product/categories" /> </home>
From this (rather sparse) 'home' resource, you can view each discounted product by following the discounted link, or you can browse the catalog by following the categories link.
If you follow one of the discounted links, you get a new resource:
<product xmlns="http://fnaah.ploeh.dk/productcatalog/2013/05" xmlns:atom="http://www.w3.org/2005/Atom"> <atom:link href="http://catalog.api.ploeh.dk" rel="http://catalog.api.ploeh.dk/docs/rels/home" /> <atom:link href="http://catalog.api.ploeh.dk/categories/chocolate" rel="http://catalog.api.ploeh.dk/docs/rels/category" /> <atom:link href="http://catalog.api.ploeh.dk/categories/gourmet" rel="http://catalog.api.ploeh.dk/docs/rels/category" /> <name>Fine Criollo dark chocolate</name> <price>50 DKK</price> <weight>100 g</weight> </product>
Notice that in addition to the two category links, the resource representation also contains a home link, enabling the client to go back to the 'home' resource.
Having a home link on all resources is another courtesy to the client, just like avoiding 204 responses - in fact, if you can't think of anything else to return instead of 204 (No Content), at the very least, you could return a home link.
In the above examples, I didn't obfuscate the URLs, but I would do that for a real REST API. The reason I didn't obfuscate the URLs here is to make the example easier to understand.