ok so i got order09-05-12-1346847709.xml file in my webserver's order folder through webhook from shopify webhook test and the file looks like
....................................................
<processing-method nil="true"></processing-method>
<line-items type="array">
<line-item>
<requires-shipping type="boolean">true</requires-shipping>
<fulfillment-service>manual</fulfillment-service>
<grams type="integer">5000</grams>
<price type="decimal">199.99</price>
<quantity type="integer">1</quantity>
<sku>SKU2006-001</sku>
<title>Sledgehammer</title>
<product-id type="integer" nil="true"></product-id>
<variant-id type="integer" nil="true"></variant-id>
<vendor nil="true"></vendor>
<variant-title nil="true"></variant-title>
<fulfillment-status nil="true"></fulfillment-status>
<name>Sledgehammer</name>
<variant-inventory-management nil="true"></variant-inventory-management>
<properties type="array">
</properties>
</line-item>
<line-item>
<requires-shipping type="boolean">true</requires-shipping>
<fulfillment-service>manual</fulfillment-service>
<grams type="integer">500</grams>
<price type="decimal">29.95</price>
<quantity type="integer">1</quantity>
<sku>SKU2006-020</sku>
<title>Wire Cutter</title>
<product-id type="integer" nil="true"></product-id>
<variant-id type="integer" nil="true"></variant-id>
<vendor nil="true"></vendor>
<variant-title nil="true"></variant-title>
<fulfillment-status nil="true"></fulfillment-status>
<name>Wire Cutter</name>
<variant-inventory-management nil="true"></variant-inventory-management>
<properties type="array">
</properties>
</line-item>
</line-items>
........................................................................
and all i need is pick "sku and qty" value so i can update to my ms sql server's data automatically how do i do that using php i mean i know how to connect to sql server using sqlsrv and but don't know php code to pick specific field's value and put values to sql server
plz guys i am desperate now ....
Thank you so much guys in advance
Here is some PHP code which fetches the sku and quantity value for each item in your XML document (it's not the best/nicest/most powerful way to search for particular piece of information in an XML document, but it works). Since you don't tell us how you want to insert them in your database, I cannot do much more.
Here is the documentation about the PHP Document Object Model interface, which allows manipulation of XML documents. Please have a look at it.
$dom = new DomDocument();
$dom->load('order09-05-12-1346847709.xml');
$itemList = $dom->getElementsByTagName('line-item');
foreach($itemList as $item) {
$sku='';
$qty='';
foreach($item->childNodes as $child) {
if ($child->localName == 'sku') {
$sku = $child->textContent;
}
if ($child->localName == 'quantity') {
$qty = $child->textContent;
}
}
echo 'Item SKU: ' . $sku . '<br />';
echo 'Item quantity: ' . $qty . '<br />';
// cast to integer: intval($qty)
echo '<br />';
}
Related
I need to get the value of every "custom_field" named "ZIP" out of the following XML-file using PHP.
When I parse it, I always get either the values of all projects or an empty array?
Can somebody help?
<?xml version="1.0" encoding="UTF-8"?>
<projects total_count="237" offset="0" limit="100" type="array">
<project>
<id>239</id>
<name>ABC</name>
<identifier></identifier>
<description></description>
<status>1</status>
<is_public>false</is_public>
<custom_fields type="array">
<custom_field id="18" name="Name affix">
<value></value>
</custom_field>
<custom_field id="20" name="ZIP">
<value>X1111</value>
</custom_field>
</custom_fields>
<created_on>2017-06-05T16:33:13Z</created_on>
<updated_on>2017-06-19T13:46:08Z</updated_on>
</project>
<project>
<id>240</id>
<name>DEF</name>
<identifier></identifier>
<description></description>
<status>1</status>
<is_public>false</is_public>
<custom_fields type="array">
<custom_field id="18" name="Name affix">
<value></value>
</custom_field>
<custom_field id="20" name="ZIP">
<value>Y2222</value>
</custom_field>
</custom_fields>
<created_on>2017-06-05T16:33:14Z</created_on>
<updated_on>2017-06-05T16:33:14Z</updated_on>
</project>
...
I tried the following and get empty arrays:
$projects = simplexml_load_file($rm_host."/projects.xml?key=".$rm_sa_key."&limit=100");
foreach($projects->project as $project){
$zip = $project->xpath('//custom_field[#name="ZIP"]');
print_r($zip);
echo "<br/>";
}
When I try to replace the string with the following, it returns the value of all items, not of the specific one:
zip = $project->xpath('//custom_fields[#type="array"]/custom_field[#name="ZIP"]')
Finally worked after trying and trying.
The correct string to get the specific value was:
$zip = $project->custom_fields->xpath('custom_field[#name="ZIP"]/value')[0];
Without the slash in front of the xpath.
I need to get the value of the custom_field "NewTitle" (ID 6) which is nested inside the child "custom_fields" of the following XML:
<issues total_count="63" offset="0" limit="100" type="array">
<issue>
<id>65</id>
<project id="7" name="ProjectName"/>
<tracker id="7" name="TrackerName"/>
<subject>MySubject</subject>
...
<custom_fields type="array">
<custom_field id="4" name="OrderType">
<value>Project</value>
</custom_field>
<custom_field id="26" name="ExtID">
<value>246558</value>
</custom_field>
<custom_field id="25" name="Area" multiple="true">
<value type="array">
<value>Process</value>
<value>System</value>
</value>
</custom_field>
<custom_field id="6" name="NewTitle">
<value>ABCDEF</value>
</custom_field>
...
<custom_field id="20" name="KST">
<value/>
</custom_field>
<custom_field id="11" name="LKF">
<value>3</value>
</custom_field>
<custom_field id="17" name="Link">
<value>XXX</value>
</custom_field>
</custom_fields>
<created_on>2015-12-14T08:00:03Z</created_on>
<updated_on>2016-01-28T09:07:20Z</updated_on>
<closed_on/>
</issue>
</issues>
Can somebody tell me how to do that with PHP? I only managed to display values of the main fields. For example the subject:
foreach ($xml->issue as $issue){
if((string) $issue->tracker['id'] == 7){
echo $issue->subject.'<br/>';
}
}
Use SimpleXML combined with an xpath:
$xml = simplexml_load_string($your_xml_here);
$fields = $xml->xpath("//custom_field[#name='NewTitle']");
foreach ($fields as $field) {
// do sth. useful here
}
You are not very specific about the key(s) to select the <value> you want.
I assume by your example that you want to select...
the <value> of a parent <custom_field>
having the attributes name = "NewTitle" and id = "6"
having an <issue> ancestor with a child <tracker> with an attribute id = "7"
xpath is a fine solution to get to that value directly without iteration. It is like SQL for XML.
select the right <issue>:
/issues/issue[tracker/#id='7']
Note how / is separating parent from child, conditions are within [], attributes have #.
within that issue, select a <custom_field>with the given attributes:
(...)/custom_fields/custom_field[#name='NewTitle'][#id='6']
then get the <value> children (can be more than just 1):
(...)/value
Combined:
$xml = simplexml_load_string($x);
$values = $xml->xpath("/issues/issue[tracker/#id='7']/custom_fields/custom_field[#name='NewTitle'][#id='6']/value");
$values is an array containing single <value> nodes, or an empty array:
foreach ($values as $val)
echo $val->asXML();
Output:
<value>ABCDEF</value>
see it in action: https://eval.in/509835
I don't have a texteditor on hand atm nor am I able to try it out myself but this should do the trick and give you an idea how to itterate through xml nestings.
foreach ($xml->issue as $issue){
foreach ($issue['custom_field'] as $custField){
echo $custField['value'];
}
}
I use the folowing PHP to extract the coordinates from a kml file:
$xml = simplexml_load_file('data.kml');
$data = $xml->Document->Folder->Placemark;
foreach ($data as $record) {
$coordinates = $record->MultiGeometry->Polygon->outerBoundaryIs->LinearRing->coordinates[0];
}
This works fine for the coordinates. But how can I Extact the ExtendedData?
The kml file I am using:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>pc4_single_vlak</name>
<visibility>1</visibility>
<Schema name="pc4_single_vlak" id="kml_schema_ft_pc4_single_vlak">
<SimpleField type="xsd:string" name="pc4">
<displayName>pc4</displayName>
</SimpleField>
<SimpleField type="xsd:string" name="woonplaats">
<displayName>woonplaats</displayName>
</SimpleField>
<SimpleField type="xsd:string" name="wplnaam_uniek">
<displayName>wplnaam_uniek</displayName>
</SimpleField>
<SimpleField type="xsd:string" name="gemeente">
<displayName>gemeente</displayName>
</SimpleField>
<SimpleField type="xsd:string" name="provincie">
<displayName>provincie</displayName>
</SimpleField>
</Schema>
<Folder id="kml_ft_pc4_single_vlak">
<name>pc4_single_vlak</name>
<Placemark id="kml_1">
<name>kml_1</name>
<snippet></snippet>
<ExtendedData>
<SchemaData schemaUrl="#kml_schema_ft_pc4_single_vlak">
<SimpleData name="pc4">4001</SimpleData>
<SimpleData name="woonplaats">Tiel</SimpleData>
<SimpleData name="wplnaam_uniek">Tiel</SimpleData>
<SimpleData name="gemeente">Tiel</SimpleData>
<SimpleData name="provincie">Gelderland</SimpleData>
</SchemaData>
</ExtendedData>
<MultiGeometry>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>...</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</MultiGeometry>
</Placemark>
</Folder>
</Document>
</kml>
I tried all kinds of things, but I cant get it to work.
I'm not sure where the hiccup is, but hopefully this provides some clarity.
Let's get the ExtendedData parent:
echo $record->ExtendedData;
No attributes though, only children, let's get the schemaUrl from the first SchemaData child:
echo $record->ExtendedData->SchemaData[0]['schemaUrl'];
When getting attrributes, you access them as an index of the element.
Here's a working example
I found the solution to my own question :). I gues this isnt the best way to do it. But I used the folowing code to get to the different SimpleData fields:
echo $record->ExtendedData->SchemaData->SimpleData[0];
echo $record->ExtendedData->SchemaData->SimpleData[1];
echo $record->ExtendedData->SchemaData->SimpleData[2];
enz..
Again. I am sure there is a better solution to this. If someone knows, please comment!
I am using shopify webhook to update my sql server's 'qty' field when order updated,
below is my php code
?php
$xmlData = fopen('php://input' , 'rb');
while (!feof($xmlData)) { $xmlString .= fread($xmlData, 4096); }
fclose($xmlData);
$xml = new SimplexmlElement($xmlString);
file_put_contents('orders/order' . '.xml', $xmlString);
$dom = new DomDocument();
$dom->load('orders/order.xml');
$itemList = $dom->getElementsByTagName('line-item');
foreach($itemList as $item) {
$sku='';
$qty='';
foreach($item->childNodes as $child) {
if ($child->localName == 'sku') {
$sku = $child->textContent;
}
if ($child->localName == 'quantity') {
$qty = $child->textContent;
}
}
mysql_connect ("?????????????????????????");
mysql_select_db("??????????");
$query = "UPDATE xcart_categories SET product_count = product_count - $qty WHERE description='$sku';";
mysql_query($query);
}
and below is xml file i am getting from shopify webhook
<?xml version="1.0" encoding="UTF-8"?>
<order>
<buyer-accepts-marketing type="boolean">true</buyer-accepts-marketing>
<closed-at type="datetime" nil="true"></closed-at>
<currency>USD</currency>
<email>yeongju_l#yahoo.com</email>
<financial-status>pending</financial-status>
<fulfillment-status>fulfilled</fulfillment-status>
<gateway>Local Pick-Up</gateway>
<id type="integer">140303247</id>
<name>#1012</name>
<note></note>
<number type="integer">12</number>
<subtotal-price type="decimal">0.2</subtotal-price>
<taxes-included type="boolean">false</taxes-included>
<total-discounts type="decimal">0.0</total-discounts>
<total-line-items-price type="decimal">0.2</total-line-items-price>
<total-price type="decimal">0.2</total-price>
<total-price-usd type="decimal">0.2</total-price-usd>
<total-tax type="decimal">0.0</total-tax>
<total-weight type="integer">0</total-weight>
<updated-at type="datetime">2012-09-16T21:20:07-04:00</updated-at>
<created-at type="datetime">2012-09-16T21:08:30-04:00</created-at>
<token>dcf523d93c68159c15a7c8d1fabbee07</token>
<landing-site>/products/test</landing-site>
<referring-site></referring-site>
<cancelled-at type="datetime" nil="true"></cancelled-at>
<cancel-reason nil="true"></cancel-reason>
<cart-token>a9a7bc5d8103f6a3bb45e827f0cb8928</cart-token>
<browser-ip nil="true"></browser-ip>
<landing-site-ref nil="true"></landing-site-ref>
<order-number type="integer">1012</order-number>
<discount-codes type="array"/>
<note-attributes type="array">
</note-attributes>
<processing-method>manual</processing-method>
<line-items type="array">
<line-item>
<id type="integer">228531213</id>
<requires-shipping type="boolean">false</requires-shipping>
<fulfillment-service>manual</fulfillment-service>
<grams type="integer">0</grams>
<price type="decimal">0.2</price>
<quantity type="integer">1</quantity>
<sku>1234567</sku>
<title>test</title>
<product-id type="integer">104663831</product-id>
<variant-id type="integer">240660979</variant-id>
<vendor>5 Second</vendor>
<variant-title nil="true"></variant-title>
<fulfillment-status>fulfilled</fulfillment-status>
<name>test</name>
<variant-inventory-management></variant-inventory-management>
<properties type="array">
</properties>
</line-item>
</line-items>
<shipping-lines type="array"/>
<tax-lines type="array">
<tax-line>
<title>NY State Tax</title>
<price type="decimal">0.0</price>
<rate type="float">0.04</rate>
</tax-line>
<tax-line>
<title>Queens County Tax</title>
<price type="decimal">0.0</price>
<rate type="float">0.04875</rate>
</tax-line>
</tax-lines>
<billing-address>
<first-name>Yeongju</first-name>
<last-name>Lee</last-name>
<address1>14809 northern blvd</address1>
<address2></address2>
<city>Flushing</city>
<company></company>
<country>United States</country>
<phone></phone>
<province>New York</province>
<zip>11354</zip>
<latitude type="decimal">40.76529</latitude>
<longitude type="decimal">-73.81831</longitude>
<name>Yeongju Lee</name>
<country-code>US</country-code>
<province-code>NY</province-code>
</billing-address>
<fulfillments type="array">
<fulfillment>
<id type="integer">67712419</id>
<order-id type="integer">140303247</order-id>
<created-at type="datetime">2012-09-16T21:20:07-04:00</created-at>
<updated-at type="datetime">2012-09-16T21:20:07-04:00</updated-at>
<tracking-number nil="true"></tracking-number>
<tracking-company nil="true"></tracking-company>
<status>success</status>
<service>manual</service>
<tracking-url>http://www.google.com/search?q=</tracking-url>
<receipt>
</receipt>
<line-items type="array">
<line-item>
<id type="integer">228531213</id>
<requires-shipping type="boolean">false</requires-shipping>
<fulfillment-service>manual</fulfillment-service>
<grams type="integer">0</grams>
<price type="decimal">0.2</price>
<quantity type="integer">1</quantity>
<sku>1234567</sku>
<title>test</title>
<product-id type="integer">104663831</product-id>
<variant-id type="integer">240660979</variant-id>
<vendor>5 Second</vendor>
<variant-title nil="true"></variant-title>
<fulfillment-status>fulfilled</fulfillment-status>
<name>test</name>
<variant-inventory-management></variant-inventory-management>
<properties type="array">
</properties>
</line-item>
</line-items>
</fulfillment>
</fulfillments>
<customer>
<id type="integer">96489088</id>
<email>yeongju_l#yahoo.com</email>
<accepts-marketing type="boolean">true</accepts-marketing>
<first-name>Yeongju</first-name>
<last-name>Lee</last-name>
<orders-count type="integer">12</orders-count>
<total-spent type="decimal">16.26</total-spent>
<note nil="true"></note>
<created-at type="datetime">2012-08-17T11:31:50-04:00</created-at>
<updated-at type="datetime">2012-09-16T21:20:07-04:00</updated-at>
<state>enabled</state>
<last-order-id type="integer">140303509</last-order-id>
<tags>C</tags>
<last-order-name>#1013</last-order-name>
</customer>
</order>
like you see i got two sku and qty because of duplicated line-item so for example when customer order one "product name - test in this case i got "-2" quantity update in my sql server sku test field , but when i am using webhook event when order creation it worked i mean i see only one line item but all the other cases(when order updated, when order payment, when order fullfillment..) show me duplicated line item even there is only one item ordered
anyone who got idea to fix this thing?
Thank you so much in advance guys......
You're parsing your XML badly. You'll notice that one of the line-items tags is in the root of the response, while the other is nested under the fulfillments node. The former is a full listing of the line items for the order, and the latter is a record of the individual fulfillments made against the order (there might be several).
I'd find an XML parser and put it to work on the data so that you can access it in a structured fashion and only pull line items from the first line-items node.
I am using shopify webhook to update my sql server's 'qty' field when order updated, below is my php code
?php
$xmlData = fopen('php://input' , 'rb');
while (!feof($xmlData)) { $xmlString .= fread($xmlData, 4096); }
fclose($xmlData);
$xml = new SimplexmlElement($xmlString);
file_put_contents('orders/order' . '.xml', $xmlString);
$dom = new DomDocument();
$dom->load('orders/order.xml');
$itemList = $dom->getElementsByTagName('line-item');
foreach($itemList as $item) {
$sku='';
$qty='';
foreach($item->childNodes as $child) {
if ($child->localName == 'sku') {
$sku = $child->textContent;
}
if ($child->localName == 'quantity') {
$qty = $child->textContent;
}
}
mysql_connect ("?????????????????????????");
mysql_select_db("??????????");
$query = "UPDATE xcart_categories SET product_count = product_count - $qty WHERE description='$sku';";
mysql_query($query);
}
and below is xml file i am getting from shopify webhook
<?xml version="1.0" encoding="UTF-8"?>
<order>
<buyer-accepts-marketing type="boolean">true</buyer-accepts-marketing>
<closed-at type="datetime" nil="true"></closed-at>
<currency>USD</currency>
<email>yeongju_l#yahoo.com</email>
<financial-status>pending</financial-status>
<fulfillment-status>fulfilled</fulfillment-status>
<gateway>Local Pick-Up</gateway>
<id type="integer">140303247</id>
<name>#1012</name>
<note></note>
<number type="integer">12</number>
<subtotal-price type="decimal">0.2</subtotal-price>
<taxes-included type="boolean">false</taxes-included>
<total-discounts type="decimal">0.0</total-discounts>
<total-line-items-price type="decimal">0.2</total-line-items-price>
<total-price type="decimal">0.2</total-price>
<total-price-usd type="decimal">0.2</total-price-usd>
<total-tax type="decimal">0.0</total-tax>
<total-weight type="integer">0</total-weight>
<updated-at type="datetime">2012-09-16T21:20:07-04:00</updated-at>
<created-at type="datetime">2012-09-16T21:08:30-04:00</created-at>
<token>dcf523d93c68159c15a7c8d1fabbee07</token>
<landing-site>/products/test</landing-site>
<referring-site></referring-site>
<cancelled-at type="datetime" nil="true"></cancelled-at>
<cancel-reason nil="true"></cancel-reason>
<cart-token>a9a7bc5d8103f6a3bb45e827f0cb8928</cart-token>
<browser-ip nil="true"></browser-ip>
<landing-site-ref nil="true"></landing-site-ref>
<order-number type="integer">1012</order-number>
<discount-codes type="array"/>
<note-attributes type="array">
</note-attributes>
<processing-method>manual</processing-method>
<line-items type="array">
<line-item>
<id type="integer">228531213</id>
<requires-shipping type="boolean">false</requires-shipping>
<fulfillment-service>manual</fulfillment-service>
<grams type="integer">0</grams>
<price type="decimal">0.2</price>
<quantity type="integer">1</quantity>
<sku>1234567</sku>
<title>test</title>
<product-id type="integer">104663831</product-id>
<variant-id type="integer">240660979</variant-id>
<vendor>5 Second</vendor>
<variant-title nil="true"></variant-title>
<fulfillment-status>fulfilled</fulfillment-status>
<name>test</name>
<variant-inventory-management></variant-inventory-management>
<properties type="array">
</properties>
</line-item>
</line-items>
<shipping-lines type="array"/>
<tax-lines type="array">
<tax-line>
<title>NY State Tax</title>
<price type="decimal">0.0</price>
<rate type="float">0.04</rate>
</tax-line>
<tax-line>
<title>Queens County Tax</title>
<price type="decimal">0.0</price>
<rate type="float">0.04875</rate>
</tax-line>
</tax-lines>
<billing-address>
<first-name>Yeongju</first-name>
<last-name>Lee</last-name>
<address1>14809 northern blvd</address1>
<address2></address2>
<city>Flushing</city>
<company></company>
<country>United States</country>
<phone></phone>
<province>New York</province>
<zip>11354</zip>
<latitude type="decimal">40.76529</latitude>
<longitude type="decimal">-73.81831</longitude>
<name>Yeongju Lee</name>
<country-code>US</country-code>
<province-code>NY</province-code>
</billing-address>
<fulfillments type="array">
<fulfillment>
<id type="integer">67712419</id>
<order-id type="integer">140303247</order-id>
<created-at type="datetime">2012-09-16T21:20:07-04:00</created-at>
<updated-at type="datetime">2012-09-16T21:20:07-04:00</updated-at>
<tracking-number nil="true"></tracking-number>
<tracking-company nil="true"></tracking-company>
<status>success</status>
<service>manual</service>
<tracking-url>http://www.google.com/search?q=</tracking-url>
<receipt>
</receipt>
<line-items type="array">
<line-item>
<id type="integer">228531213</id>
<requires-shipping type="boolean">false</requires-shipping>
<fulfillment-service>manual</fulfillment-service>
<grams type="integer">0</grams>
<price type="decimal">0.2</price>
<quantity type="integer">1</quantity>
<sku>1234567</sku>
<title>test</title>
<product-id type="integer">104663831</product-id>
<variant-id type="integer">240660979</variant-id>
<vendor>5 Second</vendor>
<variant-title nil="true"></variant-title>
<fulfillment-status>fulfilled</fulfillment-status>
<name>test</name>
<variant-inventory-management></variant-inventory-management>
<properties type="array">
</properties>
</line-item>
</line-items>
</fulfillment>
</fulfillments>
<customer>
<id type="integer">96489088</id>
<email>yeongju_l#yahoo.com</email>
<accepts-marketing type="boolean">true</accepts-marketing>
<first-name>Yeongju</first-name>
<last-name>Lee</last-name>
<orders-count type="integer">12</orders-count>
<total-spent type="decimal">16.26</total-spent>
<note nil="true"></note>
<created-at type="datetime">2012-08-17T11:31:50-04:00</created-at>
<updated-at type="datetime">2012-09-16T21:20:07-04:00</updated-at>
<state>enabled</state>
<last-order-id type="integer">140303509</last-order-id>
<tags>C</tags>
<last-order-name>#1013</last-order-name>
</customer>
like you see i got two sku and qty because of duplicated line-item so for example when customer order one "product name - test in this case i got "-2" quantity update in my sql server sku test field , but when i am using webhook event when order creation it worked i mean i see only one line item but all the other cases(when order updated, when order payment, when order fullfillment..) show me duplicated line item even there is only one item ordered
i think i am parsing my XML badly
anyone who can teach me correct code to pull 'line items' from the first line-items node i will really appreciate it! Thanks..again
You're doing a lot of redundant steps to parse your XML there. You don't need to save the data into a file before processing it, and you have a stray call to SimpleXML that you're not using. All you need is this:
$xmlString = file_get_contents('php://input');
$dom = new DomDocument();
$dom->loadXML($xmlString);
After that, your parsing logic looks fine but you are only ever running one SQL query, with one SKU in it.
Inside your foreach loop, you define the variables $sku and $qty, but you don't do anything with them inside the loop. So next time round the loop, you will over-write their values, and nothing will ever know about the old values.
There are few ways to do this:
run SQL inside the loop (not very efficient)
build up an array of SKUs and quantities ($sku[] = ...; $qty[] = ...;) and then build your SQL from these arrays
slightly tidier, build a single array with the SKU-quantity pairs as nested arrays ($sku_list[] = array('sku' => ..., 'qty' => ...))
build your SQL string progressively inside the loop ($sql .= '...') and execute it once at the end