OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv ed. | 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv ed. |
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) | 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) |
4 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t orchmobile.com/) | 4 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t orchmobile.com/) |
5 * Copyright (C) 2008 Alp Toker <alp@atoker.com> | 5 * Copyright (C) 2008 Alp Toker <alp@atoker.com> |
6 * Copyright (C) Research In Motion Limited 2009. All rights reserved. | 6 * Copyright (C) Research In Motion Limited 2009. All rights reserved. |
7 * Copyright (C) 2011 Kris Jordan <krisjordan@gmail.com> | 7 * Copyright (C) 2011 Kris Jordan <krisjordan@gmail.com> |
8 * Copyright (C) 2011 Google Inc. All rights reserved. | 8 * Copyright (C) 2011 Google Inc. All rights reserved. |
9 * | 9 * |
10 * Redistribution and use in source and binary forms, with or without | 10 * Redistribution and use in source and binary forms, with or without |
(...skipping 484 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
495 return true; | 495 return true; |
496 } | 496 } |
497 | 497 |
498 void FrameLoader::didExplicitOpen() | 498 void FrameLoader::didExplicitOpen() |
499 { | 499 { |
500 m_isComplete = false; | 500 m_isComplete = false; |
501 m_didCallImplicitClose = false; | 501 m_didCallImplicitClose = false; |
502 | 502 |
503 // Calling document.open counts as committing the first real document load. | 503 // Calling document.open counts as committing the first real document load. |
504 if (!m_stateMachine.committedFirstRealDocumentLoad()) | 504 if (!m_stateMachine.committedFirstRealDocumentLoad()) |
505 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmpty DocumentPostCommit); | 505 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad ); |
506 | 506 |
507 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results | 507 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results |
508 // from a subsequent window.document.open / window.document.write call. | 508 // from a subsequent window.document.open / window.document.write call. |
509 // Canceling redirection here works for all cases because document.open | 509 // Canceling redirection here works for all cases because document.open |
510 // implicitly precedes document.write. | 510 // implicitly precedes document.write. |
511 m_frame->navigationScheduler()->cancel(); | 511 m_frame->navigationScheduler()->cancel(); |
512 } | 512 } |
513 | 513 |
514 | 514 |
515 void FrameLoader::cancelAndClear() | 515 void FrameLoader::cancelAndClear() |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
558 if (clearScriptObjects) | 558 if (clearScriptObjects) |
559 m_frame->script()->clearScriptObjects(); | 559 m_frame->script()->clearScriptObjects(); |
560 | 560 |
561 m_frame->script()->enableEval(); | 561 m_frame->script()->enableEval(); |
562 | 562 |
563 m_frame->navigationScheduler()->clear(); | 563 m_frame->navigationScheduler()->clear(); |
564 | 564 |
565 m_checkTimer.stop(); | 565 m_checkTimer.stop(); |
566 m_shouldCallCheckCompleted = false; | 566 m_shouldCallCheckCompleted = false; |
567 m_shouldCallCheckLoadComplete = false; | 567 m_shouldCallCheckLoadComplete = false; |
568 | |
569 if (m_stateMachine.isDisplayingInitialEmptyDocument() && m_stateMachine.comm ittedFirstRealDocumentLoad()) | |
570 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad ); | |
571 } | 568 } |
572 | 569 |
573 void FrameLoader::receivedFirstData() | 570 void FrameLoader::receivedFirstData() |
574 { | 571 { |
575 dispatchDidCommitLoad(); | 572 dispatchDidCommitLoad(); |
576 dispatchDidClearWindowObjectsInAllWorlds(); | 573 dispatchDidClearWindowObjectsInAllWorlds(); |
577 | 574 |
578 if (m_documentLoader) { | 575 if (m_documentLoader) { |
579 StringWithDirection ptitle = m_documentLoader->title(); | 576 StringWithDirection ptitle = m_documentLoader->title(); |
580 // If we have a title let the WebView know about it. | 577 // If we have a title let the WebView know about it. |
(...skipping 23 matching lines...) Expand all Loading... | |
604 m_outgoingReferrer = url.strippedForUseAsReferrer(); | 601 m_outgoingReferrer = url.strippedForUseAsReferrer(); |
605 } | 602 } |
606 | 603 |
607 void FrameLoader::didBeginDocument(bool dispatch) | 604 void FrameLoader::didBeginDocument(bool dispatch) |
608 { | 605 { |
609 m_needsClear = true; | 606 m_needsClear = true; |
610 m_isComplete = false; | 607 m_isComplete = false; |
611 m_didCallImplicitClose = false; | 608 m_didCallImplicitClose = false; |
612 m_frame->document()->setReadyState(Document::Loading); | 609 m_frame->document()->setReadyState(Document::Loading); |
613 | 610 |
614 if (m_pendingStateObject) { | 611 if (history()->currentItem()) |
615 m_frame->document()->statePopped(m_pendingStateObject.get()); | 612 m_frame->document()->statePopped(history()->currentItem()->stateObject() ); |
616 m_pendingStateObject.clear(); | |
617 } | |
618 | 613 |
619 if (dispatch) | 614 if (dispatch) |
620 dispatchDidClearWindowObjectsInAllWorlds(); | 615 dispatchDidClearWindowObjectsInAllWorlds(); |
621 | 616 |
622 updateFirstPartyForCookies(); | 617 updateFirstPartyForCookies(); |
623 m_frame->document()->initContentSecurityPolicy(); | 618 m_frame->document()->initContentSecurityPolicy(); |
624 | 619 |
625 Settings* settings = m_frame->document()->settings(); | 620 Settings* settings = m_frame->document()->settings(); |
626 if (settings) { | 621 if (settings) { |
627 m_frame->document()->cachedResourceLoader()->setImagesEnabled(settings-> areImagesEnabled()); | 622 m_frame->document()->cachedResourceLoader()->setImagesEnabled(settings-> areImagesEnabled()); |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
912 void FrameLoader::handleFallbackContent() | 907 void FrameLoader::handleFallbackContent() |
913 { | 908 { |
914 HTMLFrameOwnerElement* owner = m_frame->ownerElement(); | 909 HTMLFrameOwnerElement* owner = m_frame->ownerElement(); |
915 if (!owner || !owner->hasTagName(objectTag)) | 910 if (!owner || !owner->hasTagName(objectTag)) |
916 return; | 911 return; |
917 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent(); | 912 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent(); |
918 } | 913 } |
919 | 914 |
920 void FrameLoader::provisionalLoadStarted() | 915 void FrameLoader::provisionalLoadStarted() |
921 { | 916 { |
922 if (m_stateMachine.firstLayoutDone()) | |
923 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad ); | |
924 m_frame->navigationScheduler()->cancel(true); | 917 m_frame->navigationScheduler()->cancel(true); |
925 } | 918 } |
926 | 919 |
927 void FrameLoader::resetMultipleFormSubmissionProtection() | 920 void FrameLoader::resetMultipleFormSubmissionProtection() |
928 { | 921 { |
929 m_submittedFormURL = KURL(); | 922 m_submittedFormURL = KURL(); |
930 } | 923 } |
931 | 924 |
932 void FrameLoader::updateFirstPartyForCookies() | 925 void FrameLoader::updateFirstPartyForCookies() |
933 { | 926 { |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1040 // history navigation we need to manufacture one, and update | 1033 // history navigation we need to manufacture one, and update |
1041 // the state machine of this frame to impersonate having | 1034 // the state machine of this frame to impersonate having |
1042 // loaded it. | 1035 // loaded it. |
1043 RefPtr<HistoryItem> currentItem = history()->currentItem(); | 1036 RefPtr<HistoryItem> currentItem = history()->currentItem(); |
1044 if (!currentItem) { | 1037 if (!currentItem) { |
1045 currentItem = HistoryItem::create(); | 1038 currentItem = HistoryItem::create(); |
1046 history()->setCurrentItem(currentItem.get()); | 1039 history()->setCurrentItem(currentItem.get()); |
1047 frame()->page()->backForward()->setCurrentItem(currentItem.get()); | 1040 frame()->page()->backForward()->setCurrentItem(currentItem.get()); |
1048 | 1041 |
1049 ASSERT(stateMachine()->isDisplayingInitialEmptyDocument()); | 1042 ASSERT(stateMachine()->isDisplayingInitialEmptyDocument()); |
1050 stateMachine()->advanceTo(FrameLoaderStateMachine::DisplayingInitialEmpt yDocumentPostCommit); | |
1051 stateMachine()->advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoa d); | 1043 stateMachine()->advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoa d); |
1052 } | 1044 } |
1053 } | 1045 } |
1054 | 1046 |
1055 void FrameLoader::prepareForLoadStart() | 1047 void FrameLoader::prepareForLoadStart() |
1056 { | 1048 { |
1057 m_progressTracker->progressStarted(); | 1049 m_progressTracker->progressStarted(); |
1058 m_client->dispatchDidStartProvisionalLoad(); | 1050 m_client->dispatchDidStartProvisionalLoad(); |
1059 | 1051 |
1060 // Notify accessibility. | 1052 // Notify accessibility. |
(...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1617 ASSERT(m_state == FrameStateProvisional); | 1609 ASSERT(m_state == FrameStateProvisional); |
1618 | 1610 |
1619 if (m_state != FrameStateProvisional) | 1611 if (m_state != FrameStateProvisional) |
1620 return; | 1612 return; |
1621 | 1613 |
1622 if (FrameView* view = m_frame->view()) { | 1614 if (FrameView* view = m_frame->view()) { |
1623 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator()) | 1615 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator()) |
1624 scrollAnimator->cancelAnimations(); | 1616 scrollAnimator->cancelAnimations(); |
1625 } | 1617 } |
1626 | 1618 |
1627 history()->updateForCommit(); | |
1628 | |
1629 // The call to closeURL() invokes the unload event handler, which can execut e arbitrary | 1619 // The call to closeURL() invokes the unload event handler, which can execut e arbitrary |
1630 // JavaScript. If the script initiates a new load, we need to abandon the cu rrent load, | 1620 // JavaScript. If the script initiates a new load, we need to abandon the cu rrent load, |
1631 // or the two will stomp each other. | 1621 // or the two will stomp each other. |
1632 DocumentLoader* pdl = m_provisionalDocumentLoader.get(); | 1622 DocumentLoader* pdl = m_provisionalDocumentLoader.get(); |
1633 if (m_documentLoader) | 1623 if (m_documentLoader) |
1634 closeURL(); | 1624 closeURL(); |
1635 if (pdl != m_provisionalDocumentLoader) | 1625 if (pdl != m_provisionalDocumentLoader) |
1636 return; | 1626 return; |
1637 | 1627 |
1638 // Nothing else can interupt this commit - set the Provisional->Committed tr ansition in stone | 1628 // Nothing else can interupt this commit - set the Provisional->Committed tr ansition in stone |
1639 if (m_documentLoader) | 1629 if (m_documentLoader) |
1640 m_documentLoader->stopLoadingSubresources(); | 1630 m_documentLoader->stopLoadingSubresources(); |
1641 | 1631 |
1642 setDocumentLoader(m_provisionalDocumentLoader.get()); | 1632 setDocumentLoader(m_provisionalDocumentLoader.get()); |
1643 setProvisionalDocumentLoader(0); | 1633 setProvisionalDocumentLoader(0); |
1644 | 1634 |
1645 if (pdl != m_documentLoader) { | 1635 if (pdl != m_documentLoader) { |
1646 ASSERT(m_state == FrameStateComplete); | 1636 ASSERT(m_state == FrameStateComplete); |
1647 return; | 1637 return; |
1648 } | 1638 } |
1649 | 1639 |
1650 setState(FrameStateCommittedPage); | 1640 setState(FrameStateCommittedPage); |
1651 | 1641 |
1652 if (isLoadingMainFrame()) | 1642 if (isLoadingMainFrame()) |
1653 m_frame->page()->chrome()->client()->needTouchEvents(false); | 1643 m_frame->page()->chrome()->client()->needTouchEvents(false); |
1654 | 1644 |
1655 // Handle adding the URL to the back/forward list. | 1645 history()->updateForCommit(); |
1656 DocumentLoader* dl = m_documentLoader.get(); | 1646 m_client->transitionToCommittedForNewPage(); |
1657 | |
1658 switch (m_loadType) { | |
1659 case FrameLoadTypeForward: | |
1660 case FrameLoadTypeBack: | |
1661 case FrameLoadTypeIndexedBackForward: | |
1662 if (m_frame->page()) { | |
1663 // If the first load within a frame is a navigation within a bac k/forward list that was attached | |
1664 // without any of the items being loaded then we need to update the history in a similar manner as | |
1665 // for a standard load with the exception of updating the back/f orward list (<rdar://problem/8091103>). | |
1666 if (!m_stateMachine.committedFirstRealDocumentLoad() && isLoadin gMainFrame()) | |
1667 history()->updateForStandardLoad(HistoryController::UpdateAl lExceptBackForwardList); | |
Nate Chapin
2013/05/01 21:38:34
This case appears to be a Safari-specific hack: ht
| |
1668 | |
1669 history()->updateForBackForwardNavigation(); | |
1670 | |
1671 if (history()->currentItem()) | |
1672 m_pendingStateObject = history()->currentItem()->stateObject (); | |
1673 | |
1674 // Create a document view for this document. | |
1675 m_client->transitionToCommittedForNewPage(); | |
1676 } | |
1677 break; | |
1678 | |
1679 case FrameLoadTypeReload: | |
1680 case FrameLoadTypeReloadFromOrigin: | |
1681 case FrameLoadTypeSame: | |
1682 case FrameLoadTypeReplace: | |
1683 history()->updateForReload(); | |
1684 m_client->transitionToCommittedForNewPage(); | |
1685 break; | |
1686 | |
1687 case FrameLoadTypeStandard: | |
1688 history()->updateForStandardLoad(); | |
1689 if (m_frame->view()) | |
1690 m_frame->view()->setScrollbarsSuppressed(true); | |
Nate Chapin
2013/05/01 21:38:34
This appears to only be needed for SVGImage, so it
| |
1691 m_client->transitionToCommittedForNewPage(); | |
1692 break; | |
1693 | |
1694 case FrameLoadTypeRedirectWithLockedBackForwardList: | |
1695 history()->updateForRedirectWithLockedBackForwardList(); | |
1696 m_client->transitionToCommittedForNewPage(); | |
1697 break; | |
1698 | |
1699 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is). | |
1700 // An exception should be thrown if we're in the FrameLoadTypeUninitiali zed state. | |
1701 default: | |
1702 ASSERT_NOT_REACHED(); | |
1703 } | |
1704 | |
1705 m_documentLoader->writer()->setMIMEType(dl->responseMIMEType()); | |
Nate Chapin
2013/05/01 21:38:34
Moved to DocumentLoader.
abarth-chromium
2013/05/06 17:09:42
Nice.
| |
1706 | |
1707 // Tell the client we've committed this URL. | |
1708 ASSERT(m_frame->view()); | |
Nate Chapin
2013/05/01 21:38:34
This is guaranteed by transitionToCommittedForNewP
| |
1709 | |
1710 if (m_stateMachine.creatingInitialEmptyDocument()) | |
1711 return; | |
1712 | |
1713 if (!m_stateMachine.committedFirstRealDocumentLoad()) | |
1714 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmpty DocumentPostCommit); | |
Nate Chapin
2013/05/01 21:38:34
This has been changed to advance to CommittedFirst
| |
1715 } | 1647 } |
1716 | 1648 |
1717 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgres s) | 1649 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgres s) |
1718 { | 1650 { |
1719 // Note that -webView:didCancelClientRedirectForFrame: is called on the fram e load delegate even if | 1651 // Note that -webView:didCancelClientRedirectForFrame: is called on the fram e load delegate even if |
1720 // the redirect succeeded. We should either rename this API, or add a new m ethod, like | 1652 // the redirect succeeded. We should either rename this API, or add a new m ethod, like |
1721 // -webView:didFinishClientRedirectForFrame: | 1653 // -webView:didFinishClientRedirectForFrame: |
1722 m_client->dispatchDidCancelClientRedirect(); | 1654 m_client->dispatchDidCancelClientRedirect(); |
1723 | 1655 |
1724 if (!cancelWithLoadInProgress) | 1656 if (!cancelWithLoadInProgress) |
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1997 | 1929 |
1998 void FrameLoader::didLayout(LayoutMilestones milestones) | 1930 void FrameLoader::didLayout(LayoutMilestones milestones) |
1999 { | 1931 { |
2000 m_client->dispatchDidLayout(milestones); | 1932 m_client->dispatchDidLayout(milestones); |
2001 } | 1933 } |
2002 | 1934 |
2003 void FrameLoader::didFirstLayout() | 1935 void FrameLoader::didFirstLayout() |
2004 { | 1936 { |
2005 if (m_frame->page() && isBackForwardLoadType(m_loadType)) | 1937 if (m_frame->page() && isBackForwardLoadType(m_loadType)) |
2006 history()->restoreScrollPositionAndViewState(); | 1938 history()->restoreScrollPositionAndViewState(); |
2007 | |
2008 if (m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDis playingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone()) | |
2009 m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone); | |
2010 } | 1939 } |
2011 | 1940 |
2012 void FrameLoader::frameLoadCompleted() | 1941 void FrameLoader::frameLoadCompleted() |
2013 { | 1942 { |
2014 // Note: Can be called multiple times. | 1943 // Note: Can be called multiple times. |
2015 history()->updateForFrameLoadCompleted(); | 1944 history()->updateForFrameLoadCompleted(); |
2016 | |
2017 // After a canceled provisional load, firstLayoutDone is false. | |
2018 // Reset it to true if we're displaying a page. | |
2019 if (m_documentLoader && m_stateMachine.committedFirstRealDocumentLoad() && ! m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayout Done()) | |
2020 m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone); | |
2021 } | 1945 } |
2022 | 1946 |
2023 void FrameLoader::detachChildren() | 1947 void FrameLoader::detachChildren() |
2024 { | 1948 { |
2025 typedef Vector<RefPtr<Frame> > FrameVector; | 1949 typedef Vector<RefPtr<Frame> > FrameVector; |
2026 FrameVector childrenToDetach; | 1950 FrameVector childrenToDetach; |
2027 childrenToDetach.reserveCapacity(m_frame->tree()->childCount()); | 1951 childrenToDetach.reserveCapacity(m_frame->tree()->childCount()); |
2028 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree ()->previousSibling()) | 1952 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree ()->previousSibling()) |
2029 childrenToDetach.append(child); | 1953 childrenToDetach.append(child); |
2030 FrameVector::iterator end = childrenToDetach.end(); | 1954 FrameVector::iterator end = childrenToDetach.end(); |
(...skipping 916 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2947 | 2871 |
2948 void FrameLoader::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | 2872 void FrameLoader::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const |
2949 { | 2873 { |
2950 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Loader); | 2874 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Loader); |
2951 info.addMember(m_frame, "frame"); | 2875 info.addMember(m_frame, "frame"); |
2952 info.ignoreMember(m_client); | 2876 info.ignoreMember(m_client); |
2953 info.addMember(m_progressTracker, "progressTracker"); | 2877 info.addMember(m_progressTracker, "progressTracker"); |
2954 info.addMember(m_documentLoader, "documentLoader"); | 2878 info.addMember(m_documentLoader, "documentLoader"); |
2955 info.addMember(m_provisionalDocumentLoader, "provisionalDocumentLoader"); | 2879 info.addMember(m_provisionalDocumentLoader, "provisionalDocumentLoader"); |
2956 info.addMember(m_policyDocumentLoader, "policyDocumentLoader"); | 2880 info.addMember(m_policyDocumentLoader, "policyDocumentLoader"); |
2957 info.addMember(m_pendingStateObject, "pendingStateObject"); | |
2958 info.addMember(m_submittedFormURL, "submittedFormURL"); | 2881 info.addMember(m_submittedFormURL, "submittedFormURL"); |
2959 info.addMember(m_checkTimer, "checkTimer"); | 2882 info.addMember(m_checkTimer, "checkTimer"); |
2960 info.addMember(m_opener, "opener"); | 2883 info.addMember(m_opener, "opener"); |
2961 info.addMember(m_openedFrames, "openedFrames"); | 2884 info.addMember(m_openedFrames, "openedFrames"); |
2962 info.addMember(m_outgoingReferrer, "outgoingReferrer"); | 2885 info.addMember(m_outgoingReferrer, "outgoingReferrer"); |
2963 info.addMember(m_networkingContext, "networkingContext"); | 2886 info.addMember(m_networkingContext, "networkingContext"); |
2964 info.addMember(m_previousURL, "previousURL"); | 2887 info.addMember(m_previousURL, "previousURL"); |
2965 info.addMember(m_requestedHistoryItem, "requestedHistoryItem"); | 2888 info.addMember(m_requestedHistoryItem, "requestedHistoryItem"); |
2966 } | 2889 } |
2967 | 2890 |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3039 FloatRect newWindowRect = DOMWindow::adjustWindowRect(page, windowRect); | 2962 FloatRect newWindowRect = DOMWindow::adjustWindowRect(page, windowRect); |
3040 | 2963 |
3041 page->chrome()->setWindowRect(newWindowRect); | 2964 page->chrome()->setWindowRect(newWindowRect); |
3042 page->chrome()->show(); | 2965 page->chrome()->show(); |
3043 | 2966 |
3044 created = true; | 2967 created = true; |
3045 return frame; | 2968 return frame; |
3046 } | 2969 } |
3047 | 2970 |
3048 } // namespace WebCore | 2971 } // namespace WebCore |
OLD | NEW |