After looking into EWM Discovery, how can one create or update a work item using the techniques explained so far? This post will look into the steps that are required to create and update a work item. The techniques explained in the previous posts in this series are important. If necessary, go back to the previous posts to understand the details.

This blog was originally separated into two sections, creating a work item and then updating the work item. The first part mentioned programming and Python, the second used RESTClient to demonstrate the concepts. This was just due to the code I have written so far and due to complexity of the operations. The blog post was recently updated with Python code snippets for work item update and additional content.

Update: The blog post has also been rearranged and updated to separate getting a work item and updating a work item.

Update: The blog post has been rearranged and updated to show the usage of the oslc.properties query parameter for partial get and update.

Update: The blog post has been rearranged and updated to show how to resolve a work item and setting the resolution.

Update: The blog post has been updated with how to get the complete workflow information needed to navigate the workflow states and actions.

Context of the blog post is the series

This is the series of planned posts I intent to publish over time. Most of the examples will be EWM based, but quite a lot of the content applies to more ELM applications. The examples where performed with versions and 7.0.x.

External Links

I used at least the following links for exploring this mechanism.

Discover the Creation Factory

To create a work item using the OSLC API requires some information that is provided by the OSLC API and can be discovered. To create a work item first requires a URI/URL of a creation factory providing the capability to create the work item.

EWM supports customizable work item types with customizable attributes of customizable attribute types. Each work item type has its own creation factory URL that needs to be looked up to create a work item of that type.

Work item types have potentially different sets of attributes configured. Each attribute has a type from a number of available attribute types. EWM allows to create custom attribute types. Some of the attribute types are primitive and are easy to handle. As an example the summary of a work item is just a string and it is easy to provide data. Other attribute types are far more complex. Many attributes are enumeration types. Enumerations are a number of available literals with an ID and a display name for each literal. A work item usually has an owner or subscribers. These represent users that are available in the system referenced by a unique URI. Work items can be assigned to a project or team area, which are other attribute types available in a project areas process. Which process area a work item is assigned to is controlled by a Category that maps a user readable string to the process area represented by its URI.

Note, some data that shows up in the work item is not attribute based. As example the collection of reviews and approvals, the attachments and the comments are not attribute type based. Some attributes that show up are only presentations or are calculated and can not be changed. Some of the not attribute based data is provided as pseudo attribute e.g. to be able to export the data.

To create a work item it is necessary to find out which attributes of which types a work item can have and which values the attribute of such a type can have. Attribute types can be single value such as enumerations or strings or they can have multiple values such as enumeration lists or string lists. All this information is required when creating a work item.

The information which work item attributes with what types a work item type can have, can be discovered in OSLC APIs as part of discovering the creation factory. The information is accessible via a resource shape. How the discovery process works in general is described in EWM Discovery.

Reminder, for all requests use the mandatory OSLC header:

OSLC-Core-Version 2.0

To receive RDF encoded data use the Accept header and for sending RDF use the content Type header as shown below:

Accept application/rdf+xml; charset=utf-8
Content Type application/rdf+xml; charset=utf-8

The image below shows the RDF form of a part of the service provider catalog for a project area. Using the namespace


the oslc:CreationFactory entry contains the resourceType(s) and the resourceShape. The first resourceType http://open-services.net/ns/cm#ChangeRequest is used for OSLC integrations. The second resourceType provides the link to the work item type definition. The entry oslc:creation contains the creation factory URI.

RDF form of the creation factory for defect and task

To receive JSON encoded data use the Accept header and for sending JSON use the content Type header as shown below.

Accept application/json; charset=utf-8
Content Type application/json; charset=utf-8

The image below shows the JSON format of the creation factory entry for the work item type defect. The data is provided analogue to the RDF format and can also be used to access the data for the creation factories.

JSON form of the creation factory for defect

Discover Resource Type and Shape

Following the resourceType URI provides the details of the work item type. The image below shows the details for the defect. Getting the resourceType

GET https://elm.example.com:9443/ccm/oslc/types/_8e5qfFpmEeukW7cqqDjAuA/defect

with the headers introduced above provides more details. The display name is Defect and the work item type ID is defect. The data also contains the URI for the EWM project area that defines the work item type. The image below shows the result of such a GET request.

Type definition for defect

The Python code block below processes the RDF data and extracts the important data. The important take away are the predicates to select the information to be iterated.

Extract the creation factory information

The code operates on some simplifications. The code gets the work item type ID by filtering out the entry that starts with the public URI root. The code assumes that the end segment is equal to the work item type ID. This just saves the call to the resourceType URI which would contain the information. The code gets the creation factory URI and the resource shape URI.

To be able to create a work item, GET the resource shape using its URI and the headers described above. As an example:

GET https://elm.example.com:9443/ccm/oslc/context/_8e5qfFpmEeukW7cqqDjAuA/shapes/workitems/defect

The resource shape contains a number of attribute type definitions for the attributes (and link types) the work item type can have. The information contains the name (id) of the type, the title (display name) of the attribute type, the allowed values, the default value, if the attribute is read only etc.
The image below shows one example for the attribute Priority with ID priority, the default attribute literal and the link to the allowed values. The attribute is defined for values in an enumeration. The allowed values URI describes the available values defined in the enumeration.

Allowed Values

To get the allowed values for the attribute Priority perform a GET using the shape URI. As always provide the OSLC headers.

GET https://elm.example.com:9443/ccm/oslc/context/_8e5qfFpmEeukW7cqqDjAuA/shapes/workitems/defect/property/internalPriority/allowedValues

The result of the request is shown below.

Allowed values for the work item attribute Priority with ID internalPriority

Note that the allowed values, the priority enumeration literals, do not provide any information about the display name or any other details. To get the display name it is necessary to GET (OSLC headers!) each of the priority literal resource URIs and analyze the results.

To create a work item, the next steps would be to get allowed values for all required attributes and to create a request body containing this information.

Required Attributes

At the time of writing, OSLC does not provide a mechanism to get the list of attributes that are required to create a work item due to restrictions in the process. If the target system requires special attributes to be set e.g. in certain states, or expects special values, the work item creation or save will fail. To successfully create or update work items, it is necessary to know such limitations ore provide a configuration capability to adjust for such information.

Request Body

For the JKE Banking Example that is shipped with EWM, the process requires the following information to create a defect:

  • Summary
  • Category

To make the example a bit nicer we also want to also set the description of the work item. The summary and the description attributes are easy. This is just a string value. The category is the mapping to a process area. This is not a trivial attribute and it is necessary to get an allowed value. A valid approach is to get all allowed values into an array and to pick one value. If it is desired to find the correct allowed value based on a display value or some other characteristics, iterate all allowed value URIs and get the details.

The code below is the code that creates the payload for the request body needed to create the work item. It looks more complicated than it is, probably because of the RDF library. The code creates an empty graph, a node for the work item and then adds the predicate object configuration that represents the desired information e.g. the text for the summary and the description.

Create the payload and the work item

The payloadString serialized in createRDFWorkItem from the graph simply looks like the RDF XML below. It only contains the information about the summary, description and the category

Creating the Work Item

To create the work item, POST to the work item types creation factory URI like shown below:

POST https://elm.example.com:9443/ccm/oslc/contexts/_8e5qfFpmEeukW7cqqDjAuA/workitems/defect

Provide the required headers to declare OSLC, and the headers to control the content encoding that were already explained. The Content-Type defines the format of the request body. The request body is the payloadString created above.

OSLC-Core-Version 2.0
Accept application/rdf+xml; charset=utf-8
Content-type application/rdf+xml; charset=utf-8

The response status should be a 201. The response headers should contain the location header with the URI of the work item. The URI of the work item is the unique URI of the work item and can be used in subsequent operations to identify the work item. E.g. in GET, or PUT operations to retrieve or modify the work item. The URI is also used in the process of linking work items. The URI can be used in a redirect to open the work item editor in a web UI.

The response headers contain a new important header called ETag. The ETag value describes the state of the work item. Every time the work item is changed it gets a new ETag. When trying to update a work item it is necessary to send the ETag value from the previous GET in a special If-Match header. The server can use this value to evaluate the state of the work item the update is supposed to be applied to based on the current ETag. If the ETag in the request is not the current ETag of the work item state, the request is based on stale data. New changes where done to the work item. The server detects the mismatch and alerts the client that the change can not be executed. The client needs to refresh the work item information, GET the latest state, modify it accordingly and retry to update the work item based on this information.

The response body sent back by the server, contains the data for the new work item. The information is usually much more than the information that went into the creation of the work item. The server creates several special attributes such as the creation date, the creator and similar information. In addition attributes with default values are automatically set and will be returned.

Response body for the POST to the creation factory.

All subsequent operations on the work item should be based on this state, or a never version state that was retrieved by a GET on the work item URI.

The code below shows the creation of the work item and gets the work item URI from the results location header and the etag from the results ETag header.

The work item creation and the response analysis for RDF.

The same process can be used with the JSON format. The image below shows an example for a work item creation using the JSON encoding with the same attributes used with RDF above.

JSON payload to create a work item

JSON requires to use the headers shown below instead. The header Content-Type only needs to be set when a request body is sent.

OSLC-Core-Version 2.0
Accept application/json; charset=utf-8
Content-type application/json; charset=utf-8

Get a Work Item

The following sequence is done with the RESTClient extension installed in Firefox. RESTClient is a Firefox extension that runs in the browser. This allows you to log in to the server with the web UI in Firefox and then use the RESTClient without worrying about the authentication because RESTClient reuses the authentication done in the UI. Another Option would be Postman, but that requires to log into the CCM server as explained here. Install RESTClient and Firefox to do these steps yourself.

To get a work item we need the public URI of the work item. The public URI was returned in the Location header when creating the work item. It can also be located e.g. using an OSLC Query. The public URI has this form:


where the number at the end is the work item unique ID for the repository. Note that the URI of the work item is not the URL for the work item editor you get when you copy the address URL from the browser. That URL contains information like the project area name and is not stable.

Open the Web UI of EWM. Open a work item e.g. the one created before. Get the work item URI by copying it out of the Web UI like shown below. You can also use the work item URI from the automation to create the work item.

Use copy link location on the icon to get the work item URI

To get the current state of the work item it is necessary to perform a HTTP GET operation on the public URI. Open a RESTClient and prepare to get a work item. As an example select GET as method and paste the work item URI into the URL address.

GET https://elm.example.com:9443/ccm/resource/itemName/com.ibm.team.workitem.WorkItem/242

Use the OSLC, Accept and Content Type headers as explained above.

Prepare the GET request

Push the Send button to execute the request.

The request should succeed with a status 200. Here the Request and the response headers in RESTClient in Firefox.

The successful GET request to read the work item 242

Browse the response Headers tab first. Note the ETag header. This is important for a later update.

Property Selection

Update: It is possible to use the oslc.properties query parameter to select which properties (attributes) are of interest in this OSLC request. Note that the oslc.properties require URL encoding to allow to send them in the request URL. The code shown below shows which part of the URI needs to be URL encoded. It is the the comma separated section of property definitions behind the


The oslc.properties can be used in a GET request. In this case it can be used to specify which properties the requestor is interested in. The server does not have to collect and transmit all properties, but only the ones of interest. This saves computing resources and bandwidth.

The image below shows the result of a GET request on a work item URI, providing a oslc.properties selection. Note the response body only returns a limited amount of properties compared to the full GET above.

OSLC properties selection in a GET request.

The image below shows how the requested properties are selected using Python code.

Selection of the properties the request is interested in.

Update a Work Item

To update a work item it is necessary to get the current state of the work item. For this it is necessary to perform a HTTP GET operation on the public URI as shown above. Go back to the result of the previous section or open a RESTClient and prepare to get a work item. For the latter make sure to select GET as method have the work item URI into the URL address.

Make sure to use the OSLC, Accept and Content Type headers as explained above.

Perform the GET request

Push the Send button to execute the request.

The request should succeed with a status 200.

The ETAG in the successful GET request to read the work item 242

Browse the response Headers tab first to prepare for updating the work item. Copy the ETag header into a text editor, we need the value of the header later.

Switch over to the Response tab. Search the content for :title to locate the XML containing the work item summary attribute. Mark the response body and copy its content.

The work item summary attribute

Open a new RESTClient window. Paste the response body from the previous GET request into the request body of the new request. Copy the work item URI into the address URL. Change the method to PUT.

Search for the :title in the new request body. Modify the text enclosed in the tag e.g. to An updated summary like below.

<dcterms:title rdf:parseType="Literal">An updated summary</dcterms:title>

Add the OSLC and content headers:

OSLC-Core-Version 2.0
Accept application/json; charset=utf-8
Content-type application/json; charset=utf-8

Now add another header If-Match with the ETag value from the GET method.

If-Match "c6eebbc9-257c-335a-9726-287f39732012"

See the image below how the request looks like. Perform the send.

The update should succeed with a 200 status and contain a new ETag.

Successful update with a new ETAG.

Open the work item in a work item editor. You can do this by pasting the work item URI into the browser address field. If the work item editor is already open the editor should show the work item was changed. Refresh the editor if this is the case. The summary attribute was successfully updated:

The updated work item summary in the Web UI

Performing a subsequent GET in the initial RESTClient window provides the same information and the new ETag. The ETag will change if the work item is changed again.

Update: change a work item in Python code

The code below retrieves the work item based on its URI.

Getting a work item and the ETag for updating it.

After getting the work item and the etag, the response body is parsed into a graph that has the required namespaces bound to it. The response has the work item URI as subject in the response, this is retrieved and validated. The work item data is analyzed and some data is pulled out by querying the graph for objects with a specific predicate (e.g. DCTERMS.identifier) and the data is printed.

The code below shows the modification of the summary of the work item.

Updating the work item with If-Match header

The new summary is computed based on a timestamp. Then the value of the subject node is set using the code below.

# Set a RDF entry for a node, predicate and object.
    def setRDFAttribute(self, graph, node, rdfPredicate, rdfObject):
        graph.set((node, rdfPredicate, rdfObject))

The update header is created, including the If-Match header with the work items ETag from the get operation. The RDF graph is serialized to be sent. Then the PUT operation is performed. The change will have a new ETag, so that is received.

The response body is parsed into an RDF graph again and the information for some of the attributes is again analyzed and printed. The image below shows the console output that is created.

Successful update of a work item with the original and new ETag

Property Selection

Update: It is possible to use the oslc.properties query parameter to select which properties (attributes) are of interest in this OSLC request.

The oslc.properties can also be used in create and update requests. This can be used for partial updates. Please carefully read this section about updating work items and also check the examples that are provided. Especially for creating and removing links and custom attributes.

For using the oslc.properties query parameter, to limit the amount of properties to a subset, please check the sections oslc.select and oslc.properties in the post EWM OSLC Query API. Syntax and encoding for these query parameters are the same. You have to provide the oslc.properties as a query parameter URL encoded like shown below.

PUT https://elm.example.com:9443/ccm/resource/itemName/com.ibm.team.workitem.WorkItem/242?oslc.properties=rdf%3Atype%2Cdcterms%3Aidentifier%2Cdcterms%3Atitle%2Cdcterms%3Adescription%2Cdcterms%3Amodified%2Crtc_cm%3AmodifiedBy%2Cdcterms%3Acreated%2Cdcterms%3Acreator

As a summary, the usage of the oslc.properties query parameter allows to

  • Limit the properties returned in a GET request to the selected properties. Instead of sending all properties, the server can just respond with the sub set of properties.
  • Limit the properties that are considered to be received to the selected properties in PUT and POST requests. This can be used to just have to send a limited amount of attributes, and not all, to achieve a partial update. This can also used to remove properties by including a property in the oslc.properties but not sending data for it.

The link above mentions to use the PATCH method for partial updates a couple of times. I briefly tried to use PATCH to partially update a work item, but I got an “Error 501: Not Implemented”, so I assume PATCH is not available.

Work Item Workflow State change

One important work item attribute is the workflow state also abbreviated with state of the work item (not to be confused with the ETag). When checking the Resource Oriented Work Item API V2 it mentions that the state is read only. It mentions the capability to use an action to perform a state change, but there is no documentation provided that shows how that works. Digging deeper into the Jazz.net forum there are answers that hint on how it could work, but every one of the answers I found was lacking some detail. Here what I was able to come up with to make it work for me.

The work item workflow is defining the states of the workflow and actions that are valid to get from one state to another. States and actions have unique ID’s.

Analyzing the resource shape of the work item type, the state attribute with ID internalState can be located. The attribute has allowed values that can be discovered. The allowed values are the states of the workflow. As an example for one state there is a URI like below:


We are not interested in the state, we need the ID of the action to perform the workflow action. I have not found any simple way to discover the URI to get the workflow actions. There is however a pattern how to access the required information for workflows and actions and other information required to manipulate the workflow state of a work item.

Looking at the path of the URI for the workflow state reveals that the path section after the section workflows is the project area ID. The next path section is states and the section after that describes the workflow ID. The last section is the workflow state ID.

If we remove the workflow state ID section, and perform an GET on the resulting URI e.g.

GET https://elm.example.com:9443/ccm/oslc/workflows/_8e5qfFpmEeukW7cqqDjAuA/states/com.ibm.team.workitem.defectWorkflow

the resulting response is a list of the workflow states available for the workflow.

Please note, that I experienced issues with the headers to be used here, dependent on the headers used different information was returned in some cases. I would suggest to test using the OSLC headers. If there is a lack of information try to only use the header Accept application/xml (or application/json). The result could contain more information. Please note that in this case the format is not RDF.

If we replace the section states in the URI by actions we get an URI that allows to GET all the workflow actions.

GET https://elm.example.com:9443/ccm/oslc/workflows/_8e5qfFpmEeukW7cqqDjAuA/actions/com.ibm.team.workitem.defectWorkflow

Accept application/xml

Please note, to get the complete workflow information, use only the header Accept application/xml (or application/json). Do not use the Accept application/rdf+xml and do not use the OSLC-Core-Version or any other header. Run the call as shown above.

This way you receive the full workflow table. This contains the information of the workflow action including the resulting state. Given this information it is then possible to extract all workflow information necessary to navigate the workflow. I found this hint in this answer.

To get the information in JSON use only the header application/json.

The image below shows how the complete workflow information looks like, if you get it in the correct way.

The complete workflow information, including the result state of an action.

Once a desired workflow action ID is selected, it is possible to perform a workflow action. This can be achieved by adding a query parameter ?_action=<actionID>, to the work item URI, where <actionID> is replaced by the ID found as workflow action. The result is shown in the image below. Please note the familiar OSLC and content headers as well as the ETag for the last state of the work item are needed as well.

Updating the work item performing a workflow action with an empty resource representation.

It is also necessary to send the representation of the work item, otherwise the PUT call will fail. To get an ETag, it is necessary to do a GET, so all the information is already available. By default OSLC expects the complete representation and deletes data that is no longer available in the request.

I have tried to send an “empty” work item representation as hinted in one of the forum questions and the one shown above in the image and below as code worked for me. Note that there is no guarantee that this works with all versions and forever. An attempt to do a partial update using PATCH resulted in an not implemented response. In general see some hints on partial representations in Resource Oriented Work Item API V2.

Important Update about partial update: Please see the Updating Work Items section in the Resource Oriented Work Item API with OSLC_CM 1.0 wiki page and scan through the documentation, especially for partial update. Note the usage of the query parameter oslc_cm.properties. By providing a list of properties that is to be updated it is possible to send only part of the representation containing said properties. The oslc_cm.properties uses the same syntax used by the oslc_cm.select statement. See the post EWM OSLC Query API and check the section about oslc.select for how to create, compose and encode the parameter.

To get the minimal RDF shown here, I cut out all content and stripped it down to the bare minimum. RDF libraries should be able to serialize empty graphs as well and it should be easy enough to find a minimal empty body for JSON.


The URL below successfully updated the work item state without the need to pass additional attributes. The minimal request body above was used with the URL below and the work item state update was successfully performed.

PUT https://elm.example.com:9443/ccm/resource/itemName/com.ibm.team.workitem.WorkItem/241?_action=https://elm.example.com:9443/ccm/oslc/workflows/_8e5qfFpmEeukW7cqqDjAuA/actions/com.ibm.team.workitem.defectWorkflow/com.ibm.team.workitem.defectWorkflow.action.startWorking&oslc.properties=

With headers:

OSLC-Core-Version 2.0
Accept Type application/rdf+xml; charset=utf-8
Content Type application/rdf+xml; charset=utf-8
If-Match "fcd3b360-d152-367d-956e-d1f9f428ced4"

Note that the oslc.properties statement did not work with rdf.nil. But it was possible to omit a value as shown above to clarify that no property value would be included. IT would be possible to specify additional values in oslc.properties that would be sent in the request body. One example is the resolution – see below how that looks like.

Please note, that it is necessary to satisfy all required attributes when performing a workflow action. The new state might require additional values that you might have to provide, in which case you want to definitely use the full information from the resource.

Please also note that I am not seeing errors if the workflow action can not be done or does not exist. The response is 200, regardless of this fact.

Resolve Work Item With Resolution

One example for attributes that might become required with respect to a state change is the resolution attribute


that might be required in certain states when resolving/closing the work item. Following the pattern we discovered the resolutions can be found using the workflow URI and replacing the section states by resolutions. The resulting URI provides the available resolutions.

Please note, that I experienced issues with the headers to be used here, dependent on the headers used different information was returned in cases such as the actions above. I would suggest to test using the OSLC headers. If there is a lack of information try to only use the header Accept application/xml (or application/json). The result could contain more information. Please note that in the latter case the format is not RDF.

Since I had built all the logic to get the action information using XML (minidom) and not RDF in python, I used only Accept application/xml as header to get the resolution information and reused the code written to analyze the actions.

GET https://elm.example.com:9443/ccm/oslc/workflows/_8e5qfFpmEeukW7cqqDjAuA/resolutions/com.ibm.team.workitem.defectWorkflow

Accept application/xml

With the call above it is possible to GET all resolution information like ID’s and names. The image below shows an example. Mind the request header used.

Get the resolution information.

It is then possible to add or set the attribute value like below.

<rtc_cm:resolution rdf:resource="https://elm.example.com:9443/ccm/oslc/workflows/_8e5qfFpmEeukW7cqqDjAuA/resolutions/com.ibm.team.workitem.defectWorkflow/com.ibm.team.workitem.defectWorkflow.resolution.r4"/>

See the response from a GET response to an work item URI, containing the value below as the example.

Setting the resolution results in this additional attribute.

The example below shows all that is needed to close the work item and set the resolution updated in the same request. In addition to the workflow action as above use the the oslc.properties and define an additional property, the resolution attribute, to be provided.

PUT https://elm.example.com:9443/ccm/resource/itemName/com.ibm.team.workitem.WorkItem/241?_action=https://elm.example.com:9443/ccm/oslc/workflows/_8e5qfFpmEeukW7cqqDjAuA/actions/com.ibm.team.workitem.defectWorkflow/com.ibm.team.workitem.defectWorkflow.action.resolve&oslc.properties=rtc_cm%3Aresolution

The request URL contains the workflow action and the request body contains the data for the additional attribute to be set as follows:

<?xml version="1.0" encoding="UTF-8"?>
   xmlns:rtc_cm="http://jazz.net/xmlns/prod/jazz/rtc/cm/1.0/" >
	<rdf:Description rdf:about="https://elm.example.com:9443/ccm/resource/itemName/com.ibm.team.workitem.WorkItem/241">
	<rtc_cm:resolution rdf:resource="https://elm.example.com:9443/ccm/oslc/workflows/_8e5qfFpmEeukW7cqqDjAuA/resolutions/com.ibm.team.workitem.defectWorkflow/com.ibm.team.workitem.defectWorkflow.resolution.r3"/>

The request headers, including the If-Match header, have been shown already and show up in the image below which shows all the important data in RESTClient:

Resolving the work item with setting the resolution attribute.

This is a complete example of a state change while changing the resolution attribute in addition. This can be expanded on to set more properties using oslc.properties.

I found numerous questions around this in the Jazz forum, but there was still some considerable amount of work to be done, to get the state change working.

The page Resource Oriented Work Item API V2 also describes other interesting concepts like query mechanisms and representations. Some of them will be presented in subsequent upcoming posts. Something I have not yet explored are the draft work items. Intriguing. Maybe I find time to look at it.


I am fully aware that I am quite late to the party, but despite trying, I was unable to find examples for the whole process that were consistent and simple enough, covered most of the ground or worked for me. There was quite some research that needed to be done to get all the concepts covered. All the information in the blog series I am currently writing has been collected to help customers as well as IBM internal resources with the ELM APIs.

So, as always I hope that the content of this blog (series) is of interest to users out there and helps to save some time achieving their goals.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.