From 09b279d447e0c1cca25522f380cce1abbeed04d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Viricel?= Date: Tue, 22 May 2018 23:40:58 +0200 Subject: [PATCH] Initial Commit - Plugin v1.0.0 --- .DS_Store | Bin 0 -> 8196 bytes assets/.DS_Store | Bin 0 -> 8196 bytes assets/images/.DS_Store | Bin 0 -> 6148 bytes assets/images/icon-dot-empty.svg | 3 + assets/images/icon-dot-plain.svg | 5 + assets/images/ratings-slider-placeholder.jpg | Bin 0 -> 67635 bytes assets/scripts/.DS_Store | Bin 0 -> 6148 bytes assets/scripts/bootstrap.min.js | 7 + assets/scripts/slider.js | 16 + assets/styles/.DS_Store | Bin 0 -> 6148 bytes assets/styles/bootstrap.min.css | 7 + assets/styles/slider.css | 27 + composer.json | 5 + composer.lock | 76 ++ includes/activate.php | 22 + includes/admin/enqueue.php | 25 + includes/admin/fb-login-cb.php | 69 ++ includes/admin/init.php | 10 + includes/admin/menus.php | 11 + includes/admin/options-page.php | 142 +++ includes/deactivate.php | 22 + includes/front/enqueue.php | 21 + includes/init.php | 5 + includes/widgets.php | 5 + includes/widgets/ratings-slider.php | 161 +++ index.php | 46 + process/save-options.php | 30 + process/select-page.php | 21 + vendor/autoload.php | 7 + vendor/composer/ClassLoader.php | 445 ++++++++ vendor/composer/LICENSE | 21 + vendor/composer/autoload_classmap.php | 9 + vendor/composer/autoload_files.php | 10 + vendor/composer/autoload_namespaces.php | 9 + vendor/composer/autoload_psr4.php | 10 + vendor/composer/autoload_real.php | 70 ++ vendor/composer/autoload_static.php | 35 + vendor/composer/installed.json | 62 ++ vendor/facebook/graph-sdk/CODE_OF_CONDUCT.md | 3 + vendor/facebook/graph-sdk/LICENSE | 19 + vendor/facebook/graph-sdk/composer.json | 42 + vendor/facebook/graph-sdk/phpcs.xml.dist | 7 + .../Facebook/Authentication/AccessToken.php | 160 +++ .../Authentication/AccessTokenMetadata.php | 390 +++++++ .../Facebook/Authentication/OAuth2Client.php | 292 ++++++ .../FacebookAuthenticationException.php | 33 + .../FacebookAuthorizationException.php | 33 + .../Exceptions/FacebookClientException.php | 33 + .../Exceptions/FacebookOtherException.php | 33 + .../Exceptions/FacebookResponseException.php | 216 ++++ .../FacebookResumableUploadException.php | 33 + .../Exceptions/FacebookSDKException.php | 33 + .../Exceptions/FacebookServerException.php | 33 + .../Exceptions/FacebookThrottleException.php | 33 + .../graph-sdk/src/Facebook/Facebook.php | 635 +++++++++++ .../graph-sdk/src/Facebook/FacebookApp.php | 110 ++ .../src/Facebook/FacebookBatchRequest.php | 322 ++++++ .../src/Facebook/FacebookBatchResponse.php | 174 +++ .../graph-sdk/src/Facebook/FacebookClient.php | 250 +++++ .../src/Facebook/FacebookRequest.php | 534 ++++++++++ .../src/Facebook/FacebookResponse.php | 410 ++++++++ .../src/Facebook/FileUpload/FacebookFile.php | 169 +++ .../FileUpload/FacebookResumableUploader.php | 167 +++ .../FileUpload/FacebookTransferChunk.php | 133 +++ .../src/Facebook/FileUpload/FacebookVideo.php | 33 + .../src/Facebook/FileUpload/Mimetypes.php | 988 ++++++++++++++++++ .../src/Facebook/GraphNodes/Birthday.php | 85 ++ .../src/Facebook/GraphNodes/Collection.php | 242 +++++ .../Facebook/GraphNodes/GraphAchievement.php | 112 ++ .../src/Facebook/GraphNodes/GraphAlbum.php | 183 ++++ .../Facebook/GraphNodes/GraphApplication.php | 43 + .../Facebook/GraphNodes/GraphCoverPhoto.php | 72 ++ .../src/Facebook/GraphNodes/GraphEdge.php | 252 +++++ .../src/Facebook/GraphNodes/GraphEvent.php | 242 +++++ .../src/Facebook/GraphNodes/GraphGroup.php | 170 +++ .../src/Facebook/GraphNodes/GraphList.php | 36 + .../src/Facebook/GraphNodes/GraphLocation.php | 102 ++ .../src/Facebook/GraphNodes/GraphNode.php | 197 ++++ .../Facebook/GraphNodes/GraphNodeFactory.php | 392 +++++++ .../src/Facebook/GraphNodes/GraphObject.php | 36 + .../GraphNodes/GraphObjectFactory.php | 88 ++ .../src/Facebook/GraphNodes/GraphPage.php | 147 +++ .../src/Facebook/GraphNodes/GraphPicture.php | 72 ++ .../Facebook/GraphNodes/GraphSessionInfo.php | 102 ++ .../src/Facebook/GraphNodes/GraphUser.php | 172 +++ .../Facebook/Helpers/FacebookCanvasHelper.php | 52 + .../Helpers/FacebookJavaScriptHelper.php | 42 + .../Helpers/FacebookPageTabHelper.php | 95 ++ .../Helpers/FacebookRedirectLoginHelper.php | 333 ++++++ .../FacebookSignedRequestFromInputHelper.php | 166 +++ .../src/Facebook/Http/GraphRawResponse.php | 137 +++ .../Facebook/Http/RequestBodyInterface.php | 39 + .../Facebook/Http/RequestBodyMultipart.php | 170 +++ .../Facebook/Http/RequestBodyUrlEncoded.php | 55 + .../src/Facebook/HttpClients/FacebookCurl.php | 129 +++ .../HttpClients/FacebookCurlHttpClient.php | 163 +++ .../HttpClients/FacebookGuzzleHttpClient.php | 97 ++ .../FacebookHttpClientInterface.php | 47 + .../Facebook/HttpClients/FacebookStream.php | 80 ++ .../HttpClients/FacebookStreamHttpClient.php | 94 ++ .../HttpClients/HttpClientsFactory.php | 99 ++ .../certs/DigiCertHighAssuranceEVRootCA.pem | 23 + .../FacebookMemoryPersistentDataHandler.php | 53 + .../FacebookSessionPersistentDataHandler.php | 76 ++ .../PersistentData/PersistentDataFactory.php | 65 ++ .../PersistentDataInterface.php | 49 + .../McryptPseudoRandomStringGenerator.php | 68 ++ .../OpenSslPseudoRandomStringGenerator.php | 67 ++ .../PseudoRandomStringGeneratorFactory.php | 101 ++ .../PseudoRandomStringGeneratorInterface.php | 45 + .../PseudoRandomStringGeneratorTrait.php | 58 + ...RandomBytesPseudoRandomStringGenerator.php | 59 ++ .../UrandomPseudoRandomStringGenerator.php | 89 ++ .../graph-sdk/src/Facebook/SignedRequest.php | 326 ++++++ .../Url/FacebookUrlDetectionHandler.php | 182 ++++ .../Facebook/Url/FacebookUrlManipulator.php | 167 +++ .../Facebook/Url/UrlDetectionInterface.php | 39 + .../graph-sdk/src/Facebook/autoload.php | 81 ++ .../graph-sdk/src/Facebook/polyfills.php | 49 + 119 files changed, 12872 insertions(+) create mode 100644 .DS_Store create mode 100644 assets/.DS_Store create mode 100644 assets/images/.DS_Store create mode 100644 assets/images/icon-dot-empty.svg create mode 100644 assets/images/icon-dot-plain.svg create mode 100644 assets/images/ratings-slider-placeholder.jpg create mode 100644 assets/scripts/.DS_Store create mode 100755 assets/scripts/bootstrap.min.js create mode 100644 assets/scripts/slider.js create mode 100644 assets/styles/.DS_Store create mode 100755 assets/styles/bootstrap.min.css create mode 100644 assets/styles/slider.css create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 includes/activate.php create mode 100644 includes/admin/enqueue.php create mode 100644 includes/admin/fb-login-cb.php create mode 100644 includes/admin/init.php create mode 100644 includes/admin/menus.php create mode 100644 includes/admin/options-page.php create mode 100644 includes/deactivate.php create mode 100644 includes/front/enqueue.php create mode 100644 includes/init.php create mode 100644 includes/widgets.php create mode 100644 includes/widgets/ratings-slider.php create mode 100644 index.php create mode 100644 process/save-options.php create mode 100644 process/select-page.php create mode 100644 vendor/autoload.php create mode 100644 vendor/composer/ClassLoader.php create mode 100644 vendor/composer/LICENSE create mode 100644 vendor/composer/autoload_classmap.php create mode 100644 vendor/composer/autoload_files.php create mode 100644 vendor/composer/autoload_namespaces.php create mode 100644 vendor/composer/autoload_psr4.php create mode 100644 vendor/composer/autoload_real.php create mode 100644 vendor/composer/autoload_static.php create mode 100644 vendor/composer/installed.json create mode 100644 vendor/facebook/graph-sdk/CODE_OF_CONDUCT.md create mode 100644 vendor/facebook/graph-sdk/LICENSE create mode 100644 vendor/facebook/graph-sdk/composer.json create mode 100644 vendor/facebook/graph-sdk/phpcs.xml.dist create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessToken.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessTokenMetadata.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Authentication/OAuth2Client.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookAuthenticationException.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookAuthorizationException.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookClientException.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookOtherException.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookResponseException.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookResumableUploadException.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookSDKException.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookServerException.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookThrottleException.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Facebook.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/FacebookApp.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/FacebookBatchRequest.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/FacebookBatchResponse.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/FacebookClient.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/FacebookRequest.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/FacebookResponse.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookFile.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookResumableUploader.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookTransferChunk.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookVideo.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/FileUpload/Mimetypes.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Birthday.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Collection.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAchievement.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAlbum.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphApplication.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphCoverPhoto.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEdge.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEvent.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphGroup.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphList.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphLocation.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNode.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphObject.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphObjectFactory.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPage.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPicture.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphSessionInfo.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphUser.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookCanvasHelper.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookJavaScriptHelper.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookPageTabHelper.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookRedirectLoginHelper.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookSignedRequestFromInputHelper.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Http/GraphRawResponse.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyInterface.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyMultipart.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyUrlEncoded.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurl.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurlHttpClient.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookGuzzleHttpClient.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookHttpClientInterface.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookStream.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookStreamHttpClient.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/HttpClients/HttpClientsFactory.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/HttpClients/certs/DigiCertHighAssuranceEVRootCA.pem create mode 100644 vendor/facebook/graph-sdk/src/Facebook/PersistentData/FacebookMemoryPersistentDataHandler.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/PersistentData/FacebookSessionPersistentDataHandler.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/PersistentData/PersistentDataFactory.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/PersistentData/PersistentDataInterface.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/McryptPseudoRandomStringGenerator.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/OpenSslPseudoRandomStringGenerator.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorFactory.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorInterface.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorTrait.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/RandomBytesPseudoRandomStringGenerator.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/UrandomPseudoRandomStringGenerator.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/SignedRequest.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlDetectionHandler.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlManipulator.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/Url/UrlDetectionInterface.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/autoload.php create mode 100644 vendor/facebook/graph-sdk/src/Facebook/polyfills.php diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..3fe7509433ab1046f7e965bab16674f285e7c8d6 GIT binary patch literal 8196 zcmeHM-EI;=6h6};ESN?vOv>fnn0V1N+tx^oF+mC!Bx;Npy-?EvO90*OlHH}Kh}j$8 zL45-s#V7DVd;tB<%vhI&HZdlqjdRG%H$Uf_9lkTW!z@H3>JxW|s6s>*5@Y!?vK7Yt zoR(}&w_E`V@Tuhmy{;E@Q7w&PAbiRzv38P^_m;$c^p9|wVVQtou0jQZ1q^40yok2@p3A4>Ab?Zf5y(~<86 z(|R!R-AInpRvngAw2BAi%51jh+}g5l>^k!;dseMFDDT~z&x_XPwVgYy!=pEEXYc0k zKS`NL=w}qMxM};0%7P%r?a=oEe}H!8Y)}uP9?=*%OBO=#mna3~XQcZ8?~kd_tYUiL z_2^ZG$)cy37J})+&!Y*sxMn6u#Eale|MM8AU8nljfm#wK6Re^XjwO4IFpX(Q<3*`i zI$@=PRG@p*qJ3)818P%q(OYan==9xIz?h*7A%e0L7QWBYVJXrhjC+?FbRW2lMdW72 z=OvRKKTpS)yN{sbKF;{^Tz-$vOS6W=m?)Gh9GTpOfoA`QF2;-k7fFG2HQ5TE|C^`3 z|G!9I$;{O#U=;X61w^jVZqz}NyZQ<;@A5X%Arc$=B?=`4*}@M2)KC5}MA?Qbb7~qB Tg=m497XeZRlNkm6sRBO%1Vt>o literal 0 HcmV?d00001 diff --git a/assets/.DS_Store b/assets/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..65569fcff6c7de982f25615f1f379ac103d4a444 GIT binary patch literal 8196 zcmeHMPfrs;6n}#iwiRs^u*8Gb5Y!kCtr(3l#-?HjF_DHP2oZ&CJCu#PJI(GCEEUs> zCqICHuAV&UmoU+jM^Ae6?9rRPnb|_S2p5fzIFro$-p;)DcIUk}GksG4AccA*2QUl( z23CQoL)iSLh;dQ3m7cKYC?Y|501CmR!^$Oxm9}x~4s8K#0c`QY#Fj$2bzmb?0K^z}%YroK0a7LtVm`!{LMe(mRrWwa zQ4*#YM2X{gMzAC1Lu@Hj;y{!*knqhU%utAYJIZAwJCM9W-D(SH3v9Q5$lZIv1{W-- zM)G%DN+gZr=YGl}g}Zo5Ye6l{^*@$sjver9_A}`@5Ifl0XBY`1aX4|`Tw!Y_w|G4$ zSpGfnRJ8a?DWqo@b2e$KG;7nf#nj+U=5fpRs4s=>3PqNMyS7(hYXw&KDuL8vssY1@ z8}Y@|aI-m0)-{LZ*4;N*3v{%NrYUBR!hCKDp#J)|-zvp1f2xAmKg&N%g$h zzCx;Nl1?>emYG}I@=VgG;=lkC##Z5|=yvr)Pj@MRp*S~7|p2NH<>J{JI z2LY79N0-%rLohL2%+>?$<46qdpc7qm;x?|1OBu00Uc=hy)QHXww|>}bx2BuTt2y*! zZfsYtzQ7q_+0m=Q>ycU7<<&5F$Oa_Z_Q5ohh%t zIA`vhU1py8s-#qck42vf1tT}UOS{2H{&t%^# zLcbS7pF;y2u}|#~_+31auz!PZ=nVTV-u)KzV44HWEb{+bJKz8R_4jIp+5*}F`^N$#Hg1j=@O#=vbM(_huARZUgjE#5*HS1&u#xFF tqD;pTH~%n1I)ki2CLdx;A@*ST=NAE;xlG6J34Q+SpS*kVlXtJq|6k-VxikO( literal 0 HcmV?d00001 diff --git a/assets/images/.DS_Store b/assets/images/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f7818e02d2f1bbf5db144d4eba824b15fc7801c6 GIT binary patch literal 6148 zcmeHKyG{c^3>-s>NHi&_(3UhoqNZ6zp`hjm$ODB$Ck~O&U&m*|_yOWLXep2_*|Y1% zu6By^8Gy`Q)|bEpz?iCtS2aV?xavTT!Xrc~&v?WJdrYa#Ap2*B)}G-R3mmZR)o-!J zJtI>*@w5e2+&!S>+Wi;UF|xU7+SRgYmpn%waYa3UGvO*F8At|_fn*>VNCv($puLwe zK5 + + \ No newline at end of file diff --git a/assets/images/icon-dot-plain.svg b/assets/images/icon-dot-plain.svg new file mode 100644 index 0000000..854d95e --- /dev/null +++ b/assets/images/icon-dot-plain.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/assets/images/ratings-slider-placeholder.jpg b/assets/images/ratings-slider-placeholder.jpg new file mode 100644 index 0000000000000000000000000000000000000000..77cb914a8eeeca326e32d79bbbe46703c23a53c2 GIT binary patch literal 67635 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 DGmtAL literal 0 HcmV?d00001 diff --git a/assets/scripts/bootstrap.min.js b/assets/scripts/bootstrap.min.js new file mode 100755 index 0000000..0e846b7 --- /dev/null +++ b/assets/scripts/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.1.1 (https://getbootstrap.com/) + * Copyright 2011-2018 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e(t.bootstrap={},t.jQuery,t.Popper)}(this,function(t,e,c){"use strict";function i(t,e){for(var n=0;nthis._items.length-1||t<0))if(this._isSliding)P(this._element).one(Q.SLID,function(){return e.to(t)});else{if(n===t)return this.pause(),void this.cycle();var i=ndocument.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},t._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},t._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=t.left+t.right

',trigger:"hover focus",title:"",delay:0,html:!(_e={AUTO:"auto",TOP:"top",RIGHT:"right",BOTTOM:"bottom",LEFT:"left"}),selector:!(de={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)"}),placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent"},pe="out",ve={HIDE:"hide"+he,HIDDEN:"hidden"+he,SHOW:(me="show")+he,SHOWN:"shown"+he,INSERTED:"inserted"+he,CLICK:"click"+he,FOCUSIN:"focusin"+he,FOCUSOUT:"focusout"+he,MOUSEENTER:"mouseenter"+he,MOUSELEAVE:"mouseleave"+he},Ee="fade",ye="show",Te=".tooltip-inner",Ce=".arrow",Ie="hover",Ae="focus",De="click",be="manual",Se=function(){function i(t,e){if("undefined"==typeof c)throw new TypeError("Bootstrap tooltips require Popper.js (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var t=i.prototype;return t.enable=function(){this._isEnabled=!0},t.disable=function(){this._isEnabled=!1},t.toggleEnabled=function(){this._isEnabled=!this._isEnabled},t.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=oe(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),oe(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(oe(this.getTipElement()).hasClass(ye))return void this._leave(null,this);this._enter(null,this)}},t.dispose=function(){clearTimeout(this._timeout),oe.removeData(this.element,this.constructor.DATA_KEY),oe(this.element).off(this.constructor.EVENT_KEY),oe(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&oe(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,(this._activeTrigger=null)!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},t.show=function(){var e=this;if("none"===oe(this.element).css("display"))throw new Error("Please use show on visible elements");var t=oe.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){oe(this.element).trigger(t);var n=oe.contains(this.element.ownerDocument.documentElement,this.element);if(t.isDefaultPrevented()||!n)return;var i=this.getTipElement(),r=Cn.getUID(this.constructor.NAME);i.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&oe(i).addClass(Ee);var s="function"==typeof this.config.placement?this.config.placement.call(this,i,this.element):this.config.placement,o=this._getAttachment(s);this.addAttachmentClass(o);var a=!1===this.config.container?document.body:oe(this.config.container);oe(i).data(this.constructor.DATA_KEY,this),oe.contains(this.element.ownerDocument.documentElement,this.tip)||oe(i).appendTo(a),oe(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new c(this.element,i,{placement:o,modifiers:{offset:{offset:this.config.offset},flip:{behavior:this.config.fallbackPlacement},arrow:{element:Ce},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){e._handlePopperPlacementChange(t)}}),oe(i).addClass(ye),"ontouchstart"in document.documentElement&&oe(document.body).children().on("mouseover",null,oe.noop);var l=function(){e.config.animation&&e._fixTransition();var t=e._hoverState;e._hoverState=null,oe(e.element).trigger(e.constructor.Event.SHOWN),t===pe&&e._leave(null,e)};if(oe(this.tip).hasClass(Ee)){var h=Cn.getTransitionDurationFromElement(this.tip);oe(this.tip).one(Cn.TRANSITION_END,l).emulateTransitionEnd(h)}else l()}},t.hide=function(t){var e=this,n=this.getTipElement(),i=oe.Event(this.constructor.Event.HIDE),r=function(){e._hoverState!==me&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),oe(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(oe(this.element).trigger(i),!i.isDefaultPrevented()){if(oe(n).removeClass(ye),"ontouchstart"in document.documentElement&&oe(document.body).children().off("mouseover",null,oe.noop),this._activeTrigger[De]=!1,this._activeTrigger[Ae]=!1,this._activeTrigger[Ie]=!1,oe(this.tip).hasClass(Ee)){var s=Cn.getTransitionDurationFromElement(n);oe(n).one(Cn.TRANSITION_END,r).emulateTransitionEnd(s)}else r();this._hoverState=""}},t.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},t.isWithContent=function(){return Boolean(this.getTitle())},t.addAttachmentClass=function(t){oe(this.getTipElement()).addClass(ue+"-"+t)},t.getTipElement=function(){return this.tip=this.tip||oe(this.config.template)[0],this.tip},t.setContent=function(){var t=oe(this.getTipElement());this.setElementContent(t.find(Te),this.getTitle()),t.removeClass(Ee+" "+ye)},t.setElementContent=function(t,e){var n=this.config.html;"object"==typeof e&&(e.nodeType||e.jquery)?n?oe(e).parent().is(t)||t.empty().append(e):t.text(oe(e).text()):t[n?"html":"text"](e)},t.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},t._getAttachment=function(t){return _e[t.toUpperCase()]},t._setListeners=function(){var i=this;this.config.trigger.split(" ").forEach(function(t){if("click"===t)oe(i.element).on(i.constructor.Event.CLICK,i.config.selector,function(t){return i.toggle(t)});else if(t!==be){var e=t===Ie?i.constructor.Event.MOUSEENTER:i.constructor.Event.FOCUSIN,n=t===Ie?i.constructor.Event.MOUSELEAVE:i.constructor.Event.FOCUSOUT;oe(i.element).on(e,i.config.selector,function(t){return i._enter(t)}).on(n,i.config.selector,function(t){return i._leave(t)})}oe(i.element).closest(".modal").on("hide.bs.modal",function(){return i.hide()})}),this.config.selector?this.config=h({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},t._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},t._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||oe(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),oe(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Ae:Ie]=!0),oe(e.getTipElement()).hasClass(ye)||e._hoverState===me?e._hoverState=me:(clearTimeout(e._timeout),e._hoverState=me,e.config.delay&&e.config.delay.show?e._timeout=setTimeout(function(){e._hoverState===me&&e.show()},e.config.delay.show):e.show())},t._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||oe(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),oe(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Ae:Ie]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=pe,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout(function(){e._hoverState===pe&&e.hide()},e.config.delay.hide):e.hide())},t._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},t._getConfig=function(t){return"number"==typeof(t=h({},this.constructor.Default,oe(this.element).data(),"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),Cn.typeCheckConfig(ae,t,this.constructor.DefaultType),t},t._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},t._cleanTipClass=function(){var t=oe(this.getTipElement()),e=t.attr("class").match(fe);null!==e&&0

'}),He=h({},Nn.DefaultType,{content:"(string|element|function)"}),We="fade",xe=".popover-header",Ue=".popover-body",Ke={HIDE:"hide"+ke,HIDDEN:"hidden"+ke,SHOW:(Me="show")+ke,SHOWN:"shown"+ke,INSERTED:"inserted"+ke,CLICK:"click"+ke,FOCUSIN:"focusin"+ke,FOCUSOUT:"focusout"+ke,MOUSEENTER:"mouseenter"+ke,MOUSELEAVE:"mouseleave"+ke},Fe=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),(e.prototype.constructor=e).__proto__=n;var r=i.prototype;return r.isWithContent=function(){return this.getTitle()||this._getContent()},r.addAttachmentClass=function(t){we(this.getTipElement()).addClass(Le+"-"+t)},r.getTipElement=function(){return this.tip=this.tip||we(this.config.template)[0],this.tip},r.setContent=function(){var t=we(this.getTipElement());this.setElementContent(t.find(xe),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(Ue),e),t.removeClass(We+" "+Me)},r._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},r._cleanTipClass=function(){var t=we(this.getTipElement()),e=t.attr("class").match(je);null!==e&&0=this._offsets[r]&&("undefined"==typeof this._offsets[r+1]||tH1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#212529;border-color:#32383e}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#212529}.table-dark td,.table-dark th,.table-dark thead th{border-color:#32383e}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.input-group-append>.form-control-plaintext.btn,.input-group-lg>.input-group-append>.form-control-plaintext.input-group-text,.input-group-lg>.input-group-prepend>.form-control-plaintext.btn,.input-group-lg>.input-group-prepend>.form-control-plaintext.input-group-text,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.input-group-append>.form-control-plaintext.btn,.input-group-sm>.input-group-append>.form-control-plaintext.input-group-text,.input-group-sm>.input-group-prepend>.form-control-plaintext.btn,.input-group-sm>.input-group-prepend>.form-control-plaintext.input-group-text{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-sm>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-lg>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:calc(2.875rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(40,167,69,.8);border-radius:.2rem}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#28a745}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.form-control-file.is-valid~.valid-feedback,.form-control-file.is-valid~.valid-tooltip,.was-validated .form-control-file:valid~.valid-feedback,.was-validated .form-control-file:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{background-color:#71dd8a}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(40,167,69,.25)}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label::before,.was-validated .custom-file-input:valid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,.8);border-radius:.2rem}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.form-control-file.is-invalid~.invalid-feedback,.form-control-file.is-invalid~.invalid-tooltip,.was-validated .form-control-file:invalid~.invalid-feedback,.was-validated .form-control-file:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{background-color:#efa2a9}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label::before,.was-validated .custom-file-input:invalid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn:not(:disabled):not(.disabled).active,.btn:not(:disabled):not(.disabled):active{background-image:none}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;background-color:transparent;background-image:none;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;background-color:transparent}.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent;border-color:transparent}.btn-link.focus,.btn-link:focus{text-decoration:underline;border-color:transparent;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media screen and (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media screen and (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-right{right:0;left:auto}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;width:0;height:0;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:0 1 auto;flex:0 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file:focus,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control{margin-left:-1px}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:active~.custom-control-label::before{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{position:relative;margin-bottom:0}.custom-control-label::before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#dee2e6}.custom-control-label::after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:inset 0 1px 2px rgba(0,0,0,.075),0 0 5px rgba(128,189,255,.5)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-select-lg{height:calc(2.875rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:125%}.custom-file{position:relative;display:inline-block;width:100%;height:calc(2.25rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(2.25rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:focus~.custom-file-label::after{border-color:#80bdff}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(2.25rem + 2px);padding:.375rem .75rem;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:2.25rem;padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:1px solid #ced4da;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;padding-left:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#007bff;border:0;border-radius:1rem;-webkit-appearance:none;appearance:none}.custom-range::-webkit-slider-thumb:focus{outline:0;box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;-moz-appearance:none;appearance:none}.custom-range::-moz-range-thumb:focus{outline:0;box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;appearance:none}.custom-range::-ms-thumb:focus{outline:0;box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler:not(:disabled):not(.disabled){cursor:pointer}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-ms-flexbox;display:flex;-ms-flex:1 0 0%;flex:1 0 0%;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:first-child .card-header,.card-group>.card:first-child .card-img-top{border-top-right-radius:0}.card-group>.card:first-child .card-footer,.card-group>.card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:last-child .card-header,.card-group>.card:last-child .card-img-top{border-top-left-radius:0}.card-group>.card:last-child .card-footer,.card-group>.card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:.25rem}.card-group>.card:only-child .card-header,.card-group>.card:only-child .card-img-top{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-group>.card:only-child .card-footer,.card-group>.card:only-child .card-img-bottom{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-group>.card:not(:first-child):not(:last-child):not(:only-child){border-radius:0}.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion .card:not(:first-of-type):not(:last-of-type){border-bottom:0;border-radius:0}.accordion .card:not(:first-of-type) .card-header:first-child{border-radius:0}.accordion .card:first-of-type{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion .card:last-of-type{border-top-left-radius:0;border-top-right-radius:0}.breadcrumb{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-link:not(:disabled):not(.disabled){cursor:pointer}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:focus,.badge-primary[href]:hover{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#6c757d}.badge-secondary[href]:focus,.badge-secondary[href]:hover{color:#fff;text-decoration:none;background-color:#545b62}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:focus,.badge-success[href]:hover{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:focus,.badge-info[href]:hover{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#212529;background-color:#ffc107}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#212529;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:focus,.badge-danger[href]:hover{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#212529;background-color:#f8f9fa}.badge-light[href]:focus,.badge-light[href]:hover{color:#212529;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:focus,.badge-dark[href]:hover{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media screen and (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{z-index:1;text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:focus,.close:hover{color:#000;text-decoration:none;opacity:.75}.close:not(:disabled):not(.disabled){cursor:pointer}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-25%);transform:translate(0,-25%)}@media screen and (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:translate(0,0);transform:translate(0,0)}.modal-dialog-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between;padding:1rem;border-bottom:1px solid #e9ecef;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top] .arrow,.bs-popover-top .arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::after,.bs-popover-top .arrow::before{border-width:.5rem .5rem 0}.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::before{bottom:0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-top .arrow::after{bottom:1px;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right] .arrow,.bs-popover-right .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::after,.bs-popover-right .arrow::before{border-width:.5rem .5rem .5rem 0}.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::before{left:0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-right .arrow::after{left:1px;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom] .arrow,.bs-popover-bottom .arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::after,.bs-popover-bottom .arrow::before{border-width:0 .5rem .5rem .5rem}.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::before{top:0;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-bottom .arrow::after{top:1px;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left] .arrow,.bs-popover-left .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::after,.bs-popover-left .arrow::before{border-width:.5rem 0 .5rem .5rem}.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::before{right:0;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-left .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;-ms-flex-align:center;align-items:center;width:100%;transition:-webkit-transform .6s ease;transition:transform .6s ease;transition:transform .6s ease,-webkit-transform .6s ease;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}@media screen and (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.active.carousel-item-right,.carousel-item-next{-webkit-transform:translateX(100%);transform:translateX(100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-right,.carousel-item-next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translateX(-100%);transform:translateX(-100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.carousel-fade .carousel-item{opacity:0;transition-duration:.6s;transition-property:opacity}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{opacity:0}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev,.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev,.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:rgba(255,255,255,.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-circle{border-radius:50%!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0062cc!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#545b62!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#1e7e34!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#117a8b!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#d39e00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}.table .thead-dark th{color:inherit;border-color:#dee2e6}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/assets/styles/slider.css b/assets/styles/slider.css new file mode 100644 index 0000000..e85852d --- /dev/null +++ b/assets/styles/slider.css @@ -0,0 +1,27 @@ +#ratings-slider .slider-bg { + position: absolute; + z-index: -2; + height: 100%; + -o-object-fit: cover; + object-fit: cover; +} + +#ratings-slider .carousel-caption { + font-style: italic; + top: 50%; + bottom: unset; + left: 50%; + right: unset; + transform: translate(-50%, -50%); + width: 80%; +} + +#ratings-slider .carousel-indicators li { + background-color: transparent; + width: 35px; + height: 35px; +} +.reviews .carousel .carousel-inner .carousel-item { + min-height: 300px; +} + diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..cd1700a --- /dev/null +++ b/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "facebook/graph-sdk": "^5.6" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..f16d4fb --- /dev/null +++ b/composer.lock @@ -0,0 +1,76 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "0719d5c0f2ea9b27280d086fced50c4d", + "packages": [ + { + "name": "facebook/graph-sdk", + "version": "5.6.2", + "source": { + "type": "git", + "url": "https://github.com/facebook/php-graph-sdk.git", + "reference": "030f8c5b9b1a6c09e71719fd638b66ea4daa2f10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facebook/php-graph-sdk/zipball/030f8c5b9b1a6c09e71719fd638b66ea4daa2f10", + "reference": "030f8c5b9b1a6c09e71719fd638b66ea4daa2f10", + "shasum": "" + }, + "require": { + "php": "^5.4|^7.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "~5.0", + "mockery/mockery": "~0.8", + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "guzzlehttp/guzzle": "Allows for implementation of the Guzzle HTTP client", + "paragonie/random_compat": "Provides a better CSPRNG option in PHP 5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Facebook\\": "src/Facebook/" + }, + "files": [ + "src/Facebook/polyfills.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Facebook Platform" + ], + "authors": [ + { + "name": "Facebook", + "homepage": "https://github.com/facebook/php-graph-sdk/contributors" + } + ], + "description": "Facebook SDK for PHP", + "homepage": "https://github.com/facebook/php-graph-sdk", + "keywords": [ + "facebook", + "sdk" + ], + "time": "2018-02-14T23:24:51+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/includes/activate.php b/includes/activate.php new file mode 100644 index 0000000..7af317b --- /dev/null +++ b/includes/activate.php @@ -0,0 +1,22 @@ + null, + 'fbr_app_secret' => null, + 'fbr_page_id' => null, + 'fbr_page_access_token' => null, + 'fbr_ratings' => array(), + ]; + + add_option( 'fbr_opts', $opts ); + } +} \ No newline at end of file diff --git a/includes/admin/enqueue.php b/includes/admin/enqueue.php new file mode 100644 index 0000000..fd2c5bb --- /dev/null +++ b/includes/admin/enqueue.php @@ -0,0 +1,25 @@ + $fbr_app_id, + 'app_secret' => $fbr_app_secret, + 'default_graph_version' => 'v2.2', + ]); + + $helper = $fb->getRedirectLoginHelper(); + + try { + $accessToken = $helper->getAccessToken(); + } catch(Facebook\Exceptions\FacebookResponseException $e) { + // When Graph returns an error + echo 'Graph returned an error: ' . $e->getMessage(); + exit; + } catch(Facebook\Exceptions\FacebookSDKException $e) { + // When validation fails or other local issues + echo 'Facebook SDK returned an error: ' . $e->getMessage(); + exit; + } + + if (! isset($accessToken)) { + if ($helper->getError()) { + header('HTTP/1.0 401 Unauthorized'); + echo "Error: " . $helper->getError() . "\n"; + echo "Error Code: " . $helper->getErrorCode() . "\n"; + echo "Error Reason: " . $helper->getErrorReason() . "\n"; + echo "Error Description: " . $helper->getErrorDescription() . "\n"; + } else { + header('HTTP/1.0 400 Bad Request'); + echo 'Bad request'; + } + exit; + } + + // The OAuth 2.0 client handler helps us manage access tokens + $oAuth2Client = $fb->getOAuth2Client(); + + // Get the access token metadata from /debug_token + $tokenMetadata = $oAuth2Client->debugToken($accessToken); + + // Validation (these will throw FacebookSDKException's when they fail) + $tokenMetadata->validateAppId($fbr_app_id); // Replace {app-id} with your app id + // If you know the user ID this access token belongs to, you can validate it here + //$tokenMetadata->validateUserId('123'); + $tokenMetadata->validateExpiration(); + + if (! $accessToken->isLongLived()) { + // Exchanges a short-lived access token for a long-lived one + try { + $accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken); + } catch (Facebook\Exceptions\FacebookSDKException $e) { + echo "

Error getting long-lived access token: " . $helper->getMessage() . "

\n\n"; + exit; + } + } + + $_SESSION['fb_access_token'] = (string) $accessToken; + + // User is logged in with a long-lived access token. + // You can redirect them to a members-only page. + wp_redirect( admin_url( 'admin.php?page=fbr_plugin_opts&status=2' ) ); +} \ No newline at end of file diff --git a/includes/admin/init.php b/includes/admin/init.php new file mode 100644 index 0000000..4822fcf --- /dev/null +++ b/includes/admin/init.php @@ -0,0 +1,10 @@ + $fbr_app_id, + 'app_secret' => $fbr_app_secret, + 'default_graph_version' => 'v2.2', + 'default_access_token' => $_SESSION['fb_access_token'] + ]); + + try { + // Get the \Facebook\GraphNodes\GraphUser object for the current user. + // If you provided a 'default_access_token', the '{access-token}' is optional. + $response = $fb->get('/me/accounts'); + } catch(\Facebook\Exceptions\FacebookResponseException $e) { + // When Graph returns an error + echo 'Graph returned an error: ' . $e->getMessage(); + exit; + } catch(\Facebook\Exceptions\FacebookSDKException $e) { + // When validation fails or other local issues + echo 'Facebook SDK returned an error: ' . $e->getMessage(); + exit; + } + + $graphEdge = $response->getGraphEdge(); + } + ?> +
+

Facebook Ratings

+

Connectez-vous et autorisez Facebook Ratings à accéder à vos Pages.

+ +
+
+ + +
+ + +
+ + +
+
+ +
+
+ + + + +
+ + + +
+ + +
+
+ + +
+
+
+ +
+
+ + + +
+
+
+ '; + $html .= __( $content, 'wp-fb-ratings' ); + $html .= ''; + $html .= ''; + echo $html; +} \ No newline at end of file diff --git a/includes/deactivate.php b/includes/deactivate.php new file mode 100644 index 0000000..4cfab4f --- /dev/null +++ b/includes/deactivate.php @@ -0,0 +1,22 @@ + null, + 'fbr_app_secret' => null, + 'fbr_page_id' => null, + 'fbr_page_access_token' => null, + 'fbr_ratings' => array(), + ]; + + update_option( 'fbr_opts', $fbr_opts ); + } +} \ No newline at end of file diff --git a/includes/front/enqueue.php b/includes/front/enqueue.php new file mode 100644 index 0000000..400ba24 --- /dev/null +++ b/includes/front/enqueue.php @@ -0,0 +1,21 @@ + 'Displays Page Ratings into a neat slider.', + ); + parent::__construct( + 'fbr_ratings_slider_widget', + 'FB Ratings Slider', + $widget_ops + ); + } + + /** + * Outputs the options form on admin + * + * @param array $instance The widget options + */ + public function form( $instance ) { + // outputs the options form on admin + } + + /** + * Processing widget options on save + * + * @param array $new_instance The new options + * @param array $old_instance The previous options + * + * @return array + */ + public function update( $new_instance, $old_instance ) { + // processes widget options to be saved + $instance = []; + + $fbr_opts = get_option( 'fbr_opts' ); + extract( $fbr_opts ); + + $fbr_opts['fbr_ratings'] = array(); + + $fb = new Facebook\Facebook([ + 'app_id' => $fbr_app_id, + 'app_secret' => $fbr_app_secret, + 'default_graph_version' => 'v2.2', + ]); + + try { + // Get the \Facebook\GraphNodes\GraphUser object for the current user. + // If you provided a 'default_access_token', the '{access-token}' is optional. + $response = $fb->get('/'. $fbr_page_id .'/ratings?limit=15&fields=reviewer,has_rating,has_review,review_text,rating,created_time', $fbr_page_access_token); + } catch(\Facebook\Exceptions\FacebookResponseException $e) { + // When Graph returns an error + echo 'Graph returned an error: ' . $e->getMessage(); + exit; + } catch(\Facebook\Exceptions\FacebookSDKException $e) { + // When validation fails or other local issues + echo 'Facebook SDK returned an error: ' . $e->getMessage(); + exit; + } + + $graphEdge = $response->getGraphEdge(); + + + foreach( $graphEdge as $graphNode ) { + if( $graphNode->getField( 'has_rating' ) && $graphNode->getField('has_review') ){ + array_push($fbr_opts['fbr_ratings'], $graphNode->asArray()); + } + } + + error_log(print_r($fbr_opts['fbr_ratings'], true)); + + update_option( 'fbr_opts', $fbr_opts ); + + return $instance; + } + + /** + * Outputs the content of the widget + * + * @param array $args + * @param array $instance + */ + public function widget( $args, $instance ) { + // outputs the content of the widget + extract( $args ); + // extract( $instance ); + + $fbr_opts = get_option( 'fbr_opts' ); + extract( $fbr_opts ); + + echo $before_widget; + + ?> + + + $i ) { + $html .= '' . jouvanceau_get_svg( array( 'icon' => 'star-plain', 'id' => '', 'class' => '' ) ) . ''; + } else { + $html .= '' . jouvanceau_get_svg( array( 'icon' => 'star-empty', 'id' => '', 'class' => '' ) ) . ''; + } + } + + echo $html; +} \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..8790fc8 --- /dev/null +++ b/index.php @@ -0,0 +1,46 @@ + $fbr_opts['fbr_app_id'], + 'app_secret' => $fbr_opts['fbr_app_secret'], + 'default_graph_version' => 'v2.2', + ]); + + $helper = $fb->getRedirectLoginHelper(); + + $permissions = ['email','public_profile','manage_pages','pages_show_list']; + $loginUrl = $helper->getLoginUrl(admin_url( 'admin-post.php?action=fbr_fb_login_cb' ), $permissions); + + update_option( 'fbr_opts', $fbr_opts ); + + wp_redirect( $loginUrl ); + exit; +} \ No newline at end of file diff --git a/process/select-page.php b/process/select-page.php new file mode 100644 index 0000000..89a4f67 --- /dev/null +++ b/process/select-page.php @@ -0,0 +1,21 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath.'\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100644 index 0000000..f27399a --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +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. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 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. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..7a91153 --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,9 @@ + $vendorDir . '/facebook/graph-sdk/src/Facebook/polyfills.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..b7fc012 --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/facebook/graph-sdk/src/Facebook'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 0000000..79ad801 --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,70 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require_once __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInit6a2183509b2beeda8cd3ef3eec1bae60::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + if ($useStaticLoader) { + $includeFiles = Composer\Autoload\ComposerStaticInit6a2183509b2beeda8cd3ef3eec1bae60::$files; + } else { + $includeFiles = require __DIR__ . '/autoload_files.php'; + } + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequire6a2183509b2beeda8cd3ef3eec1bae60($fileIdentifier, $file); + } + + return $loader; + } +} + +function composerRequire6a2183509b2beeda8cd3ef3eec1bae60($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + require $file; + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 0000000..fe25a02 --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,35 @@ + __DIR__ . '/..' . '/facebook/graph-sdk/src/Facebook/polyfills.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'F' => + array ( + 'Facebook\\' => 9, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Facebook\\' => + array ( + 0 => __DIR__ . '/..' . '/facebook/graph-sdk/src/Facebook', + ), + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit6a2183509b2beeda8cd3ef3eec1bae60::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit6a2183509b2beeda8cd3ef3eec1bae60::$prefixDirsPsr4; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 0000000..a25db7d --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,62 @@ +[ + { + "name": "facebook/graph-sdk", + "version": "5.6.2", + "version_normalized": "5.6.2.0", + "source": { + "type": "git", + "url": "https://github.com/facebook/php-graph-sdk.git", + "reference": "030f8c5b9b1a6c09e71719fd638b66ea4daa2f10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facebook/php-graph-sdk/zipball/030f8c5b9b1a6c09e71719fd638b66ea4daa2f10", + "reference": "030f8c5b9b1a6c09e71719fd638b66ea4daa2f10", + "shasum": "" + }, + "require": { + "php": "^5.4|^7.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "~5.0", + "mockery/mockery": "~0.8", + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "guzzlehttp/guzzle": "Allows for implementation of the Guzzle HTTP client", + "paragonie/random_compat": "Provides a better CSPRNG option in PHP 5" + }, + "time": "2018-02-14T23:24:51+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Facebook\\": "src/Facebook/" + }, + "files": [ + "src/Facebook/polyfills.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Facebook Platform" + ], + "authors": [ + { + "name": "Facebook", + "homepage": "https://github.com/facebook/php-graph-sdk/contributors" + } + ], + "description": "Facebook SDK for PHP", + "homepage": "https://github.com/facebook/php-graph-sdk", + "keywords": [ + "facebook", + "sdk" + ] + } +] diff --git a/vendor/facebook/graph-sdk/CODE_OF_CONDUCT.md b/vendor/facebook/graph-sdk/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..0a45f9b --- /dev/null +++ b/vendor/facebook/graph-sdk/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# Code of Conduct + +Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please [read the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated. diff --git a/vendor/facebook/graph-sdk/LICENSE b/vendor/facebook/graph-sdk/LICENSE new file mode 100644 index 0000000..8b93109 --- /dev/null +++ b/vendor/facebook/graph-sdk/LICENSE @@ -0,0 +1,19 @@ +Copyright 2017 Facebook, Inc. + +You are hereby granted a non-exclusive, worldwide, royalty-free license to +use, copy, modify, and distribute this software in source code or binary +form for use in connection with the web services and APIs provided by +Facebook. + +As with any software that integrates with the Facebook platform, your use +of this software is subject to the Facebook Developer Principles and +Policies [http://developers.facebook.com/policy/]. This copyright notice +shall be included in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 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. diff --git a/vendor/facebook/graph-sdk/composer.json b/vendor/facebook/graph-sdk/composer.json new file mode 100644 index 0000000..9d54abc --- /dev/null +++ b/vendor/facebook/graph-sdk/composer.json @@ -0,0 +1,42 @@ +{ + "name": "facebook/graph-sdk", + "description": "Facebook SDK for PHP", + "keywords": ["facebook", "sdk"], + "type": "library", + "homepage": "https://github.com/facebook/php-graph-sdk", + "license": "Facebook Platform", + "authors": [ + { + "name": "Facebook", + "homepage": "https://github.com/facebook/php-graph-sdk/contributors" + } + ], + "require": { + "php": "^5.4|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "mockery/mockery": "~0.8", + "guzzlehttp/guzzle": "~5.0" + }, + "suggest": { + "paragonie/random_compat": "Provides a better CSPRNG option in PHP 5", + "guzzlehttp/guzzle": "Allows for implementation of the Guzzle HTTP client" + }, + "autoload": { + "psr-4": { + "Facebook\\": "src/Facebook/" + }, + "files": ["src/Facebook/polyfills.php"] + }, + "autoload-dev": { + "psr-4": { + "Facebook\\Tests\\": "tests/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + } +} diff --git a/vendor/facebook/graph-sdk/phpcs.xml.dist b/vendor/facebook/graph-sdk/phpcs.xml.dist new file mode 100644 index 0000000..96c56f8 --- /dev/null +++ b/vendor/facebook/graph-sdk/phpcs.xml.dist @@ -0,0 +1,7 @@ + + + src/ + tests/ + + + diff --git a/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessToken.php b/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessToken.php new file mode 100644 index 0000000..5d70073 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessToken.php @@ -0,0 +1,160 @@ +value = $accessToken; + if ($expiresAt) { + $this->setExpiresAtFromTimeStamp($expiresAt); + } + } + + /** + * Generate an app secret proof to sign a request to Graph. + * + * @param string $appSecret The app secret. + * + * @return string + */ + public function getAppSecretProof($appSecret) + { + return hash_hmac('sha256', $this->value, $appSecret); + } + + /** + * Getter for expiresAt. + * + * @return \DateTime|null + */ + public function getExpiresAt() + { + return $this->expiresAt; + } + + /** + * Determines whether or not this is an app access token. + * + * @return bool + */ + public function isAppAccessToken() + { + return strpos($this->value, '|') !== false; + } + + /** + * Determines whether or not this is a long-lived token. + * + * @return bool + */ + public function isLongLived() + { + if ($this->expiresAt) { + return $this->expiresAt->getTimestamp() > time() + (60 * 60 * 2); + } + + if ($this->isAppAccessToken()) { + return true; + } + + return false; + } + + /** + * Checks the expiration of the access token. + * + * @return boolean|null + */ + public function isExpired() + { + if ($this->getExpiresAt() instanceof \DateTime) { + return $this->getExpiresAt()->getTimestamp() < time(); + } + + if ($this->isAppAccessToken()) { + return false; + } + + return null; + } + + /** + * Returns the access token as a string. + * + * @return string + */ + public function getValue() + { + return $this->value; + } + + /** + * Returns the access token as a string. + * + * @return string + */ + public function __toString() + { + return $this->getValue(); + } + + /** + * Setter for expires_at. + * + * @param int $timeStamp + */ + protected function setExpiresAtFromTimeStamp($timeStamp) + { + $dt = new \DateTime(); + $dt->setTimestamp($timeStamp); + $this->expiresAt = $dt; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessTokenMetadata.php b/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessTokenMetadata.php new file mode 100644 index 0000000..165433c --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessTokenMetadata.php @@ -0,0 +1,390 @@ +metadata = $metadata['data']; + + $this->castTimestampsToDateTime(); + } + + /** + * Returns a value from the metadata. + * + * @param string $field The property to retrieve. + * @param mixed $default The default to return if the property doesn't exist. + * + * @return mixed + */ + public function getField($field, $default = null) + { + if (isset($this->metadata[$field])) { + return $this->metadata[$field]; + } + + return $default; + } + + /** + * Returns a value from the metadata. + * + * @param string $field The property to retrieve. + * @param mixed $default The default to return if the property doesn't exist. + * + * @return mixed + * + * @deprecated 5.0.0 getProperty() has been renamed to getField() + * @todo v6: Remove this method + */ + public function getProperty($field, $default = null) + { + return $this->getField($field, $default); + } + + /** + * Returns a value from a child property in the metadata. + * + * @param string $parentField The parent property. + * @param string $field The property to retrieve. + * @param mixed $default The default to return if the property doesn't exist. + * + * @return mixed + */ + public function getChildProperty($parentField, $field, $default = null) + { + if (!isset($this->metadata[$parentField])) { + return $default; + } + + if (!isset($this->metadata[$parentField][$field])) { + return $default; + } + + return $this->metadata[$parentField][$field]; + } + + /** + * Returns a value from the error metadata. + * + * @param string $field The property to retrieve. + * @param mixed $default The default to return if the property doesn't exist. + * + * @return mixed + */ + public function getErrorProperty($field, $default = null) + { + return $this->getChildProperty('error', $field, $default); + } + + /** + * Returns a value from the "metadata" metadata. *Brain explodes* + * + * @param string $field The property to retrieve. + * @param mixed $default The default to return if the property doesn't exist. + * + * @return mixed + */ + public function getMetadataProperty($field, $default = null) + { + return $this->getChildProperty('metadata', $field, $default); + } + + /** + * The ID of the application this access token is for. + * + * @return string|null + */ + public function getAppId() + { + return $this->getField('app_id'); + } + + /** + * Name of the application this access token is for. + * + * @return string|null + */ + public function getApplication() + { + return $this->getField('application'); + } + + /** + * Any error that a request to the graph api + * would return due to the access token. + * + * @return bool|null + */ + public function isError() + { + return $this->getField('error') !== null; + } + + /** + * The error code for the error. + * + * @return int|null + */ + public function getErrorCode() + { + return $this->getErrorProperty('code'); + } + + /** + * The error message for the error. + * + * @return string|null + */ + public function getErrorMessage() + { + return $this->getErrorProperty('message'); + } + + /** + * The error subcode for the error. + * + * @return int|null + */ + public function getErrorSubcode() + { + return $this->getErrorProperty('subcode'); + } + + /** + * DateTime when this access token expires. + * + * @return \DateTime|null + */ + public function getExpiresAt() + { + return $this->getField('expires_at'); + } + + /** + * Whether the access token is still valid or not. + * + * @return boolean|null + */ + public function getIsValid() + { + return $this->getField('is_valid'); + } + + /** + * DateTime when this access token was issued. + * + * Note that the issued_at field is not returned + * for short-lived access tokens. + * + * @see https://developers.facebook.com/docs/facebook-login/access-tokens#debug + * + * @return \DateTime|null + */ + public function getIssuedAt() + { + return $this->getField('issued_at'); + } + + /** + * General metadata associated with the access token. + * Can contain data like 'sso', 'auth_type', 'auth_nonce'. + * + * @return array|null + */ + public function getMetadata() + { + return $this->getField('metadata'); + } + + /** + * The 'sso' child property from the 'metadata' parent property. + * + * @return string|null + */ + public function getSso() + { + return $this->getMetadataProperty('sso'); + } + + /** + * The 'auth_type' child property from the 'metadata' parent property. + * + * @return string|null + */ + public function getAuthType() + { + return $this->getMetadataProperty('auth_type'); + } + + /** + * The 'auth_nonce' child property from the 'metadata' parent property. + * + * @return string|null + */ + public function getAuthNonce() + { + return $this->getMetadataProperty('auth_nonce'); + } + + /** + * For impersonated access tokens, the ID of + * the page this token contains. + * + * @return string|null + */ + public function getProfileId() + { + return $this->getField('profile_id'); + } + + /** + * List of permissions that the user has granted for + * the app in this access token. + * + * @return array + */ + public function getScopes() + { + return $this->getField('scopes'); + } + + /** + * The ID of the user this access token is for. + * + * @return string|null + */ + public function getUserId() + { + return $this->getField('user_id'); + } + + /** + * Ensures the app ID from the access token + * metadata is what we expect. + * + * @param string $appId + * + * @throws FacebookSDKException + */ + public function validateAppId($appId) + { + if ($this->getAppId() !== $appId) { + throw new FacebookSDKException('Access token metadata contains unexpected app ID.', 401); + } + } + + /** + * Ensures the user ID from the access token + * metadata is what we expect. + * + * @param string $userId + * + * @throws FacebookSDKException + */ + public function validateUserId($userId) + { + if ($this->getUserId() !== $userId) { + throw new FacebookSDKException('Access token metadata contains unexpected user ID.', 401); + } + } + + /** + * Ensures the access token has not expired yet. + * + * @throws FacebookSDKException + */ + public function validateExpiration() + { + if (!$this->getExpiresAt() instanceof \DateTime) { + return; + } + + if ($this->getExpiresAt()->getTimestamp() < time()) { + throw new FacebookSDKException('Inspection of access token metadata shows that the access token has expired.', 401); + } + } + + /** + * Converts a unix timestamp into a DateTime entity. + * + * @param int $timestamp + * + * @return \DateTime + */ + private function convertTimestampToDateTime($timestamp) + { + $dt = new \DateTime(); + $dt->setTimestamp($timestamp); + + return $dt; + } + + /** + * Casts the unix timestamps as DateTime entities. + */ + private function castTimestampsToDateTime() + { + foreach (static::$dateProperties as $key) { + if (isset($this->metadata[$key]) && $this->metadata[$key] !== 0) { + $this->metadata[$key] = $this->convertTimestampToDateTime($this->metadata[$key]); + } + } + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Authentication/OAuth2Client.php b/vendor/facebook/graph-sdk/src/Facebook/Authentication/OAuth2Client.php new file mode 100644 index 0000000..94df9b7 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Authentication/OAuth2Client.php @@ -0,0 +1,292 @@ +app = $app; + $this->client = $client; + $this->graphVersion = $graphVersion ?: Facebook::DEFAULT_GRAPH_VERSION; + } + + /** + * Returns the last FacebookRequest that was sent. + * Useful for debugging and testing. + * + * @return FacebookRequest|null + */ + public function getLastRequest() + { + return $this->lastRequest; + } + + /** + * Get the metadata associated with the access token. + * + * @param AccessToken|string $accessToken The access token to debug. + * + * @return AccessTokenMetadata + */ + public function debugToken($accessToken) + { + $accessToken = $accessToken instanceof AccessToken ? $accessToken->getValue() : $accessToken; + $params = ['input_token' => $accessToken]; + + $this->lastRequest = new FacebookRequest( + $this->app, + $this->app->getAccessToken(), + 'GET', + '/debug_token', + $params, + null, + $this->graphVersion + ); + $response = $this->client->sendRequest($this->lastRequest); + $metadata = $response->getDecodedBody(); + + return new AccessTokenMetadata($metadata); + } + + /** + * Generates an authorization URL to begin the process of authenticating a user. + * + * @param string $redirectUrl The callback URL to redirect to. + * @param string $state The CSPRNG-generated CSRF value. + * @param array $scope An array of permissions to request. + * @param array $params An array of parameters to generate URL. + * @param string $separator The separator to use in http_build_query(). + * + * @return string + */ + public function getAuthorizationUrl($redirectUrl, $state, array $scope = [], array $params = [], $separator = '&') + { + $params += [ + 'client_id' => $this->app->getId(), + 'state' => $state, + 'response_type' => 'code', + 'sdk' => 'php-sdk-' . Facebook::VERSION, + 'redirect_uri' => $redirectUrl, + 'scope' => implode(',', $scope) + ]; + + return static::BASE_AUTHORIZATION_URL . '/' . $this->graphVersion . '/dialog/oauth?' . http_build_query($params, null, $separator); + } + + /** + * Get a valid access token from a code. + * + * @param string $code + * @param string $redirectUri + * + * @return AccessToken + * + * @throws FacebookSDKException + */ + public function getAccessTokenFromCode($code, $redirectUri = '') + { + $params = [ + 'code' => $code, + 'redirect_uri' => $redirectUri, + ]; + + return $this->requestAnAccessToken($params); + } + + /** + * Exchanges a short-lived access token with a long-lived access token. + * + * @param AccessToken|string $accessToken + * + * @return AccessToken + * + * @throws FacebookSDKException + */ + public function getLongLivedAccessToken($accessToken) + { + $accessToken = $accessToken instanceof AccessToken ? $accessToken->getValue() : $accessToken; + $params = [ + 'grant_type' => 'fb_exchange_token', + 'fb_exchange_token' => $accessToken, + ]; + + return $this->requestAnAccessToken($params); + } + + /** + * Get a valid code from an access token. + * + * @param AccessToken|string $accessToken + * @param string $redirectUri + * + * @return AccessToken + * + * @throws FacebookSDKException + */ + public function getCodeFromLongLivedAccessToken($accessToken, $redirectUri = '') + { + $params = [ + 'redirect_uri' => $redirectUri, + ]; + + $response = $this->sendRequestWithClientParams('/oauth/client_code', $params, $accessToken); + $data = $response->getDecodedBody(); + + if (!isset($data['code'])) { + throw new FacebookSDKException('Code was not returned from Graph.', 401); + } + + return $data['code']; + } + + /** + * Send a request to the OAuth endpoint. + * + * @param array $params + * + * @return AccessToken + * + * @throws FacebookSDKException + */ + protected function requestAnAccessToken(array $params) + { + $response = $this->sendRequestWithClientParams('/oauth/access_token', $params); + $data = $response->getDecodedBody(); + + if (!isset($data['access_token'])) { + throw new FacebookSDKException('Access token was not returned from Graph.', 401); + } + + // Graph returns two different key names for expiration time + // on the same endpoint. Doh! :/ + $expiresAt = 0; + if (isset($data['expires'])) { + // For exchanging a short lived token with a long lived token. + // The expiration time in seconds will be returned as "expires". + $expiresAt = time() + $data['expires']; + } elseif (isset($data['expires_in'])) { + // For exchanging a code for a short lived access token. + // The expiration time in seconds will be returned as "expires_in". + // See: https://developers.facebook.com/docs/facebook-login/access-tokens#long-via-code + $expiresAt = time() + $data['expires_in']; + } + + return new AccessToken($data['access_token'], $expiresAt); + } + + /** + * Send a request to Graph with an app access token. + * + * @param string $endpoint + * @param array $params + * @param AccessToken|string|null $accessToken + * + * @return FacebookResponse + * + * @throws FacebookResponseException + */ + protected function sendRequestWithClientParams($endpoint, array $params, $accessToken = null) + { + $params += $this->getClientParams(); + + $accessToken = $accessToken ?: $this->app->getAccessToken(); + + $this->lastRequest = new FacebookRequest( + $this->app, + $accessToken, + 'GET', + $endpoint, + $params, + null, + $this->graphVersion + ); + + return $this->client->sendRequest($this->lastRequest); + } + + /** + * Returns the client_* params for OAuth requests. + * + * @return array + */ + protected function getClientParams() + { + return [ + 'client_id' => $this->app->getId(), + 'client_secret' => $this->app->getSecret(), + ]; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookAuthenticationException.php b/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookAuthenticationException.php new file mode 100644 index 0000000..c5e45fa --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookAuthenticationException.php @@ -0,0 +1,33 @@ +response = $response; + $this->responseData = $response->getDecodedBody(); + + $errorMessage = $this->get('message', 'Unknown error from Graph.'); + $errorCode = $this->get('code', -1); + + parent::__construct($errorMessage, $errorCode, $previousException); + } + + /** + * A factory for creating the appropriate exception based on the response from Graph. + * + * @param FacebookResponse $response The response that threw the exception. + * + * @return FacebookResponseException + */ + public static function create(FacebookResponse $response) + { + $data = $response->getDecodedBody(); + + if (!isset($data['error']['code']) && isset($data['code'])) { + $data = ['error' => $data]; + } + + $code = isset($data['error']['code']) ? $data['error']['code'] : null; + $message = isset($data['error']['message']) ? $data['error']['message'] : 'Unknown error from Graph.'; + + if (isset($data['error']['error_subcode'])) { + switch ($data['error']['error_subcode']) { + // Other authentication issues + case 458: + case 459: + case 460: + case 463: + case 464: + case 467: + return new static($response, new FacebookAuthenticationException($message, $code)); + // Video upload resumable error + case 1363030: + case 1363019: + case 1363037: + case 1363033: + case 1363021: + case 1363041: + return new static($response, new FacebookResumableUploadException($message, $code)); + } + } + + switch ($code) { + // Login status or token expired, revoked, or invalid + case 100: + case 102: + case 190: + return new static($response, new FacebookAuthenticationException($message, $code)); + + // Server issue, possible downtime + case 1: + case 2: + return new static($response, new FacebookServerException($message, $code)); + + // API Throttling + case 4: + case 17: + case 32: + case 341: + case 613: + return new static($response, new FacebookThrottleException($message, $code)); + + // Duplicate Post + case 506: + return new static($response, new FacebookClientException($message, $code)); + } + + // Missing Permissions + if ($code == 10 || ($code >= 200 && $code <= 299)) { + return new static($response, new FacebookAuthorizationException($message, $code)); + } + + // OAuth authentication error + if (isset($data['error']['type']) && $data['error']['type'] === 'OAuthException') { + return new static($response, new FacebookAuthenticationException($message, $code)); + } + + // All others + return new static($response, new FacebookOtherException($message, $code)); + } + + /** + * Checks isset and returns that or a default value. + * + * @param string $key + * @param mixed $default + * + * @return mixed + */ + private function get($key, $default = null) + { + if (isset($this->responseData['error'][$key])) { + return $this->responseData['error'][$key]; + } + + return $default; + } + + /** + * Returns the HTTP status code + * + * @return int + */ + public function getHttpStatusCode() + { + return $this->response->getHttpStatusCode(); + } + + /** + * Returns the sub-error code + * + * @return int + */ + public function getSubErrorCode() + { + return $this->get('error_subcode', -1); + } + + /** + * Returns the error type + * + * @return string + */ + public function getErrorType() + { + return $this->get('type', ''); + } + + /** + * Returns the raw response used to create the exception. + * + * @return string + */ + public function getRawResponse() + { + return $this->response->getBody(); + } + + /** + * Returns the decoded response used to create the exception. + * + * @return array + */ + public function getResponseData() + { + return $this->responseData; + } + + /** + * Returns the response entity used to create the exception. + * + * @return FacebookResponse + */ + public function getResponse() + { + return $this->response; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookResumableUploadException.php b/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookResumableUploadException.php new file mode 100644 index 0000000..6f47066 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookResumableUploadException.php @@ -0,0 +1,33 @@ + getenv(static::APP_ID_ENV_NAME), + 'app_secret' => getenv(static::APP_SECRET_ENV_NAME), + 'default_graph_version' => static::DEFAULT_GRAPH_VERSION, + 'enable_beta_mode' => false, + 'http_client_handler' => null, + 'persistent_data_handler' => null, + 'pseudo_random_string_generator' => null, + 'url_detection_handler' => null, + ], $config); + + if (!$config['app_id']) { + throw new FacebookSDKException('Required "app_id" key not supplied in config and could not find fallback environment variable "' . static::APP_ID_ENV_NAME . '"'); + } + if (!$config['app_secret']) { + throw new FacebookSDKException('Required "app_secret" key not supplied in config and could not find fallback environment variable "' . static::APP_SECRET_ENV_NAME . '"'); + } + + $this->app = new FacebookApp($config['app_id'], $config['app_secret']); + $this->client = new FacebookClient( + HttpClientsFactory::createHttpClient($config['http_client_handler']), + $config['enable_beta_mode'] + ); + $this->pseudoRandomStringGenerator = PseudoRandomStringGeneratorFactory::createPseudoRandomStringGenerator( + $config['pseudo_random_string_generator'] + ); + $this->setUrlDetectionHandler($config['url_detection_handler'] ?: new FacebookUrlDetectionHandler()); + $this->persistentDataHandler = PersistentDataFactory::createPersistentDataHandler( + $config['persistent_data_handler'] + ); + + if (isset($config['default_access_token'])) { + $this->setDefaultAccessToken($config['default_access_token']); + } + + // @todo v6: Throw an InvalidArgumentException if "default_graph_version" is not set + $this->defaultGraphVersion = $config['default_graph_version']; + } + + /** + * Returns the FacebookApp entity. + * + * @return FacebookApp + */ + public function getApp() + { + return $this->app; + } + + /** + * Returns the FacebookClient service. + * + * @return FacebookClient + */ + public function getClient() + { + return $this->client; + } + + /** + * Returns the OAuth 2.0 client service. + * + * @return OAuth2Client + */ + public function getOAuth2Client() + { + if (!$this->oAuth2Client instanceof OAuth2Client) { + $app = $this->getApp(); + $client = $this->getClient(); + $this->oAuth2Client = new OAuth2Client($app, $client, $this->defaultGraphVersion); + } + + return $this->oAuth2Client; + } + + /** + * Returns the last response returned from Graph. + * + * @return FacebookResponse|FacebookBatchResponse|null + */ + public function getLastResponse() + { + return $this->lastResponse; + } + + /** + * Returns the URL detection handler. + * + * @return UrlDetectionInterface + */ + public function getUrlDetectionHandler() + { + return $this->urlDetectionHandler; + } + + /** + * Changes the URL detection handler. + * + * @param UrlDetectionInterface $urlDetectionHandler + */ + private function setUrlDetectionHandler(UrlDetectionInterface $urlDetectionHandler) + { + $this->urlDetectionHandler = $urlDetectionHandler; + } + + /** + * Returns the default AccessToken entity. + * + * @return AccessToken|null + */ + public function getDefaultAccessToken() + { + return $this->defaultAccessToken; + } + + /** + * Sets the default access token to use with requests. + * + * @param AccessToken|string $accessToken The access token to save. + * + * @throws \InvalidArgumentException + */ + public function setDefaultAccessToken($accessToken) + { + if (is_string($accessToken)) { + $this->defaultAccessToken = new AccessToken($accessToken); + + return; + } + + if ($accessToken instanceof AccessToken) { + $this->defaultAccessToken = $accessToken; + + return; + } + + throw new \InvalidArgumentException('The default access token must be of type "string" or Facebook\AccessToken'); + } + + /** + * Returns the default Graph version. + * + * @return string + */ + public function getDefaultGraphVersion() + { + return $this->defaultGraphVersion; + } + + /** + * Returns the redirect login helper. + * + * @return FacebookRedirectLoginHelper + */ + public function getRedirectLoginHelper() + { + return new FacebookRedirectLoginHelper( + $this->getOAuth2Client(), + $this->persistentDataHandler, + $this->urlDetectionHandler, + $this->pseudoRandomStringGenerator + ); + } + + /** + * Returns the JavaScript helper. + * + * @return FacebookJavaScriptHelper + */ + public function getJavaScriptHelper() + { + return new FacebookJavaScriptHelper($this->app, $this->client, $this->defaultGraphVersion); + } + + /** + * Returns the canvas helper. + * + * @return FacebookCanvasHelper + */ + public function getCanvasHelper() + { + return new FacebookCanvasHelper($this->app, $this->client, $this->defaultGraphVersion); + } + + /** + * Returns the page tab helper. + * + * @return FacebookPageTabHelper + */ + public function getPageTabHelper() + { + return new FacebookPageTabHelper($this->app, $this->client, $this->defaultGraphVersion); + } + + /** + * Sends a GET request to Graph and returns the result. + * + * @param string $endpoint + * @param AccessToken|string|null $accessToken + * @param string|null $eTag + * @param string|null $graphVersion + * + * @return FacebookResponse + * + * @throws FacebookSDKException + */ + public function get($endpoint, $accessToken = null, $eTag = null, $graphVersion = null) + { + return $this->sendRequest( + 'GET', + $endpoint, + $params = [], + $accessToken, + $eTag, + $graphVersion + ); + } + + /** + * Sends a POST request to Graph and returns the result. + * + * @param string $endpoint + * @param array $params + * @param AccessToken|string|null $accessToken + * @param string|null $eTag + * @param string|null $graphVersion + * + * @return FacebookResponse + * + * @throws FacebookSDKException + */ + public function post($endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null) + { + return $this->sendRequest( + 'POST', + $endpoint, + $params, + $accessToken, + $eTag, + $graphVersion + ); + } + + /** + * Sends a DELETE request to Graph and returns the result. + * + * @param string $endpoint + * @param array $params + * @param AccessToken|string|null $accessToken + * @param string|null $eTag + * @param string|null $graphVersion + * + * @return FacebookResponse + * + * @throws FacebookSDKException + */ + public function delete($endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null) + { + return $this->sendRequest( + 'DELETE', + $endpoint, + $params, + $accessToken, + $eTag, + $graphVersion + ); + } + + /** + * Sends a request to Graph for the next page of results. + * + * @param GraphEdge $graphEdge The GraphEdge to paginate over. + * + * @return GraphEdge|null + * + * @throws FacebookSDKException + */ + public function next(GraphEdge $graphEdge) + { + return $this->getPaginationResults($graphEdge, 'next'); + } + + /** + * Sends a request to Graph for the previous page of results. + * + * @param GraphEdge $graphEdge The GraphEdge to paginate over. + * + * @return GraphEdge|null + * + * @throws FacebookSDKException + */ + public function previous(GraphEdge $graphEdge) + { + return $this->getPaginationResults($graphEdge, 'previous'); + } + + /** + * Sends a request to Graph for the next page of results. + * + * @param GraphEdge $graphEdge The GraphEdge to paginate over. + * @param string $direction The direction of the pagination: next|previous. + * + * @return GraphEdge|null + * + * @throws FacebookSDKException + */ + public function getPaginationResults(GraphEdge $graphEdge, $direction) + { + $paginationRequest = $graphEdge->getPaginationRequest($direction); + if (!$paginationRequest) { + return null; + } + + $this->lastResponse = $this->client->sendRequest($paginationRequest); + + // Keep the same GraphNode subclass + $subClassName = $graphEdge->getSubClassName(); + $graphEdge = $this->lastResponse->getGraphEdge($subClassName, false); + + return count($graphEdge) > 0 ? $graphEdge : null; + } + + /** + * Sends a request to Graph and returns the result. + * + * @param string $method + * @param string $endpoint + * @param array $params + * @param AccessToken|string|null $accessToken + * @param string|null $eTag + * @param string|null $graphVersion + * + * @return FacebookResponse + * + * @throws FacebookSDKException + */ + public function sendRequest($method, $endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null) + { + $accessToken = $accessToken ?: $this->defaultAccessToken; + $graphVersion = $graphVersion ?: $this->defaultGraphVersion; + $request = $this->request($method, $endpoint, $params, $accessToken, $eTag, $graphVersion); + + return $this->lastResponse = $this->client->sendRequest($request); + } + + /** + * Sends a batched request to Graph and returns the result. + * + * @param array $requests + * @param AccessToken|string|null $accessToken + * @param string|null $graphVersion + * + * @return FacebookBatchResponse + * + * @throws FacebookSDKException + */ + public function sendBatchRequest(array $requests, $accessToken = null, $graphVersion = null) + { + $accessToken = $accessToken ?: $this->defaultAccessToken; + $graphVersion = $graphVersion ?: $this->defaultGraphVersion; + $batchRequest = new FacebookBatchRequest( + $this->app, + $requests, + $accessToken, + $graphVersion + ); + + return $this->lastResponse = $this->client->sendBatchRequest($batchRequest); + } + + /** + * Instantiates an empty FacebookBatchRequest entity. + * + * @param AccessToken|string|null $accessToken The top-level access token. Requests with no access token + * will fallback to this. + * @param string|null $graphVersion The Graph API version to use. + * @return FacebookBatchRequest + */ + public function newBatchRequest($accessToken = null, $graphVersion = null) + { + $accessToken = $accessToken ?: $this->defaultAccessToken; + $graphVersion = $graphVersion ?: $this->defaultGraphVersion; + + return new FacebookBatchRequest( + $this->app, + [], + $accessToken, + $graphVersion + ); + } + + /** + * Instantiates a new FacebookRequest entity. + * + * @param string $method + * @param string $endpoint + * @param array $params + * @param AccessToken|string|null $accessToken + * @param string|null $eTag + * @param string|null $graphVersion + * + * @return FacebookRequest + * + * @throws FacebookSDKException + */ + public function request($method, $endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null) + { + $accessToken = $accessToken ?: $this->defaultAccessToken; + $graphVersion = $graphVersion ?: $this->defaultGraphVersion; + + return new FacebookRequest( + $this->app, + $accessToken, + $method, + $endpoint, + $params, + $eTag, + $graphVersion + ); + } + + /** + * Factory to create FacebookFile's. + * + * @param string $pathToFile + * + * @return FacebookFile + * + * @throws FacebookSDKException + */ + public function fileToUpload($pathToFile) + { + return new FacebookFile($pathToFile); + } + + /** + * Factory to create FacebookVideo's. + * + * @param string $pathToFile + * + * @return FacebookVideo + * + * @throws FacebookSDKException + */ + public function videoToUpload($pathToFile) + { + return new FacebookVideo($pathToFile); + } + + /** + * Upload a video in chunks. + * + * @param int $target The id of the target node before the /videos edge. + * @param string $pathToFile The full path to the file. + * @param array $metadata The metadata associated with the video file. + * @param string|null $accessToken The access token. + * @param int $maxTransferTries The max times to retry a failed upload chunk. + * @param string|null $graphVersion The Graph API version to use. + * + * @return array + * + * @throws FacebookSDKException + */ + public function uploadVideo($target, $pathToFile, $metadata = [], $accessToken = null, $maxTransferTries = 5, $graphVersion = null) + { + $accessToken = $accessToken ?: $this->defaultAccessToken; + $graphVersion = $graphVersion ?: $this->defaultGraphVersion; + + $uploader = new FacebookResumableUploader($this->app, $this->client, $accessToken, $graphVersion); + $endpoint = '/'.$target.'/videos'; + $file = $this->videoToUpload($pathToFile); + $chunk = $uploader->start($endpoint, $file); + + do { + $chunk = $this->maxTriesTransfer($uploader, $endpoint, $chunk, $maxTransferTries); + } while (!$chunk->isLastChunk()); + + return [ + 'video_id' => $chunk->getVideoId(), + 'success' => $uploader->finish($endpoint, $chunk->getUploadSessionId(), $metadata), + ]; + } + + /** + * Attempts to upload a chunk of a file in $retryCountdown tries. + * + * @param FacebookResumableUploader $uploader + * @param string $endpoint + * @param FacebookTransferChunk $chunk + * @param int $retryCountdown + * + * @return FacebookTransferChunk + * + * @throws FacebookSDKException + */ + private function maxTriesTransfer(FacebookResumableUploader $uploader, $endpoint, FacebookTransferChunk $chunk, $retryCountdown) + { + $newChunk = $uploader->transfer($endpoint, $chunk, $retryCountdown < 1); + + if ($newChunk !== $chunk) { + return $newChunk; + } + + $retryCountdown--; + + // If transfer() returned the same chunk entity, the transfer failed but is resumable. + return $this->maxTriesTransfer($uploader, $endpoint, $chunk, $retryCountdown); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/FacebookApp.php b/vendor/facebook/graph-sdk/src/Facebook/FacebookApp.php new file mode 100644 index 0000000..804c9bb --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/FacebookApp.php @@ -0,0 +1,110 @@ +id = (string) $id; + $this->secret = $secret; + } + + /** + * Returns the app ID. + * + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * Returns the app secret. + * + * @return string + */ + public function getSecret() + { + return $this->secret; + } + + /** + * Returns an app access token. + * + * @return AccessToken + */ + public function getAccessToken() + { + return new AccessToken($this->id . '|' . $this->secret); + } + + /** + * Serializes the FacebookApp entity as a string. + * + * @return string + */ + public function serialize() + { + return implode('|', [$this->id, $this->secret]); + } + + /** + * Unserializes a string as a FacebookApp entity. + * + * @param string $serialized + */ + public function unserialize($serialized) + { + list($id, $secret) = explode('|', $serialized); + + $this->__construct($id, $secret); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchRequest.php b/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchRequest.php new file mode 100644 index 0000000..3d5d5d5 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchRequest.php @@ -0,0 +1,322 @@ +add($requests); + } + + /** + * Adds a new request to the array. + * + * @param FacebookRequest|array $request + * @param string|null|array $options Array of batch request options e.g. 'name', 'omit_response_on_success'. + * If a string is given, it is the value of the 'name' option. + * + * @return FacebookBatchRequest + * + * @throws \InvalidArgumentException + */ + public function add($request, $options = null) + { + if (is_array($request)) { + foreach ($request as $key => $req) { + $this->add($req, $key); + } + + return $this; + } + + if (!$request instanceof FacebookRequest) { + throw new \InvalidArgumentException('Argument for add() must be of type array or FacebookRequest.'); + } + + if (null === $options) { + $options = []; + } elseif (!is_array($options)) { + $options = ['name' => $options]; + } + + $this->addFallbackDefaults($request); + + // File uploads + $attachedFiles = $this->extractFileAttachments($request); + + $name = isset($options['name']) ? $options['name'] : null; + + unset($options['name']); + + $requestToAdd = [ + 'name' => $name, + 'request' => $request, + 'options' => $options, + 'attached_files' => $attachedFiles, + ]; + + $this->requests[] = $requestToAdd; + + return $this; + } + + /** + * Ensures that the FacebookApp and access token fall back when missing. + * + * @param FacebookRequest $request + * + * @throws FacebookSDKException + */ + public function addFallbackDefaults(FacebookRequest $request) + { + if (!$request->getApp()) { + $app = $this->getApp(); + if (!$app) { + throw new FacebookSDKException('Missing FacebookApp on FacebookRequest and no fallback detected on FacebookBatchRequest.'); + } + $request->setApp($app); + } + + if (!$request->getAccessToken()) { + $accessToken = $this->getAccessToken(); + if (!$accessToken) { + throw new FacebookSDKException('Missing access token on FacebookRequest and no fallback detected on FacebookBatchRequest.'); + } + $request->setAccessToken($accessToken); + } + } + + /** + * Extracts the files from a request. + * + * @param FacebookRequest $request + * + * @return string|null + * + * @throws FacebookSDKException + */ + public function extractFileAttachments(FacebookRequest $request) + { + if (!$request->containsFileUploads()) { + return null; + } + + $files = $request->getFiles(); + $fileNames = []; + foreach ($files as $file) { + $fileName = uniqid(); + $this->addFile($fileName, $file); + $fileNames[] = $fileName; + } + + $request->resetFiles(); + + // @TODO Does Graph support multiple uploads on one endpoint? + return implode(',', $fileNames); + } + + /** + * Return the FacebookRequest entities. + * + * @return array + */ + public function getRequests() + { + return $this->requests; + } + + /** + * Prepares the requests to be sent as a batch request. + */ + public function prepareRequestsForBatch() + { + $this->validateBatchRequestCount(); + + $params = [ + 'batch' => $this->convertRequestsToJson(), + 'include_headers' => true, + ]; + $this->setParams($params); + } + + /** + * Converts the requests into a JSON(P) string. + * + * @return string + */ + public function convertRequestsToJson() + { + $requests = []; + foreach ($this->requests as $request) { + $options = []; + + if (null !== $request['name']) { + $options['name'] = $request['name']; + } + + $options += $request['options']; + + $requests[] = $this->requestEntityToBatchArray($request['request'], $options, $request['attached_files']); + } + + return json_encode($requests); + } + + /** + * Validate the request count before sending them as a batch. + * + * @throws FacebookSDKException + */ + public function validateBatchRequestCount() + { + $batchCount = count($this->requests); + if ($batchCount === 0) { + throw new FacebookSDKException('There are no batch requests to send.'); + } elseif ($batchCount > 50) { + // Per: https://developers.facebook.com/docs/graph-api/making-multiple-requests#limits + throw new FacebookSDKException('You cannot send more than 50 batch requests at a time.'); + } + } + + /** + * Converts a Request entity into an array that is batch-friendly. + * + * @param FacebookRequest $request The request entity to convert. + * @param string|null|array $options Array of batch request options e.g. 'name', 'omit_response_on_success'. + * If a string is given, it is the value of the 'name' option. + * @param string|null $attachedFiles Names of files associated with the request. + * + * @return array + */ + public function requestEntityToBatchArray(FacebookRequest $request, $options = null, $attachedFiles = null) + { + + if (null === $options) { + $options = []; + } elseif (!is_array($options)) { + $options = ['name' => $options]; + } + + $compiledHeaders = []; + $headers = $request->getHeaders(); + foreach ($headers as $name => $value) { + $compiledHeaders[] = $name . ': ' . $value; + } + + $batch = [ + 'headers' => $compiledHeaders, + 'method' => $request->getMethod(), + 'relative_url' => $request->getUrl(), + ]; + + // Since file uploads are moved to the root request of a batch request, + // the child requests will always be URL-encoded. + $body = $request->getUrlEncodedBody()->getBody(); + if ($body) { + $batch['body'] = $body; + } + + $batch += $options; + + if (null !== $attachedFiles) { + $batch['attached_files'] = $attachedFiles; + } + + return $batch; + } + + /** + * Get an iterator for the items. + * + * @return ArrayIterator + */ + public function getIterator() + { + return new ArrayIterator($this->requests); + } + + /** + * @inheritdoc + */ + public function offsetSet($offset, $value) + { + $this->add($value, $offset); + } + + /** + * @inheritdoc + */ + public function offsetExists($offset) + { + return isset($this->requests[$offset]); + } + + /** + * @inheritdoc + */ + public function offsetUnset($offset) + { + unset($this->requests[$offset]); + } + + /** + * @inheritdoc + */ + public function offsetGet($offset) + { + return isset($this->requests[$offset]) ? $this->requests[$offset] : null; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchResponse.php b/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchResponse.php new file mode 100644 index 0000000..8e1464c --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchResponse.php @@ -0,0 +1,174 @@ +batchRequest = $batchRequest; + + $request = $response->getRequest(); + $body = $response->getBody(); + $httpStatusCode = $response->getHttpStatusCode(); + $headers = $response->getHeaders(); + parent::__construct($request, $body, $httpStatusCode, $headers); + + $responses = $response->getDecodedBody(); + $this->setResponses($responses); + } + + /** + * Returns an array of FacebookResponse entities. + * + * @return array + */ + public function getResponses() + { + return $this->responses; + } + + /** + * The main batch response will be an array of requests so + * we need to iterate over all the responses. + * + * @param array $responses + */ + public function setResponses(array $responses) + { + $this->responses = []; + + foreach ($responses as $key => $graphResponse) { + $this->addResponse($key, $graphResponse); + } + } + + /** + * Add a response to the list. + * + * @param int $key + * @param array|null $response + */ + public function addResponse($key, $response) + { + $originalRequestName = isset($this->batchRequest[$key]['name']) ? $this->batchRequest[$key]['name'] : $key; + $originalRequest = isset($this->batchRequest[$key]['request']) ? $this->batchRequest[$key]['request'] : null; + + $httpResponseBody = isset($response['body']) ? $response['body'] : null; + $httpResponseCode = isset($response['code']) ? $response['code'] : null; + // @TODO With PHP 5.5 support, this becomes array_column($response['headers'], 'value', 'name') + $httpResponseHeaders = isset($response['headers']) ? $this->normalizeBatchHeaders($response['headers']) : []; + + $this->responses[$originalRequestName] = new FacebookResponse( + $originalRequest, + $httpResponseBody, + $httpResponseCode, + $httpResponseHeaders + ); + } + + /** + * @inheritdoc + */ + public function getIterator() + { + return new ArrayIterator($this->responses); + } + + /** + * @inheritdoc + */ + public function offsetSet($offset, $value) + { + $this->addResponse($offset, $value); + } + + /** + * @inheritdoc + */ + public function offsetExists($offset) + { + return isset($this->responses[$offset]); + } + + /** + * @inheritdoc + */ + public function offsetUnset($offset) + { + unset($this->responses[$offset]); + } + + /** + * @inheritdoc + */ + public function offsetGet($offset) + { + return isset($this->responses[$offset]) ? $this->responses[$offset] : null; + } + + /** + * Converts the batch header array into a standard format. + * @TODO replace with array_column() when PHP 5.5 is supported. + * + * @param array $batchHeaders + * + * @return array + */ + private function normalizeBatchHeaders(array $batchHeaders) + { + $headers = []; + + foreach ($batchHeaders as $header) { + $headers[$header['name']] = $header['value']; + } + + return $headers; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/FacebookClient.php b/vendor/facebook/graph-sdk/src/Facebook/FacebookClient.php new file mode 100644 index 0000000..dbf7592 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/FacebookClient.php @@ -0,0 +1,250 @@ +httpClientHandler = $httpClientHandler ?: $this->detectHttpClientHandler(); + $this->enableBetaMode = $enableBeta; + } + + /** + * Sets the HTTP client handler. + * + * @param FacebookHttpClientInterface $httpClientHandler + */ + public function setHttpClientHandler(FacebookHttpClientInterface $httpClientHandler) + { + $this->httpClientHandler = $httpClientHandler; + } + + /** + * Returns the HTTP client handler. + * + * @return FacebookHttpClientInterface + */ + public function getHttpClientHandler() + { + return $this->httpClientHandler; + } + + /** + * Detects which HTTP client handler to use. + * + * @return FacebookHttpClientInterface + */ + public function detectHttpClientHandler() + { + return extension_loaded('curl') ? new FacebookCurlHttpClient() : new FacebookStreamHttpClient(); + } + + /** + * Toggle beta mode. + * + * @param boolean $betaMode + */ + public function enableBetaMode($betaMode = true) + { + $this->enableBetaMode = $betaMode; + } + + /** + * Returns the base Graph URL. + * + * @param boolean $postToVideoUrl Post to the video API if videos are being uploaded. + * + * @return string + */ + public function getBaseGraphUrl($postToVideoUrl = false) + { + if ($postToVideoUrl) { + return $this->enableBetaMode ? static::BASE_GRAPH_VIDEO_URL_BETA : static::BASE_GRAPH_VIDEO_URL; + } + + return $this->enableBetaMode ? static::BASE_GRAPH_URL_BETA : static::BASE_GRAPH_URL; + } + + /** + * Prepares the request for sending to the client handler. + * + * @param FacebookRequest $request + * + * @return array + */ + public function prepareRequestMessage(FacebookRequest $request) + { + $postToVideoUrl = $request->containsVideoUploads(); + $url = $this->getBaseGraphUrl($postToVideoUrl) . $request->getUrl(); + + // If we're sending files they should be sent as multipart/form-data + if ($request->containsFileUploads()) { + $requestBody = $request->getMultipartBody(); + $request->setHeaders([ + 'Content-Type' => 'multipart/form-data; boundary=' . $requestBody->getBoundary(), + ]); + } else { + $requestBody = $request->getUrlEncodedBody(); + $request->setHeaders([ + 'Content-Type' => 'application/x-www-form-urlencoded', + ]); + } + + return [ + $url, + $request->getMethod(), + $request->getHeaders(), + $requestBody->getBody(), + ]; + } + + /** + * Makes the request to Graph and returns the result. + * + * @param FacebookRequest $request + * + * @return FacebookResponse + * + * @throws FacebookSDKException + */ + public function sendRequest(FacebookRequest $request) + { + if (get_class($request) === 'Facebook\FacebookRequest') { + $request->validateAccessToken(); + } + + list($url, $method, $headers, $body) = $this->prepareRequestMessage($request); + + // Since file uploads can take a while, we need to give more time for uploads + $timeOut = static::DEFAULT_REQUEST_TIMEOUT; + if ($request->containsFileUploads()) { + $timeOut = static::DEFAULT_FILE_UPLOAD_REQUEST_TIMEOUT; + } elseif ($request->containsVideoUploads()) { + $timeOut = static::DEFAULT_VIDEO_UPLOAD_REQUEST_TIMEOUT; + } + + // Should throw `FacebookSDKException` exception on HTTP client error. + // Don't catch to allow it to bubble up. + $rawResponse = $this->httpClientHandler->send($url, $method, $body, $headers, $timeOut); + + static::$requestCount++; + + $returnResponse = new FacebookResponse( + $request, + $rawResponse->getBody(), + $rawResponse->getHttpResponseCode(), + $rawResponse->getHeaders() + ); + + if ($returnResponse->isError()) { + throw $returnResponse->getThrownException(); + } + + return $returnResponse; + } + + /** + * Makes a batched request to Graph and returns the result. + * + * @param FacebookBatchRequest $request + * + * @return FacebookBatchResponse + * + * @throws FacebookSDKException + */ + public function sendBatchRequest(FacebookBatchRequest $request) + { + $request->prepareRequestsForBatch(); + $facebookResponse = $this->sendRequest($request); + + return new FacebookBatchResponse($request, $facebookResponse); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/FacebookRequest.php b/vendor/facebook/graph-sdk/src/Facebook/FacebookRequest.php new file mode 100644 index 0000000..2b10089 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/FacebookRequest.php @@ -0,0 +1,534 @@ +setApp($app); + $this->setAccessToken($accessToken); + $this->setMethod($method); + $this->setEndpoint($endpoint); + $this->setParams($params); + $this->setETag($eTag); + $this->graphVersion = $graphVersion ?: Facebook::DEFAULT_GRAPH_VERSION; + } + + /** + * Set the access token for this request. + * + * @param AccessToken|string|null + * + * @return FacebookRequest + */ + public function setAccessToken($accessToken) + { + $this->accessToken = $accessToken; + if ($accessToken instanceof AccessToken) { + $this->accessToken = $accessToken->getValue(); + } + + return $this; + } + + /** + * Sets the access token with one harvested from a URL or POST params. + * + * @param string $accessToken The access token. + * + * @return FacebookRequest + * + * @throws FacebookSDKException + */ + public function setAccessTokenFromParams($accessToken) + { + $existingAccessToken = $this->getAccessToken(); + if (!$existingAccessToken) { + $this->setAccessToken($accessToken); + } elseif ($accessToken !== $existingAccessToken) { + throw new FacebookSDKException('Access token mismatch. The access token provided in the FacebookRequest and the one provided in the URL or POST params do not match.'); + } + + return $this; + } + + /** + * Return the access token for this request. + * + * @return string|null + */ + public function getAccessToken() + { + return $this->accessToken; + } + + /** + * Return the access token for this request as an AccessToken entity. + * + * @return AccessToken|null + */ + public function getAccessTokenEntity() + { + return $this->accessToken ? new AccessToken($this->accessToken) : null; + } + + /** + * Set the FacebookApp entity used for this request. + * + * @param FacebookApp|null $app + */ + public function setApp(FacebookApp $app = null) + { + $this->app = $app; + } + + /** + * Return the FacebookApp entity used for this request. + * + * @return FacebookApp + */ + public function getApp() + { + return $this->app; + } + + /** + * Generate an app secret proof to sign this request. + * + * @return string|null + */ + public function getAppSecretProof() + { + if (!$accessTokenEntity = $this->getAccessTokenEntity()) { + return null; + } + + return $accessTokenEntity->getAppSecretProof($this->app->getSecret()); + } + + /** + * Validate that an access token exists for this request. + * + * @throws FacebookSDKException + */ + public function validateAccessToken() + { + $accessToken = $this->getAccessToken(); + if (!$accessToken) { + throw new FacebookSDKException('You must provide an access token.'); + } + } + + /** + * Set the HTTP method for this request. + * + * @param string + */ + public function setMethod($method) + { + $this->method = strtoupper($method); + } + + /** + * Return the HTTP method for this request. + * + * @return string + */ + public function getMethod() + { + return $this->method; + } + + /** + * Validate that the HTTP method is set. + * + * @throws FacebookSDKException + */ + public function validateMethod() + { + if (!$this->method) { + throw new FacebookSDKException('HTTP method not specified.'); + } + + if (!in_array($this->method, ['GET', 'POST', 'DELETE'])) { + throw new FacebookSDKException('Invalid HTTP method specified.'); + } + } + + /** + * Set the endpoint for this request. + * + * @param string + * + * @return FacebookRequest + * + * @throws FacebookSDKException + */ + public function setEndpoint($endpoint) + { + // Harvest the access token from the endpoint to keep things in sync + $params = FacebookUrlManipulator::getParamsAsArray($endpoint); + if (isset($params['access_token'])) { + $this->setAccessTokenFromParams($params['access_token']); + } + + // Clean the token & app secret proof from the endpoint. + $filterParams = ['access_token', 'appsecret_proof']; + $this->endpoint = FacebookUrlManipulator::removeParamsFromUrl($endpoint, $filterParams); + + return $this; + } + + /** + * Return the endpoint for this request. + * + * @return string + */ + public function getEndpoint() + { + // For batch requests, this will be empty + return $this->endpoint; + } + + /** + * Generate and return the headers for this request. + * + * @return array + */ + public function getHeaders() + { + $headers = static::getDefaultHeaders(); + + if ($this->eTag) { + $headers['If-None-Match'] = $this->eTag; + } + + return array_merge($this->headers, $headers); + } + + /** + * Set the headers for this request. + * + * @param array $headers + */ + public function setHeaders(array $headers) + { + $this->headers = array_merge($this->headers, $headers); + } + + /** + * Sets the eTag value. + * + * @param string $eTag + */ + public function setETag($eTag) + { + $this->eTag = $eTag; + } + + /** + * Set the params for this request. + * + * @param array $params + * + * @return FacebookRequest + * + * @throws FacebookSDKException + */ + public function setParams(array $params = []) + { + if (isset($params['access_token'])) { + $this->setAccessTokenFromParams($params['access_token']); + } + + // Don't let these buggers slip in. + unset($params['access_token'], $params['appsecret_proof']); + + // @TODO Refactor code above with this + //$params = $this->sanitizeAuthenticationParams($params); + $params = $this->sanitizeFileParams($params); + $this->dangerouslySetParams($params); + + return $this; + } + + /** + * Set the params for this request without filtering them first. + * + * @param array $params + * + * @return FacebookRequest + */ + public function dangerouslySetParams(array $params = []) + { + $this->params = array_merge($this->params, $params); + + return $this; + } + + /** + * Iterate over the params and pull out the file uploads. + * + * @param array $params + * + * @return array + */ + public function sanitizeFileParams(array $params) + { + foreach ($params as $key => $value) { + if ($value instanceof FacebookFile) { + $this->addFile($key, $value); + unset($params[$key]); + } + } + + return $params; + } + + /** + * Add a file to be uploaded. + * + * @param string $key + * @param FacebookFile $file + */ + public function addFile($key, FacebookFile $file) + { + $this->files[$key] = $file; + } + + /** + * Removes all the files from the upload queue. + */ + public function resetFiles() + { + $this->files = []; + } + + /** + * Get the list of files to be uploaded. + * + * @return array + */ + public function getFiles() + { + return $this->files; + } + + /** + * Let's us know if there is a file upload with this request. + * + * @return boolean + */ + public function containsFileUploads() + { + return !empty($this->files); + } + + /** + * Let's us know if there is a video upload with this request. + * + * @return boolean + */ + public function containsVideoUploads() + { + foreach ($this->files as $file) { + if ($file instanceof FacebookVideo) { + return true; + } + } + + return false; + } + + /** + * Returns the body of the request as multipart/form-data. + * + * @return RequestBodyMultipart + */ + public function getMultipartBody() + { + $params = $this->getPostParams(); + + return new RequestBodyMultipart($params, $this->files); + } + + /** + * Returns the body of the request as URL-encoded. + * + * @return RequestBodyUrlEncoded + */ + public function getUrlEncodedBody() + { + $params = $this->getPostParams(); + + return new RequestBodyUrlEncoded($params); + } + + /** + * Generate and return the params for this request. + * + * @return array + */ + public function getParams() + { + $params = $this->params; + + $accessToken = $this->getAccessToken(); + if ($accessToken) { + $params['access_token'] = $accessToken; + $params['appsecret_proof'] = $this->getAppSecretProof(); + } + + return $params; + } + + /** + * Only return params on POST requests. + * + * @return array + */ + public function getPostParams() + { + if ($this->getMethod() === 'POST') { + return $this->getParams(); + } + + return []; + } + + /** + * The graph version used for this request. + * + * @return string + */ + public function getGraphVersion() + { + return $this->graphVersion; + } + + /** + * Generate and return the URL for this request. + * + * @return string + */ + public function getUrl() + { + $this->validateMethod(); + + $graphVersion = FacebookUrlManipulator::forceSlashPrefix($this->graphVersion); + $endpoint = FacebookUrlManipulator::forceSlashPrefix($this->getEndpoint()); + + $url = $graphVersion . $endpoint; + + if ($this->getMethod() !== 'POST') { + $params = $this->getParams(); + $url = FacebookUrlManipulator::appendParamsToUrl($url, $params); + } + + return $url; + } + + /** + * Return the default headers that every request should use. + * + * @return array + */ + public static function getDefaultHeaders() + { + return [ + 'User-Agent' => 'fb-php-' . Facebook::VERSION, + 'Accept-Encoding' => '*', + ]; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/FacebookResponse.php b/vendor/facebook/graph-sdk/src/Facebook/FacebookResponse.php new file mode 100644 index 0000000..251ca2f --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/FacebookResponse.php @@ -0,0 +1,410 @@ +request = $request; + $this->body = $body; + $this->httpStatusCode = $httpStatusCode; + $this->headers = $headers; + + $this->decodeBody(); + } + + /** + * Return the original request that returned this response. + * + * @return FacebookRequest + */ + public function getRequest() + { + return $this->request; + } + + /** + * Return the FacebookApp entity used for this response. + * + * @return FacebookApp + */ + public function getApp() + { + return $this->request->getApp(); + } + + /** + * Return the access token that was used for this response. + * + * @return string|null + */ + public function getAccessToken() + { + return $this->request->getAccessToken(); + } + + /** + * Return the HTTP status code for this response. + * + * @return int + */ + public function getHttpStatusCode() + { + return $this->httpStatusCode; + } + + /** + * Return the HTTP headers for this response. + * + * @return array + */ + public function getHeaders() + { + return $this->headers; + } + + /** + * Return the raw body response. + * + * @return string + */ + public function getBody() + { + return $this->body; + } + + /** + * Return the decoded body response. + * + * @return array + */ + public function getDecodedBody() + { + return $this->decodedBody; + } + + /** + * Get the app secret proof that was used for this response. + * + * @return string|null + */ + public function getAppSecretProof() + { + return $this->request->getAppSecretProof(); + } + + /** + * Get the ETag associated with the response. + * + * @return string|null + */ + public function getETag() + { + return isset($this->headers['ETag']) ? $this->headers['ETag'] : null; + } + + /** + * Get the version of Graph that returned this response. + * + * @return string|null + */ + public function getGraphVersion() + { + return isset($this->headers['Facebook-API-Version']) ? $this->headers['Facebook-API-Version'] : null; + } + + /** + * Returns true if Graph returned an error message. + * + * @return boolean + */ + public function isError() + { + return isset($this->decodedBody['error']); + } + + /** + * Throws the exception. + * + * @throws FacebookSDKException + */ + public function throwException() + { + throw $this->thrownException; + } + + /** + * Instantiates an exception to be thrown later. + */ + public function makeException() + { + $this->thrownException = FacebookResponseException::create($this); + } + + /** + * Returns the exception that was thrown for this request. + * + * @return FacebookResponseException|null + */ + public function getThrownException() + { + return $this->thrownException; + } + + /** + * Convert the raw response into an array if possible. + * + * Graph will return 2 types of responses: + * - JSON(P) + * Most responses from Graph are JSON(P) + * - application/x-www-form-urlencoded key/value pairs + * Happens on the `/oauth/access_token` endpoint when exchanging + * a short-lived access token for a long-lived access token + * - And sometimes nothing :/ but that'd be a bug. + */ + public function decodeBody() + { + $this->decodedBody = json_decode($this->body, true); + + if ($this->decodedBody === null) { + $this->decodedBody = []; + parse_str($this->body, $this->decodedBody); + } elseif (is_bool($this->decodedBody)) { + // Backwards compatibility for Graph < 2.1. + // Mimics 2.1 responses. + // @TODO Remove this after Graph 2.0 is no longer supported + $this->decodedBody = ['success' => $this->decodedBody]; + } elseif (is_numeric($this->decodedBody)) { + $this->decodedBody = ['id' => $this->decodedBody]; + } + + if (!is_array($this->decodedBody)) { + $this->decodedBody = []; + } + + if ($this->isError()) { + $this->makeException(); + } + } + + /** + * Instantiate a new GraphObject from response. + * + * @param string|null $subclassName The GraphNode subclass to cast to. + * + * @return \Facebook\GraphNodes\GraphObject + * + * @throws FacebookSDKException + * + * @deprecated 5.0.0 getGraphObject() has been renamed to getGraphNode() + * @todo v6: Remove this method + */ + public function getGraphObject($subclassName = null) + { + return $this->getGraphNode($subclassName); + } + + /** + * Instantiate a new GraphNode from response. + * + * @param string|null $subclassName The GraphNode subclass to cast to. + * + * @return \Facebook\GraphNodes\GraphNode + * + * @throws FacebookSDKException + */ + public function getGraphNode($subclassName = null) + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphNode($subclassName); + } + + /** + * Convenience method for creating a GraphAlbum collection. + * + * @return \Facebook\GraphNodes\GraphAlbum + * + * @throws FacebookSDKException + */ + public function getGraphAlbum() + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphAlbum(); + } + + /** + * Convenience method for creating a GraphPage collection. + * + * @return \Facebook\GraphNodes\GraphPage + * + * @throws FacebookSDKException + */ + public function getGraphPage() + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphPage(); + } + + /** + * Convenience method for creating a GraphSessionInfo collection. + * + * @return \Facebook\GraphNodes\GraphSessionInfo + * + * @throws FacebookSDKException + */ + public function getGraphSessionInfo() + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphSessionInfo(); + } + + /** + * Convenience method for creating a GraphUser collection. + * + * @return \Facebook\GraphNodes\GraphUser + * + * @throws FacebookSDKException + */ + public function getGraphUser() + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphUser(); + } + + /** + * Convenience method for creating a GraphEvent collection. + * + * @return \Facebook\GraphNodes\GraphEvent + * + * @throws FacebookSDKException + */ + public function getGraphEvent() + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphEvent(); + } + + /** + * Convenience method for creating a GraphGroup collection. + * + * @return \Facebook\GraphNodes\GraphGroup + * + * @throws FacebookSDKException + */ + public function getGraphGroup() + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphGroup(); + } + + /** + * Instantiate a new GraphList from response. + * + * @param string|null $subclassName The GraphNode subclass to cast list items to. + * @param boolean $auto_prefix Toggle to auto-prefix the subclass name. + * + * @return \Facebook\GraphNodes\GraphList + * + * @throws FacebookSDKException + * + * @deprecated 5.0.0 getGraphList() has been renamed to getGraphEdge() + * @todo v6: Remove this method + */ + public function getGraphList($subclassName = null, $auto_prefix = true) + { + return $this->getGraphEdge($subclassName, $auto_prefix); + } + + /** + * Instantiate a new GraphEdge from response. + * + * @param string|null $subclassName The GraphNode subclass to cast list items to. + * @param boolean $auto_prefix Toggle to auto-prefix the subclass name. + * + * @return \Facebook\GraphNodes\GraphEdge + * + * @throws FacebookSDKException + */ + public function getGraphEdge($subclassName = null, $auto_prefix = true) + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphEdge($subclassName, $auto_prefix); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookFile.php b/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookFile.php new file mode 100644 index 0000000..3c1536d --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookFile.php @@ -0,0 +1,169 @@ +path = $filePath; + $this->maxLength = $maxLength; + $this->offset = $offset; + $this->open(); + } + + /** + * Closes the stream when destructed. + */ + public function __destruct() + { + $this->close(); + } + + /** + * Opens a stream for the file. + * + * @throws FacebookSDKException + */ + public function open() + { + if (!$this->isRemoteFile($this->path) && !is_readable($this->path)) { + throw new FacebookSDKException('Failed to create FacebookFile entity. Unable to read resource: ' . $this->path . '.'); + } + + $this->stream = fopen($this->path, 'r'); + + if (!$this->stream) { + throw new FacebookSDKException('Failed to create FacebookFile entity. Unable to open resource: ' . $this->path . '.'); + } + } + + /** + * Stops the file stream. + */ + public function close() + { + if (is_resource($this->stream)) { + fclose($this->stream); + } + } + + /** + * Return the contents of the file. + * + * @return string + */ + public function getContents() + { + return stream_get_contents($this->stream, $this->maxLength, $this->offset); + } + + /** + * Return the name of the file. + * + * @return string + */ + public function getFileName() + { + return basename($this->path); + } + + /** + * Return the path of the file. + * + * @return string + */ + public function getFilePath() + { + return $this->path; + } + + /** + * Return the size of the file. + * + * @return int + */ + public function getSize() + { + return filesize($this->path); + } + + /** + * Return the mimetype of the file. + * + * @return string + */ + public function getMimetype() + { + return Mimetypes::getInstance()->fromFilename($this->path) ?: 'text/plain'; + } + + /** + * Returns true if the path to the file is remote. + * + * @param string $pathToFile + * + * @return boolean + */ + protected function isRemoteFile($pathToFile) + { + return preg_match('/^(https?|ftp):\/\/.*/', $pathToFile) === 1; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookResumableUploader.php b/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookResumableUploader.php new file mode 100644 index 0000000..92a22f1 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookResumableUploader.php @@ -0,0 +1,167 @@ +app = $app; + $this->client = $client; + $this->accessToken = $accessToken; + $this->graphVersion = $graphVersion; + } + + /** + * Upload by chunks - start phase + * + * @param string $endpoint + * @param FacebookFile $file + * + * @return FacebookTransferChunk + * + * @throws FacebookSDKException + */ + public function start($endpoint, FacebookFile $file) + { + $params = [ + 'upload_phase' => 'start', + 'file_size' => $file->getSize(), + ]; + $response = $this->sendUploadRequest($endpoint, $params); + + return new FacebookTransferChunk($file, $response['upload_session_id'], $response['video_id'], $response['start_offset'], $response['end_offset']); + } + + /** + * Upload by chunks - transfer phase + * + * @param string $endpoint + * @param FacebookTransferChunk $chunk + * @param boolean $allowToThrow + * + * @return FacebookTransferChunk + * + * @throws FacebookResponseException + */ + public function transfer($endpoint, FacebookTransferChunk $chunk, $allowToThrow = false) + { + $params = [ + 'upload_phase' => 'transfer', + 'upload_session_id' => $chunk->getUploadSessionId(), + 'start_offset' => $chunk->getStartOffset(), + 'video_file_chunk' => $chunk->getPartialFile(), + ]; + + try { + $response = $this->sendUploadRequest($endpoint, $params); + } catch (FacebookResponseException $e) { + $preException = $e->getPrevious(); + if ($allowToThrow || !$preException instanceof FacebookResumableUploadException) { + throw $e; + } + + // Return the same chunk entity so it can be retried. + return $chunk; + } + + return new FacebookTransferChunk($chunk->getFile(), $chunk->getUploadSessionId(), $chunk->getVideoId(), $response['start_offset'], $response['end_offset']); + } + + /** + * Upload by chunks - finish phase + * + * @param string $endpoint + * @param string $uploadSessionId + * @param array $metadata The metadata associated with the file. + * + * @return boolean + * + * @throws FacebookSDKException + */ + public function finish($endpoint, $uploadSessionId, $metadata = []) + { + $params = array_merge($metadata, [ + 'upload_phase' => 'finish', + 'upload_session_id' => $uploadSessionId, + ]); + $response = $this->sendUploadRequest($endpoint, $params); + + return $response['success']; + } + + /** + * Helper to make a FacebookRequest and send it. + * + * @param string $endpoint The endpoint to POST to. + * @param array $params The params to send with the request. + * + * @return array + */ + private function sendUploadRequest($endpoint, $params = []) + { + $request = new FacebookRequest($this->app, $this->accessToken, 'POST', $endpoint, $params, null, $this->graphVersion); + + return $this->client->sendRequest($request)->getDecodedBody(); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookTransferChunk.php b/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookTransferChunk.php new file mode 100644 index 0000000..a909e87 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookTransferChunk.php @@ -0,0 +1,133 @@ +file = $file; + $this->uploadSessionId = $uploadSessionId; + $this->videoId = $videoId; + $this->startOffset = $startOffset; + $this->endOffset = $endOffset; + } + + /** + * Return the file entity. + * + * @return FacebookFile + */ + public function getFile() + { + return $this->file; + } + + /** + * Return a FacebookFile entity with partial content. + * + * @return FacebookFile + */ + public function getPartialFile() + { + $maxLength = $this->endOffset - $this->startOffset; + + return new FacebookFile($this->file->getFilePath(), $maxLength, $this->startOffset); + } + + /** + * Return upload session Id + * + * @return int + */ + public function getUploadSessionId() + { + return $this->uploadSessionId; + } + + /** + * Check whether is the last chunk + * + * @return bool + */ + public function isLastChunk() + { + return $this->startOffset === $this->endOffset; + } + + /** + * @return int + */ + public function getStartOffset() + { + return $this->startOffset; + } + + /** + * Get uploaded video Id + * + * @return int + */ + public function getVideoId() + { + return $this->videoId; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookVideo.php b/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookVideo.php new file mode 100644 index 0000000..ee6dd53 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookVideo.php @@ -0,0 +1,33 @@ + 'text/vnd.in3d.3dml', + '3g2' => 'video/3gpp2', + '3gp' => 'video/3gpp', + '7z' => 'application/x-7z-compressed', + 'aab' => 'application/x-authorware-bin', + 'aac' => 'audio/x-aac', + 'aam' => 'application/x-authorware-map', + 'aas' => 'application/x-authorware-seg', + 'abw' => 'application/x-abiword', + 'ac' => 'application/pkix-attr-cert', + 'acc' => 'application/vnd.americandynamics.acc', + 'ace' => 'application/x-ace-compressed', + 'acu' => 'application/vnd.acucobol', + 'acutc' => 'application/vnd.acucorp', + 'adp' => 'audio/adpcm', + 'aep' => 'application/vnd.audiograph', + 'afm' => 'application/x-font-type1', + 'afp' => 'application/vnd.ibm.modcap', + 'ahead' => 'application/vnd.ahead.space', + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'air' => 'application/vnd.adobe.air-application-installer-package+zip', + 'ait' => 'application/vnd.dvb.ait', + 'ami' => 'application/vnd.amiga.ami', + 'apk' => 'application/vnd.android.package-archive', + 'application' => 'application/x-ms-application', + 'apr' => 'application/vnd.lotus-approach', + 'asa' => 'text/plain', + 'asax' => 'application/octet-stream', + 'asc' => 'application/pgp-signature', + 'ascx' => 'text/plain', + 'asf' => 'video/x-ms-asf', + 'ashx' => 'text/plain', + 'asm' => 'text/x-asm', + 'asmx' => 'text/plain', + 'aso' => 'application/vnd.accpac.simply.aso', + 'asp' => 'text/plain', + 'aspx' => 'text/plain', + 'asx' => 'video/x-ms-asf', + 'atc' => 'application/vnd.acucorp', + 'atom' => 'application/atom+xml', + 'atomcat' => 'application/atomcat+xml', + 'atomsvc' => 'application/atomsvc+xml', + 'atx' => 'application/vnd.antix.game-component', + 'au' => 'audio/basic', + 'avi' => 'video/x-msvideo', + 'aw' => 'application/applixware', + 'axd' => 'text/plain', + 'azf' => 'application/vnd.airzip.filesecure.azf', + 'azs' => 'application/vnd.airzip.filesecure.azs', + 'azw' => 'application/vnd.amazon.ebook', + 'bat' => 'application/x-msdownload', + 'bcpio' => 'application/x-bcpio', + 'bdf' => 'application/x-font-bdf', + 'bdm' => 'application/vnd.syncml.dm+wbxml', + 'bed' => 'application/vnd.realvnc.bed', + 'bh2' => 'application/vnd.fujitsu.oasysprs', + 'bin' => 'application/octet-stream', + 'bmi' => 'application/vnd.bmi', + 'bmp' => 'image/bmp', + 'book' => 'application/vnd.framemaker', + 'box' => 'application/vnd.previewsystems.box', + 'boz' => 'application/x-bzip2', + 'bpk' => 'application/octet-stream', + 'btif' => 'image/prs.btif', + 'bz' => 'application/x-bzip', + 'bz2' => 'application/x-bzip2', + 'c' => 'text/x-c', + 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', + 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', + 'c4d' => 'application/vnd.clonk.c4group', + 'c4f' => 'application/vnd.clonk.c4group', + 'c4g' => 'application/vnd.clonk.c4group', + 'c4p' => 'application/vnd.clonk.c4group', + 'c4u' => 'application/vnd.clonk.c4group', + 'cab' => 'application/vnd.ms-cab-compressed', + 'car' => 'application/vnd.curl.car', + 'cat' => 'application/vnd.ms-pki.seccat', + 'cc' => 'text/x-c', + 'cct' => 'application/x-director', + 'ccxml' => 'application/ccxml+xml', + 'cdbcmsg' => 'application/vnd.contact.cmsg', + 'cdf' => 'application/x-netcdf', + 'cdkey' => 'application/vnd.mediastation.cdkey', + 'cdmia' => 'application/cdmi-capability', + 'cdmic' => 'application/cdmi-container', + 'cdmid' => 'application/cdmi-domain', + 'cdmio' => 'application/cdmi-object', + 'cdmiq' => 'application/cdmi-queue', + 'cdx' => 'chemical/x-cdx', + 'cdxml' => 'application/vnd.chemdraw+xml', + 'cdy' => 'application/vnd.cinderella', + 'cer' => 'application/pkix-cert', + 'cfc' => 'application/x-coldfusion', + 'cfm' => 'application/x-coldfusion', + 'cgm' => 'image/cgm', + 'chat' => 'application/x-chat', + 'chm' => 'application/vnd.ms-htmlhelp', + 'chrt' => 'application/vnd.kde.kchart', + 'cif' => 'chemical/x-cif', + 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', + 'cil' => 'application/vnd.ms-artgalry', + 'cla' => 'application/vnd.claymore', + 'class' => 'application/java-vm', + 'clkk' => 'application/vnd.crick.clicker.keyboard', + 'clkp' => 'application/vnd.crick.clicker.palette', + 'clkt' => 'application/vnd.crick.clicker.template', + 'clkw' => 'application/vnd.crick.clicker.wordbank', + 'clkx' => 'application/vnd.crick.clicker', + 'clp' => 'application/x-msclip', + 'cmc' => 'application/vnd.cosmocaller', + 'cmdf' => 'chemical/x-cmdf', + 'cml' => 'chemical/x-cml', + 'cmp' => 'application/vnd.yellowriver-custom-menu', + 'cmx' => 'image/x-cmx', + 'cod' => 'application/vnd.rim.cod', + 'com' => 'application/x-msdownload', + 'conf' => 'text/plain', + 'cpio' => 'application/x-cpio', + 'cpp' => 'text/x-c', + 'cpt' => 'application/mac-compactpro', + 'crd' => 'application/x-mscardfile', + 'crl' => 'application/pkix-crl', + 'crt' => 'application/x-x509-ca-cert', + 'cryptonote' => 'application/vnd.rig.cryptonote', + 'cs' => 'text/plain', + 'csh' => 'application/x-csh', + 'csml' => 'chemical/x-csml', + 'csp' => 'application/vnd.commonspace', + 'css' => 'text/css', + 'cst' => 'application/x-director', + 'csv' => 'text/csv', + 'cu' => 'application/cu-seeme', + 'curl' => 'text/vnd.curl', + 'cww' => 'application/prs.cww', + 'cxt' => 'application/x-director', + 'cxx' => 'text/x-c', + 'dae' => 'model/vnd.collada+xml', + 'daf' => 'application/vnd.mobius.daf', + 'dataless' => 'application/vnd.fdsn.seed', + 'davmount' => 'application/davmount+xml', + 'dcr' => 'application/x-director', + 'dcurl' => 'text/vnd.curl.dcurl', + 'dd2' => 'application/vnd.oma.dd2+xml', + 'ddd' => 'application/vnd.fujixerox.ddd', + 'deb' => 'application/x-debian-package', + 'def' => 'text/plain', + 'deploy' => 'application/octet-stream', + 'der' => 'application/x-x509-ca-cert', + 'dfac' => 'application/vnd.dreamfactory', + 'dic' => 'text/x-c', + 'dir' => 'application/x-director', + 'dis' => 'application/vnd.mobius.dis', + 'dist' => 'application/octet-stream', + 'distz' => 'application/octet-stream', + 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dll' => 'application/x-msdownload', + 'dmg' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'dna' => 'application/vnd.dna', + 'doc' => 'application/msword', + 'docm' => 'application/vnd.ms-word.document.macroenabled.12', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dot' => 'application/msword', + 'dotm' => 'application/vnd.ms-word.template.macroenabled.12', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'dp' => 'application/vnd.osgi.dp', + 'dpg' => 'application/vnd.dpgraph', + 'dra' => 'audio/vnd.dra', + 'dsc' => 'text/prs.lines.tag', + 'dssc' => 'application/dssc+der', + 'dtb' => 'application/x-dtbook+xml', + 'dtd' => 'application/xml-dtd', + 'dts' => 'audio/vnd.dts', + 'dtshd' => 'audio/vnd.dts.hd', + 'dump' => 'application/octet-stream', + 'dvi' => 'application/x-dvi', + 'dwf' => 'model/vnd.dwf', + 'dwg' => 'image/vnd.dwg', + 'dxf' => 'image/vnd.dxf', + 'dxp' => 'application/vnd.spotfire.dxp', + 'dxr' => 'application/x-director', + 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', + 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', + 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', + 'ecma' => 'application/ecmascript', + 'edm' => 'application/vnd.novadigm.edm', + 'edx' => 'application/vnd.novadigm.edx', + 'efif' => 'application/vnd.picsel', + 'ei6' => 'application/vnd.pg.osasli', + 'elc' => 'application/octet-stream', + 'eml' => 'message/rfc822', + 'emma' => 'application/emma+xml', + 'eol' => 'audio/vnd.digital-winds', + 'eot' => 'application/vnd.ms-fontobject', + 'eps' => 'application/postscript', + 'epub' => 'application/epub+zip', + 'es3' => 'application/vnd.eszigno3+xml', + 'esf' => 'application/vnd.epson.esf', + 'et3' => 'application/vnd.eszigno3+xml', + 'etx' => 'text/x-setext', + 'exe' => 'application/x-msdownload', + 'exi' => 'application/exi', + 'ext' => 'application/vnd.novadigm.ext', + 'ez' => 'application/andrew-inset', + 'ez2' => 'application/vnd.ezpix-album', + 'ez3' => 'application/vnd.ezpix-package', + 'f' => 'text/x-fortran', + 'f4v' => 'video/x-f4v', + 'f77' => 'text/x-fortran', + 'f90' => 'text/x-fortran', + 'fbs' => 'image/vnd.fastbidsheet', + 'fcs' => 'application/vnd.isac.fcs', + 'fdf' => 'application/vnd.fdf', + 'fe_launch' => 'application/vnd.denovo.fcselayout-link', + 'fg5' => 'application/vnd.fujitsu.oasysgp', + 'fgd' => 'application/x-director', + 'fh' => 'image/x-freehand', + 'fh4' => 'image/x-freehand', + 'fh5' => 'image/x-freehand', + 'fh7' => 'image/x-freehand', + 'fhc' => 'image/x-freehand', + 'fig' => 'application/x-xfig', + 'fli' => 'video/x-fli', + 'flo' => 'application/vnd.micrografx.flo', + 'flv' => 'video/x-flv', + 'flw' => 'application/vnd.kde.kivio', + 'flx' => 'text/vnd.fmi.flexstor', + 'fly' => 'text/vnd.fly', + 'fm' => 'application/vnd.framemaker', + 'fnc' => 'application/vnd.frogans.fnc', + 'for' => 'text/x-fortran', + 'fpx' => 'image/vnd.fpx', + 'frame' => 'application/vnd.framemaker', + 'fsc' => 'application/vnd.fsc.weblaunch', + 'fst' => 'image/vnd.fst', + 'ftc' => 'application/vnd.fluxtime.clip', + 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', + 'fvt' => 'video/vnd.fvt', + 'fxp' => 'application/vnd.adobe.fxp', + 'fxpl' => 'application/vnd.adobe.fxp', + 'fzs' => 'application/vnd.fuzzysheet', + 'g2w' => 'application/vnd.geoplan', + 'g3' => 'image/g3fax', + 'g3w' => 'application/vnd.geospace', + 'gac' => 'application/vnd.groove-account', + 'gdl' => 'model/vnd.gdl', + 'geo' => 'application/vnd.dynageo', + 'gex' => 'application/vnd.geometry-explorer', + 'ggb' => 'application/vnd.geogebra.file', + 'ggt' => 'application/vnd.geogebra.tool', + 'ghf' => 'application/vnd.groove-help', + 'gif' => 'image/gif', + 'gim' => 'application/vnd.groove-identity-message', + 'gmx' => 'application/vnd.gmx', + 'gnumeric' => 'application/x-gnumeric', + 'gph' => 'application/vnd.flographit', + 'gqf' => 'application/vnd.grafeq', + 'gqs' => 'application/vnd.grafeq', + 'gram' => 'application/srgs', + 'gre' => 'application/vnd.geometry-explorer', + 'grv' => 'application/vnd.groove-injector', + 'grxml' => 'application/srgs+xml', + 'gsf' => 'application/x-font-ghostscript', + 'gtar' => 'application/x-gtar', + 'gtm' => 'application/vnd.groove-tool-message', + 'gtw' => 'model/vnd.gtw', + 'gv' => 'text/vnd.graphviz', + 'gxt' => 'application/vnd.geonext', + 'h' => 'text/x-c', + 'h261' => 'video/h261', + 'h263' => 'video/h263', + 'h264' => 'video/h264', + 'hal' => 'application/vnd.hal+xml', + 'hbci' => 'application/vnd.hbci', + 'hdf' => 'application/x-hdf', + 'hh' => 'text/x-c', + 'hlp' => 'application/winhlp', + 'hpgl' => 'application/vnd.hp-hpgl', + 'hpid' => 'application/vnd.hp-hpid', + 'hps' => 'application/vnd.hp-hps', + 'hqx' => 'application/mac-binhex40', + 'hta' => 'application/octet-stream', + 'htc' => 'text/html', + 'htke' => 'application/vnd.kenameaapp', + 'htm' => 'text/html', + 'html' => 'text/html', + 'hvd' => 'application/vnd.yamaha.hv-dic', + 'hvp' => 'application/vnd.yamaha.hv-voice', + 'hvs' => 'application/vnd.yamaha.hv-script', + 'i2g' => 'application/vnd.intergeo', + 'icc' => 'application/vnd.iccprofile', + 'ice' => 'x-conference/x-cooltalk', + 'icm' => 'application/vnd.iccprofile', + 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'ief' => 'image/ief', + 'ifb' => 'text/calendar', + 'ifm' => 'application/vnd.shana.informed.formdata', + 'iges' => 'model/iges', + 'igl' => 'application/vnd.igloader', + 'igm' => 'application/vnd.insors.igm', + 'igs' => 'model/iges', + 'igx' => 'application/vnd.micrografx.igx', + 'iif' => 'application/vnd.shana.informed.interchange', + 'imp' => 'application/vnd.accpac.simply.imp', + 'ims' => 'application/vnd.ms-ims', + 'in' => 'text/plain', + 'ini' => 'text/plain', + 'ipfix' => 'application/ipfix', + 'ipk' => 'application/vnd.shana.informed.package', + 'irm' => 'application/vnd.ibm.rights-management', + 'irp' => 'application/vnd.irepository.package+xml', + 'iso' => 'application/octet-stream', + 'itp' => 'application/vnd.shana.informed.formtemplate', + 'ivp' => 'application/vnd.immervision-ivp', + 'ivu' => 'application/vnd.immervision-ivu', + 'jad' => 'text/vnd.sun.j2me.app-descriptor', + 'jam' => 'application/vnd.jam', + 'jar' => 'application/java-archive', + 'java' => 'text/x-java-source', + 'jisp' => 'application/vnd.jisp', + 'jlt' => 'application/vnd.hp-jlyt', + 'jnlp' => 'application/x-java-jnlp-file', + 'joda' => 'application/vnd.joost.joda-archive', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'jpgm' => 'video/jpm', + 'jpgv' => 'video/jpeg', + 'jpm' => 'video/jpm', + 'js' => 'text/javascript', + 'json' => 'application/json', + 'kar' => 'audio/midi', + 'karbon' => 'application/vnd.kde.karbon', + 'kfo' => 'application/vnd.kde.kformula', + 'kia' => 'application/vnd.kidspiration', + 'kml' => 'application/vnd.google-earth.kml+xml', + 'kmz' => 'application/vnd.google-earth.kmz', + 'kne' => 'application/vnd.kinar', + 'knp' => 'application/vnd.kinar', + 'kon' => 'application/vnd.kde.kontour', + 'kpr' => 'application/vnd.kde.kpresenter', + 'kpt' => 'application/vnd.kde.kpresenter', + 'ksp' => 'application/vnd.kde.kspread', + 'ktr' => 'application/vnd.kahootz', + 'ktx' => 'image/ktx', + 'ktz' => 'application/vnd.kahootz', + 'kwd' => 'application/vnd.kde.kword', + 'kwt' => 'application/vnd.kde.kword', + 'lasxml' => 'application/vnd.las.las+xml', + 'latex' => 'application/x-latex', + 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', + 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', + 'les' => 'application/vnd.hhe.lesson-player', + 'lha' => 'application/octet-stream', + 'link66' => 'application/vnd.route66.link66+xml', + 'list' => 'text/plain', + 'list3820' => 'application/vnd.ibm.modcap', + 'listafp' => 'application/vnd.ibm.modcap', + 'log' => 'text/plain', + 'lostxml' => 'application/lost+xml', + 'lrf' => 'application/octet-stream', + 'lrm' => 'application/vnd.ms-lrm', + 'ltf' => 'application/vnd.frogans.ltf', + 'lvp' => 'audio/vnd.lucent.voice', + 'lwp' => 'application/vnd.lotus-wordpro', + 'lzh' => 'application/octet-stream', + 'm13' => 'application/x-msmediaview', + 'm14' => 'application/x-msmediaview', + 'm1v' => 'video/mpeg', + 'm21' => 'application/mp21', + 'm2a' => 'audio/mpeg', + 'm2v' => 'video/mpeg', + 'm3a' => 'audio/mpeg', + 'm3u' => 'audio/x-mpegurl', + 'm3u8' => 'application/vnd.apple.mpegurl', + 'm4a' => 'audio/mp4', + 'm4u' => 'video/vnd.mpegurl', + 'm4v' => 'video/mp4', + 'ma' => 'application/mathematica', + 'mads' => 'application/mads+xml', + 'mag' => 'application/vnd.ecowin.chart', + 'maker' => 'application/vnd.framemaker', + 'man' => 'text/troff', + 'mathml' => 'application/mathml+xml', + 'mb' => 'application/mathematica', + 'mbk' => 'application/vnd.mobius.mbk', + 'mbox' => 'application/mbox', + 'mc1' => 'application/vnd.medcalcdata', + 'mcd' => 'application/vnd.mcd', + 'mcurl' => 'text/vnd.curl.mcurl', + 'mdb' => 'application/x-msaccess', + 'mdi' => 'image/vnd.ms-modi', + 'me' => 'text/troff', + 'mesh' => 'model/mesh', + 'meta4' => 'application/metalink4+xml', + 'mets' => 'application/mets+xml', + 'mfm' => 'application/vnd.mfmp', + 'mgp' => 'application/vnd.osgeo.mapguide.package', + 'mgz' => 'application/vnd.proteus.magazine', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mif' => 'application/vnd.mif', + 'mime' => 'message/rfc822', + 'mj2' => 'video/mj2', + 'mjp2' => 'video/mj2', + 'mlp' => 'application/vnd.dolby.mlp', + 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', + 'mmf' => 'application/vnd.smaf', + 'mmr' => 'image/vnd.fujixerox.edmics-mmr', + 'mny' => 'application/x-msmoney', + 'mobi' => 'application/x-mobipocket-ebook', + 'mods' => 'application/mods+xml', + 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', + 'mp2' => 'audio/mpeg', + 'mp21' => 'application/mp21', + 'mp2a' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mp4a' => 'audio/mp4', + 'mp4s' => 'application/mp4', + 'mp4v' => 'video/mp4', + 'mpc' => 'application/vnd.mophun.certificate', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpg4' => 'video/mp4', + 'mpga' => 'audio/mpeg', + 'mpkg' => 'application/vnd.apple.installer+xml', + 'mpm' => 'application/vnd.blueice.multipass', + 'mpn' => 'application/vnd.mophun.application', + 'mpp' => 'application/vnd.ms-project', + 'mpt' => 'application/vnd.ms-project', + 'mpy' => 'application/vnd.ibm.minipay', + 'mqy' => 'application/vnd.mobius.mqy', + 'mrc' => 'application/marc', + 'mrcx' => 'application/marcxml+xml', + 'ms' => 'text/troff', + 'mscml' => 'application/mediaservercontrol+xml', + 'mseed' => 'application/vnd.fdsn.mseed', + 'mseq' => 'application/vnd.mseq', + 'msf' => 'application/vnd.epson.msf', + 'msh' => 'model/mesh', + 'msi' => 'application/x-msdownload', + 'msl' => 'application/vnd.mobius.msl', + 'msty' => 'application/vnd.muvee.style', + 'mts' => 'model/vnd.mts', + 'mus' => 'application/vnd.musician', + 'musicxml' => 'application/vnd.recordare.musicxml+xml', + 'mvb' => 'application/x-msmediaview', + 'mwf' => 'application/vnd.mfer', + 'mxf' => 'application/mxf', + 'mxl' => 'application/vnd.recordare.musicxml', + 'mxml' => 'application/xv+xml', + 'mxs' => 'application/vnd.triscape.mxs', + 'mxu' => 'video/vnd.mpegurl', + 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', + 'n3' => 'text/n3', + 'nb' => 'application/mathematica', + 'nbp' => 'application/vnd.wolfram.player', + 'nc' => 'application/x-netcdf', + 'ncx' => 'application/x-dtbncx+xml', + 'ngdat' => 'application/vnd.nokia.n-gage.data', + 'nlu' => 'application/vnd.neurolanguage.nlu', + 'nml' => 'application/vnd.enliven', + 'nnd' => 'application/vnd.noblenet-directory', + 'nns' => 'application/vnd.noblenet-sealer', + 'nnw' => 'application/vnd.noblenet-web', + 'npx' => 'image/vnd.net-fpx', + 'nsf' => 'application/vnd.lotus-notes', + 'oa2' => 'application/vnd.fujitsu.oasys2', + 'oa3' => 'application/vnd.fujitsu.oasys3', + 'oas' => 'application/vnd.fujitsu.oasys', + 'obd' => 'application/x-msbinder', + 'oda' => 'application/oda', + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odft' => 'application/vnd.oasis.opendocument.formula-template', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'oga' => 'audio/ogg', + 'ogg' => 'audio/ogg', + 'ogv' => 'video/ogg', + 'ogx' => 'application/ogg', + 'onepkg' => 'application/onenote', + 'onetmp' => 'application/onenote', + 'onetoc' => 'application/onenote', + 'onetoc2' => 'application/onenote', + 'opf' => 'application/oebps-package+xml', + 'oprc' => 'application/vnd.palm', + 'org' => 'application/vnd.lotus-organizer', + 'osf' => 'application/vnd.yamaha.openscoreformat', + 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', + 'otc' => 'application/vnd.oasis.opendocument.chart-template', + 'otf' => 'application/x-font-otf', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'oti' => 'application/vnd.oasis.opendocument.image-template', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'oxt' => 'application/vnd.openofficeorg.extension', + 'p' => 'text/x-pascal', + 'p10' => 'application/pkcs10', + 'p12' => 'application/x-pkcs12', + 'p7b' => 'application/x-pkcs7-certificates', + 'p7c' => 'application/pkcs7-mime', + 'p7m' => 'application/pkcs7-mime', + 'p7r' => 'application/x-pkcs7-certreqresp', + 'p7s' => 'application/pkcs7-signature', + 'p8' => 'application/pkcs8', + 'pas' => 'text/x-pascal', + 'paw' => 'application/vnd.pawaafile', + 'pbd' => 'application/vnd.powerbuilder6', + 'pbm' => 'image/x-portable-bitmap', + 'pcf' => 'application/x-font-pcf', + 'pcl' => 'application/vnd.hp-pcl', + 'pclxl' => 'application/vnd.hp-pclxl', + 'pct' => 'image/x-pict', + 'pcurl' => 'application/vnd.curl.pcurl', + 'pcx' => 'image/x-pcx', + 'pdb' => 'application/vnd.palm', + 'pdf' => 'application/pdf', + 'pfa' => 'application/x-font-type1', + 'pfb' => 'application/x-font-type1', + 'pfm' => 'application/x-font-type1', + 'pfr' => 'application/font-tdpfr', + 'pfx' => 'application/x-pkcs12', + 'pgm' => 'image/x-portable-graymap', + 'pgn' => 'application/x-chess-pgn', + 'pgp' => 'application/pgp-encrypted', + 'php' => 'text/x-php', + 'phps' => 'application/x-httpd-phps', + 'pic' => 'image/x-pict', + 'pkg' => 'application/octet-stream', + 'pki' => 'application/pkixcmp', + 'pkipath' => 'application/pkix-pkipath', + 'plb' => 'application/vnd.3gpp.pic-bw-large', + 'plc' => 'application/vnd.mobius.plc', + 'plf' => 'application/vnd.pocketlearn', + 'pls' => 'application/pls+xml', + 'pml' => 'application/vnd.ctc-posml', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'portpkg' => 'application/vnd.macports.portpkg', + 'pot' => 'application/vnd.ms-powerpoint', + 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12', + 'ppd' => 'application/vnd.cups-ppd', + 'ppm' => 'image/x-portable-pixmap', + 'pps' => 'application/vnd.ms-powerpoint', + 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'pqa' => 'application/vnd.palm', + 'prc' => 'application/x-mobipocket-ebook', + 'pre' => 'application/vnd.lotus-freelance', + 'prf' => 'application/pics-rules', + 'ps' => 'application/postscript', + 'psb' => 'application/vnd.3gpp.pic-bw-small', + 'psd' => 'image/vnd.adobe.photoshop', + 'psf' => 'application/x-font-linux-psf', + 'pskcxml' => 'application/pskc+xml', + 'ptid' => 'application/vnd.pvi.ptid1', + 'pub' => 'application/x-mspublisher', + 'pvb' => 'application/vnd.3gpp.pic-bw-var', + 'pwn' => 'application/vnd.3m.post-it-notes', + 'pya' => 'audio/vnd.ms-playready.media.pya', + 'pyv' => 'video/vnd.ms-playready.media.pyv', + 'qam' => 'application/vnd.epson.quickanime', + 'qbo' => 'application/vnd.intu.qbo', + 'qfx' => 'application/vnd.intu.qfx', + 'qps' => 'application/vnd.publishare-delta-tree', + 'qt' => 'video/quicktime', + 'qwd' => 'application/vnd.quark.quarkxpress', + 'qwt' => 'application/vnd.quark.quarkxpress', + 'qxb' => 'application/vnd.quark.quarkxpress', + 'qxd' => 'application/vnd.quark.quarkxpress', + 'qxl' => 'application/vnd.quark.quarkxpress', + 'qxt' => 'application/vnd.quark.quarkxpress', + 'ra' => 'audio/x-pn-realaudio', + 'ram' => 'audio/x-pn-realaudio', + 'rar' => 'application/x-rar-compressed', + 'ras' => 'image/x-cmu-raster', + 'rb' => 'text/plain', + 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', + 'rdf' => 'application/rdf+xml', + 'rdz' => 'application/vnd.data-vision.rdz', + 'rep' => 'application/vnd.businessobjects', + 'res' => 'application/x-dtbresource+xml', + 'resx' => 'text/xml', + 'rgb' => 'image/x-rgb', + 'rif' => 'application/reginfo+xml', + 'rip' => 'audio/vnd.rip', + 'rl' => 'application/resource-lists+xml', + 'rlc' => 'image/vnd.fujixerox.edmics-rlc', + 'rld' => 'application/resource-lists-diff+xml', + 'rm' => 'application/vnd.rn-realmedia', + 'rmi' => 'audio/midi', + 'rmp' => 'audio/x-pn-realaudio-plugin', + 'rms' => 'application/vnd.jcp.javame.midlet-rms', + 'rnc' => 'application/relax-ng-compact-syntax', + 'roff' => 'text/troff', + 'rp9' => 'application/vnd.cloanto.rp9', + 'rpss' => 'application/vnd.nokia.radio-presets', + 'rpst' => 'application/vnd.nokia.radio-preset', + 'rq' => 'application/sparql-query', + 'rs' => 'application/rls-services+xml', + 'rsd' => 'application/rsd+xml', + 'rss' => 'application/rss+xml', + 'rtf' => 'application/rtf', + 'rtx' => 'text/richtext', + 's' => 'text/x-asm', + 'saf' => 'application/vnd.yamaha.smaf-audio', + 'sbml' => 'application/sbml+xml', + 'sc' => 'application/vnd.ibm.secure-container', + 'scd' => 'application/x-msschedule', + 'scm' => 'application/vnd.lotus-screencam', + 'scq' => 'application/scvp-cv-request', + 'scs' => 'application/scvp-cv-response', + 'scurl' => 'text/vnd.curl.scurl', + 'sda' => 'application/vnd.stardivision.draw', + 'sdc' => 'application/vnd.stardivision.calc', + 'sdd' => 'application/vnd.stardivision.impress', + 'sdkd' => 'application/vnd.solent.sdkm+xml', + 'sdkm' => 'application/vnd.solent.sdkm+xml', + 'sdp' => 'application/sdp', + 'sdw' => 'application/vnd.stardivision.writer', + 'see' => 'application/vnd.seemail', + 'seed' => 'application/vnd.fdsn.seed', + 'sema' => 'application/vnd.sema', + 'semd' => 'application/vnd.semd', + 'semf' => 'application/vnd.semf', + 'ser' => 'application/java-serialized-object', + 'setpay' => 'application/set-payment-initiation', + 'setreg' => 'application/set-registration-initiation', + 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', + 'sfs' => 'application/vnd.spotfire.sfs', + 'sgl' => 'application/vnd.stardivision.writer-global', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'shf' => 'application/shf+xml', + 'sig' => 'application/pgp-signature', + 'silo' => 'model/mesh', + 'sis' => 'application/vnd.symbian.install', + 'sisx' => 'application/vnd.symbian.install', + 'sit' => 'application/x-stuffit', + 'sitx' => 'application/x-stuffitx', + 'skd' => 'application/vnd.koan', + 'skm' => 'application/vnd.koan', + 'skp' => 'application/vnd.koan', + 'skt' => 'application/vnd.koan', + 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'slt' => 'application/vnd.epson.salt', + 'sm' => 'application/vnd.stepmania.stepchart', + 'smf' => 'application/vnd.stardivision.math', + 'smi' => 'application/smil+xml', + 'smil' => 'application/smil+xml', + 'snd' => 'audio/basic', + 'snf' => 'application/x-font-snf', + 'so' => 'application/octet-stream', + 'spc' => 'application/x-pkcs7-certificates', + 'spf' => 'application/vnd.yamaha.smaf-phrase', + 'spl' => 'application/x-futuresplash', + 'spot' => 'text/vnd.in3d.spot', + 'spp' => 'application/scvp-vp-response', + 'spq' => 'application/scvp-vp-request', + 'spx' => 'audio/ogg', + 'src' => 'application/x-wais-source', + 'srt' => 'application/octet-stream', + 'sru' => 'application/sru+xml', + 'srx' => 'application/sparql-results+xml', + 'sse' => 'application/vnd.kodak-descriptor', + 'ssf' => 'application/vnd.epson.ssf', + 'ssml' => 'application/ssml+xml', + 'st' => 'application/vnd.sailingtracker.track', + 'stc' => 'application/vnd.sun.xml.calc.template', + 'std' => 'application/vnd.sun.xml.draw.template', + 'stf' => 'application/vnd.wt.stf', + 'sti' => 'application/vnd.sun.xml.impress.template', + 'stk' => 'application/hyperstudio', + 'stl' => 'application/vnd.ms-pki.stl', + 'str' => 'application/vnd.pg.format', + 'stw' => 'application/vnd.sun.xml.writer.template', + 'sub' => 'image/vnd.dvb.subtitle', + 'sus' => 'application/vnd.sus-calendar', + 'susp' => 'application/vnd.sus-calendar', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'svc' => 'application/vnd.dvb.service', + 'svd' => 'application/vnd.svd', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + 'swa' => 'application/x-director', + 'swf' => 'application/x-shockwave-flash', + 'swi' => 'application/vnd.aristanetworks.swi', + 'sxc' => 'application/vnd.sun.xml.calc', + 'sxd' => 'application/vnd.sun.xml.draw', + 'sxg' => 'application/vnd.sun.xml.writer.global', + 'sxi' => 'application/vnd.sun.xml.impress', + 'sxm' => 'application/vnd.sun.xml.math', + 'sxw' => 'application/vnd.sun.xml.writer', + 't' => 'text/troff', + 'tao' => 'application/vnd.tao.intent-module-archive', + 'tar' => 'application/x-tar', + 'tcap' => 'application/vnd.3gpp2.tcap', + 'tcl' => 'application/x-tcl', + 'teacher' => 'application/vnd.smart.teacher', + 'tei' => 'application/tei+xml', + 'teicorpus' => 'application/tei+xml', + 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + 'text' => 'text/plain', + 'tfi' => 'application/thraud+xml', + 'tfm' => 'application/x-tex-tfm', + 'thmx' => 'application/vnd.ms-officetheme', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'tmo' => 'application/vnd.tmobile-livetv', + 'torrent' => 'application/x-bittorrent', + 'tpl' => 'application/vnd.groove-tool-template', + 'tpt' => 'application/vnd.trid.tpt', + 'tr' => 'text/troff', + 'tra' => 'application/vnd.trueapp', + 'trm' => 'application/x-msterminal', + 'tsd' => 'application/timestamped-data', + 'tsv' => 'text/tab-separated-values', + 'ttc' => 'application/x-font-ttf', + 'ttf' => 'application/x-font-ttf', + 'ttl' => 'text/turtle', + 'twd' => 'application/vnd.simtech-mindmapper', + 'twds' => 'application/vnd.simtech-mindmapper', + 'txd' => 'application/vnd.genomatix.tuxedo', + 'txf' => 'application/vnd.mobius.txf', + 'txt' => 'text/plain', + 'u32' => 'application/x-authorware-bin', + 'udeb' => 'application/x-debian-package', + 'ufd' => 'application/vnd.ufdl', + 'ufdl' => 'application/vnd.ufdl', + 'umj' => 'application/vnd.umajin', + 'unityweb' => 'application/vnd.unity', + 'uoml' => 'application/vnd.uoml+xml', + 'uri' => 'text/uri-list', + 'uris' => 'text/uri-list', + 'urls' => 'text/uri-list', + 'ustar' => 'application/x-ustar', + 'utz' => 'application/vnd.uiq.theme', + 'uu' => 'text/x-uuencode', + 'uva' => 'audio/vnd.dece.audio', + 'uvd' => 'application/vnd.dece.data', + 'uvf' => 'application/vnd.dece.data', + 'uvg' => 'image/vnd.dece.graphic', + 'uvh' => 'video/vnd.dece.hd', + 'uvi' => 'image/vnd.dece.graphic', + 'uvm' => 'video/vnd.dece.mobile', + 'uvp' => 'video/vnd.dece.pd', + 'uvs' => 'video/vnd.dece.sd', + 'uvt' => 'application/vnd.dece.ttml+xml', + 'uvu' => 'video/vnd.uvvu.mp4', + 'uvv' => 'video/vnd.dece.video', + 'uvva' => 'audio/vnd.dece.audio', + 'uvvd' => 'application/vnd.dece.data', + 'uvvf' => 'application/vnd.dece.data', + 'uvvg' => 'image/vnd.dece.graphic', + 'uvvh' => 'video/vnd.dece.hd', + 'uvvi' => 'image/vnd.dece.graphic', + 'uvvm' => 'video/vnd.dece.mobile', + 'uvvp' => 'video/vnd.dece.pd', + 'uvvs' => 'video/vnd.dece.sd', + 'uvvt' => 'application/vnd.dece.ttml+xml', + 'uvvu' => 'video/vnd.uvvu.mp4', + 'uvvv' => 'video/vnd.dece.video', + 'uvvx' => 'application/vnd.dece.unspecified', + 'uvx' => 'application/vnd.dece.unspecified', + 'vcd' => 'application/x-cdlink', + 'vcf' => 'text/x-vcard', + 'vcg' => 'application/vnd.groove-vcard', + 'vcs' => 'text/x-vcalendar', + 'vcx' => 'application/vnd.vcx', + 'vis' => 'application/vnd.visionary', + 'viv' => 'video/vnd.vivo', + 'vor' => 'application/vnd.stardivision.writer', + 'vox' => 'application/x-authorware-bin', + 'vrml' => 'model/vrml', + 'vsd' => 'application/vnd.visio', + 'vsf' => 'application/vnd.vsf', + 'vss' => 'application/vnd.visio', + 'vst' => 'application/vnd.visio', + 'vsw' => 'application/vnd.visio', + 'vtu' => 'model/vnd.vtu', + 'vxml' => 'application/voicexml+xml', + 'w3d' => 'application/x-director', + 'wad' => 'application/x-doom', + 'wav' => 'audio/x-wav', + 'wax' => 'audio/x-ms-wax', + 'wbmp' => 'image/vnd.wap.wbmp', + 'wbs' => 'application/vnd.criticaltools.wbs+xml', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wcm' => 'application/vnd.ms-works', + 'wdb' => 'application/vnd.ms-works', + 'weba' => 'audio/webm', + 'webm' => 'video/webm', + 'webp' => 'image/webp', + 'wg' => 'application/vnd.pmi.widget', + 'wgt' => 'application/widget', + 'wks' => 'application/vnd.ms-works', + 'wm' => 'video/x-ms-wm', + 'wma' => 'audio/x-ms-wma', + 'wmd' => 'application/x-ms-wmd', + 'wmf' => 'application/x-msmetafile', + 'wml' => 'text/vnd.wap.wml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmls' => 'text/vnd.wap.wmlscript', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wmz' => 'application/x-ms-wmz', + 'woff' => 'application/x-font-woff', + 'wpd' => 'application/vnd.wordperfect', + 'wpl' => 'application/vnd.ms-wpl', + 'wps' => 'application/vnd.ms-works', + 'wqd' => 'application/vnd.wqd', + 'wri' => 'application/x-mswrite', + 'wrl' => 'model/vrml', + 'wsdl' => 'application/wsdl+xml', + 'wspolicy' => 'application/wspolicy+xml', + 'wtb' => 'application/vnd.webturbo', + 'wvx' => 'video/x-ms-wvx', + 'x32' => 'application/x-authorware-bin', + 'x3d' => 'application/vnd.hzn-3d-crossword', + 'xap' => 'application/x-silverlight-app', + 'xar' => 'application/vnd.xara', + 'xbap' => 'application/x-ms-xbap', + 'xbd' => 'application/vnd.fujixerox.docuworks.binder', + 'xbm' => 'image/x-xbitmap', + 'xdf' => 'application/xcap-diff+xml', + 'xdm' => 'application/vnd.syncml.dm+xml', + 'xdp' => 'application/vnd.adobe.xdp+xml', + 'xdssc' => 'application/dssc+xml', + 'xdw' => 'application/vnd.fujixerox.docuworks', + 'xenc' => 'application/xenc+xml', + 'xer' => 'application/patch-ops-error+xml', + 'xfdf' => 'application/vnd.adobe.xfdf', + 'xfdl' => 'application/vnd.xfdl', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xhvml' => 'application/xv+xml', + 'xif' => 'image/vnd.xiff', + 'xla' => 'application/vnd.ms-excel', + 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12', + 'xlc' => 'application/vnd.ms-excel', + 'xlm' => 'application/vnd.ms-excel', + 'xls' => 'application/vnd.ms-excel', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12', + 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xlt' => 'application/vnd.ms-excel', + 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'xlw' => 'application/vnd.ms-excel', + 'xml' => 'application/xml', + 'xo' => 'application/vnd.olpc-sugar', + 'xop' => 'application/xop+xml', + 'xpi' => 'application/x-xpinstall', + 'xpm' => 'image/x-xpixmap', + 'xpr' => 'application/vnd.is-xpr', + 'xps' => 'application/vnd.ms-xpsdocument', + 'xpw' => 'application/vnd.intercon.formnet', + 'xpx' => 'application/vnd.intercon.formnet', + 'xsl' => 'application/xml', + 'xslt' => 'application/xslt+xml', + 'xsm' => 'application/vnd.syncml+xml', + 'xspf' => 'application/xspf+xml', + 'xul' => 'application/vnd.mozilla.xul+xml', + 'xvm' => 'application/xv+xml', + 'xvml' => 'application/xv+xml', + 'xwd' => 'image/x-xwindowdump', + 'xyz' => 'chemical/x-xyz', + 'yaml' => 'text/yaml', + 'yang' => 'application/yang', + 'yin' => 'application/yin+xml', + 'yml' => 'text/yaml', + 'zaz' => 'application/vnd.zzazz.deck+xml', + 'zip' => 'application/zip', + 'zir' => 'application/vnd.zul', + 'zirz' => 'application/vnd.zul', + 'zmm' => 'application/vnd.handheld-entertainment+xml' + ]; + + /** + * Get a singleton instance of the class + * + * @return self + * @codeCoverageIgnore + */ + public static function getInstance() + { + if (!self::$instance) { + self::$instance = new self(); + } + + return self::$instance; + } + + /** + * Get a mimetype value from a file extension + * + * @param string $extension File extension + * + * @return string|null + */ + public function fromExtension($extension) + { + $extension = strtolower($extension); + + return isset($this->mimetypes[$extension]) ? $this->mimetypes[$extension] : null; + } + + /** + * Get a mimetype from a filename + * + * @param string $filename Filename to generate a mimetype from + * + * @return string|null + */ + public function fromFilename($filename) + { + return $this->fromExtension(pathinfo($filename, PATHINFO_EXTENSION)); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Birthday.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Birthday.php new file mode 100644 index 0000000..4338b65 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Birthday.php @@ -0,0 +1,85 @@ +hasYear = count($parts) === 3 || count($parts) === 1; + $this->hasDate = count($parts) === 3 || count($parts) === 2; + + parent::__construct($date); + } + + /** + * Returns whether date object contains birth day and month + * + * @return bool + */ + public function hasDate() + { + return $this->hasDate; + } + + /** + * Returns whether date object contains birth year + * + * @return bool + */ + public function hasYear() + { + return $this->hasYear; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Collection.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Collection.php new file mode 100644 index 0000000..424b7cf --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Collection.php @@ -0,0 +1,242 @@ +items = $items; + } + + /** + * Gets the value of a field from the Graph node. + * + * @param string $name The field to retrieve. + * @param mixed $default The default to return if the field doesn't exist. + * + * @return mixed + */ + public function getField($name, $default = null) + { + if (isset($this->items[$name])) { + return $this->items[$name]; + } + + return $default; + } + + /** + * Gets the value of the named property for this graph object. + * + * @param string $name The property to retrieve. + * @param mixed $default The default to return if the property doesn't exist. + * + * @return mixed + * + * @deprecated 5.0.0 getProperty() has been renamed to getField() + * @todo v6: Remove this method + */ + public function getProperty($name, $default = null) + { + return $this->getField($name, $default); + } + + /** + * Returns a list of all fields set on the object. + * + * @return array + */ + public function getFieldNames() + { + return array_keys($this->items); + } + + /** + * Returns a list of all properties set on the object. + * + * @return array + * + * @deprecated 5.0.0 getPropertyNames() has been renamed to getFieldNames() + * @todo v6: Remove this method + */ + public function getPropertyNames() + { + return $this->getFieldNames(); + } + + /** + * Get all of the items in the collection. + * + * @return array + */ + public function all() + { + return $this->items; + } + + /** + * Get the collection of items as a plain array. + * + * @return array + */ + public function asArray() + { + return array_map(function ($value) { + return $value instanceof Collection ? $value->asArray() : $value; + }, $this->items); + } + + /** + * Run a map over each of the items. + * + * @param \Closure $callback + * + * @return static + */ + public function map(\Closure $callback) + { + return new static(array_map($callback, $this->items, array_keys($this->items))); + } + + /** + * Get the collection of items as JSON. + * + * @param int $options + * + * @return string + */ + public function asJson($options = 0) + { + return json_encode($this->asArray(), $options); + } + + /** + * Count the number of items in the collection. + * + * @return int + */ + public function count() + { + return count($this->items); + } + + /** + * Get an iterator for the items. + * + * @return ArrayIterator + */ + public function getIterator() + { + return new ArrayIterator($this->items); + } + + /** + * Determine if an item exists at an offset. + * + * @param mixed $key + * + * @return bool + */ + public function offsetExists($key) + { + return array_key_exists($key, $this->items); + } + + /** + * Get an item at a given offset. + * + * @param mixed $key + * + * @return mixed + */ + public function offsetGet($key) + { + return $this->items[$key]; + } + + /** + * Set the item at a given offset. + * + * @param mixed $key + * @param mixed $value + * + * @return void + */ + public function offsetSet($key, $value) + { + if (is_null($key)) { + $this->items[] = $value; + } else { + $this->items[$key] = $value; + } + } + + /** + * Unset the item at a given offset. + * + * @param string $key + * + * @return void + */ + public function offsetUnset($key) + { + unset($this->items[$key]); + } + + /** + * Convert the collection to its string representation. + * + * @return string + */ + public function __toString() + { + return $this->asJson(); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAchievement.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAchievement.php new file mode 100644 index 0000000..31508ee --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAchievement.php @@ -0,0 +1,112 @@ + '\Facebook\GraphNodes\GraphUser', + 'application' => '\Facebook\GraphNodes\GraphApplication', + ]; + + /** + * Returns the ID for the achievement. + * + * @return string|null + */ + public function getId() + { + return $this->getField('id'); + } + + /** + * Returns the user who achieved this. + * + * @return GraphUser|null + */ + public function getFrom() + { + return $this->getField('from'); + } + + /** + * Returns the time at which this was achieved. + * + * @return \DateTime|null + */ + public function getPublishTime() + { + return $this->getField('publish_time'); + } + + /** + * Returns the app in which the user achieved this. + * + * @return GraphApplication|null + */ + public function getApplication() + { + return $this->getField('application'); + } + + /** + * Returns information about the achievement type this instance is connected with. + * + * @return array|null + */ + public function getData() + { + return $this->getField('data'); + } + + /** + * Returns the type of achievement. + * + * @see https://developers.facebook.com/docs/graph-api/reference/achievement + * + * @return string + */ + public function getType() + { + return 'game.achievement'; + } + + /** + * Indicates whether gaining the achievement published a feed story for the user. + * + * @return boolean|null + */ + public function isNoFeedStory() + { + return $this->getField('no_feed_story'); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAlbum.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAlbum.php new file mode 100644 index 0000000..52f19b5 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAlbum.php @@ -0,0 +1,183 @@ + '\Facebook\GraphNodes\GraphUser', + 'place' => '\Facebook\GraphNodes\GraphPage', + ]; + + /** + * Returns the ID for the album. + * + * @return string|null + */ + public function getId() + { + return $this->getField('id'); + } + + /** + * Returns whether the viewer can upload photos to this album. + * + * @return boolean|null + */ + public function getCanUpload() + { + return $this->getField('can_upload'); + } + + /** + * Returns the number of photos in this album. + * + * @return int|null + */ + public function getCount() + { + return $this->getField('count'); + } + + /** + * Returns the ID of the album's cover photo. + * + * @return string|null + */ + public function getCoverPhoto() + { + return $this->getField('cover_photo'); + } + + /** + * Returns the time the album was initially created. + * + * @return \DateTime|null + */ + public function getCreatedTime() + { + return $this->getField('created_time'); + } + + /** + * Returns the time the album was updated. + * + * @return \DateTime|null + */ + public function getUpdatedTime() + { + return $this->getField('updated_time'); + } + + /** + * Returns the description of the album. + * + * @return string|null + */ + public function getDescription() + { + return $this->getField('description'); + } + + /** + * Returns profile that created the album. + * + * @return GraphUser|null + */ + public function getFrom() + { + return $this->getField('from'); + } + + /** + * Returns profile that created the album. + * + * @return GraphPage|null + */ + public function getPlace() + { + return $this->getField('place'); + } + + /** + * Returns a link to this album on Facebook. + * + * @return string|null + */ + public function getLink() + { + return $this->getField('link'); + } + + /** + * Returns the textual location of the album. + * + * @return string|null + */ + public function getLocation() + { + return $this->getField('location'); + } + + /** + * Returns the title of the album. + * + * @return string|null + */ + public function getName() + { + return $this->getField('name'); + } + + /** + * Returns the privacy settings for the album. + * + * @return string|null + */ + public function getPrivacy() + { + return $this->getField('privacy'); + } + + /** + * Returns the type of the album. + * + * enum{ profile, mobile, wall, normal, album } + * + * @return string|null + */ + public function getType() + { + return $this->getField('type'); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphApplication.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphApplication.php new file mode 100644 index 0000000..aa07c82 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphApplication.php @@ -0,0 +1,43 @@ +getField('id'); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphCoverPhoto.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphCoverPhoto.php new file mode 100644 index 0000000..824275b --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphCoverPhoto.php @@ -0,0 +1,72 @@ +getField('id'); + } + + /** + * Returns the source of cover if it exists + * + * @return string|null + */ + public function getSource() + { + return $this->getField('source'); + } + + /** + * Returns the offset_x of cover if it exists + * + * @return int|null + */ + public function getOffsetX() + { + return $this->getField('offset_x'); + } + + /** + * Returns the offset_y of cover if it exists + * + * @return int|null + */ + public function getOffsetY() + { + return $this->getField('offset_y'); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEdge.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEdge.php new file mode 100644 index 0000000..f6f4970 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEdge.php @@ -0,0 +1,252 @@ +request = $request; + $this->metaData = $metaData; + $this->parentEdgeEndpoint = $parentEdgeEndpoint; + $this->subclassName = $subclassName; + + parent::__construct($data); + } + + /** + * Gets the parent Graph edge endpoint that generated the list. + * + * @return string|null + */ + public function getParentGraphEdge() + { + return $this->parentEdgeEndpoint; + } + + /** + * Gets the subclass name that the child GraphNode's are cast as. + * + * @return string|null + */ + public function getSubClassName() + { + return $this->subclassName; + } + + /** + * Returns the raw meta data associated with this GraphEdge. + * + * @return array + */ + public function getMetaData() + { + return $this->metaData; + } + + /** + * Returns the next cursor if it exists. + * + * @return string|null + */ + public function getNextCursor() + { + return $this->getCursor('after'); + } + + /** + * Returns the previous cursor if it exists. + * + * @return string|null + */ + public function getPreviousCursor() + { + return $this->getCursor('before'); + } + + /** + * Returns the cursor for a specific direction if it exists. + * + * @param string $direction The direction of the page: after|before + * + * @return string|null + */ + public function getCursor($direction) + { + if (isset($this->metaData['paging']['cursors'][$direction])) { + return $this->metaData['paging']['cursors'][$direction]; + } + + return null; + } + + /** + * Generates a pagination URL based on a cursor. + * + * @param string $direction The direction of the page: next|previous + * + * @return string|null + * + * @throws FacebookSDKException + */ + public function getPaginationUrl($direction) + { + $this->validateForPagination(); + + // Do we have a paging URL? + if (!isset($this->metaData['paging'][$direction])) { + return null; + } + + $pageUrl = $this->metaData['paging'][$direction]; + + return FacebookUrlManipulator::baseGraphUrlEndpoint($pageUrl); + } + + /** + * Validates whether or not we can paginate on this request. + * + * @throws FacebookSDKException + */ + public function validateForPagination() + { + if ($this->request->getMethod() !== 'GET') { + throw new FacebookSDKException('You can only paginate on a GET request.', 720); + } + } + + /** + * Gets the request object needed to make a next|previous page request. + * + * @param string $direction The direction of the page: next|previous + * + * @return FacebookRequest|null + * + * @throws FacebookSDKException + */ + public function getPaginationRequest($direction) + { + $pageUrl = $this->getPaginationUrl($direction); + if (!$pageUrl) { + return null; + } + + $newRequest = clone $this->request; + $newRequest->setEndpoint($pageUrl); + + return $newRequest; + } + + /** + * Gets the request object needed to make a "next" page request. + * + * @return FacebookRequest|null + * + * @throws FacebookSDKException + */ + public function getNextPageRequest() + { + return $this->getPaginationRequest('next'); + } + + /** + * Gets the request object needed to make a "previous" page request. + * + * @return FacebookRequest|null + * + * @throws FacebookSDKException + */ + public function getPreviousPageRequest() + { + return $this->getPaginationRequest('previous'); + } + + /** + * The total number of results according to Graph if it exists. + * + * This will be returned if the summary=true modifier is present in the request. + * + * @return int|null + */ + public function getTotalCount() + { + if (isset($this->metaData['summary']['total_count'])) { + return $this->metaData['summary']['total_count']; + } + + return null; + } + + /** + * @inheritDoc + */ + public function map(\Closure $callback) + { + return new static( + $this->request, + array_map($callback, $this->items, array_keys($this->items)), + $this->metaData, + $this->parentEdgeEndpoint, + $this->subclassName + ); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEvent.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEvent.php new file mode 100644 index 0000000..a470d89 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEvent.php @@ -0,0 +1,242 @@ + '\Facebook\GraphNodes\GraphCoverPhoto', + 'place' => '\Facebook\GraphNodes\GraphPage', + 'picture' => '\Facebook\GraphNodes\GraphPicture', + 'parent_group' => '\Facebook\GraphNodes\GraphGroup', + ]; + + /** + * Returns the `id` (The event ID) as string if present. + * + * @return string|null + */ + public function getId() + { + return $this->getField('id'); + } + + /** + * Returns the `cover` (Cover picture) as GraphCoverPhoto if present. + * + * @return GraphCoverPhoto|null + */ + public function getCover() + { + return $this->getField('cover'); + } + + /** + * Returns the `description` (Long-form description) as string if present. + * + * @return string|null + */ + public function getDescription() + { + return $this->getField('description'); + } + + /** + * Returns the `end_time` (End time, if one has been set) as DateTime if present. + * + * @return \DateTime|null + */ + public function getEndTime() + { + return $this->getField('end_time'); + } + + /** + * Returns the `is_date_only` (Whether the event only has a date specified, but no time) as bool if present. + * + * @return bool|null + */ + public function getIsDateOnly() + { + return $this->getField('is_date_only'); + } + + /** + * Returns the `name` (Event name) as string if present. + * + * @return string|null + */ + public function getName() + { + return $this->getField('name'); + } + + /** + * Returns the `owner` (The profile that created the event) as GraphNode if present. + * + * @return GraphNode|null + */ + public function getOwner() + { + return $this->getField('owner'); + } + + /** + * Returns the `parent_group` (The group the event belongs to) as GraphGroup if present. + * + * @return GraphGroup|null + */ + public function getParentGroup() + { + return $this->getField('parent_group'); + } + + /** + * Returns the `place` (Event Place information) as GraphPage if present. + * + * @return GraphPage|null + */ + public function getPlace() + { + return $this->getField('place'); + } + + /** + * Returns the `privacy` (Who can see the event) as string if present. + * + * @return string|null + */ + public function getPrivacy() + { + return $this->getField('privacy'); + } + + /** + * Returns the `start_time` (Start time) as DateTime if present. + * + * @return \DateTime|null + */ + public function getStartTime() + { + return $this->getField('start_time'); + } + + /** + * Returns the `ticket_uri` (The link users can visit to buy a ticket to this event) as string if present. + * + * @return string|null + */ + public function getTicketUri() + { + return $this->getField('ticket_uri'); + } + + /** + * Returns the `timezone` (Timezone) as string if present. + * + * @return string|null + */ + public function getTimezone() + { + return $this->getField('timezone'); + } + + /** + * Returns the `updated_time` (Last update time) as DateTime if present. + * + * @return \DateTime|null + */ + public function getUpdatedTime() + { + return $this->getField('updated_time'); + } + + /** + * Returns the `picture` (Event picture) as GraphPicture if present. + * + * @return GraphPicture|null + */ + public function getPicture() + { + return $this->getField('picture'); + } + + /** + * Returns the `attending_count` (Number of people attending the event) as int if present. + * + * @return int|null + */ + public function getAttendingCount() + { + return $this->getField('attending_count'); + } + + /** + * Returns the `declined_count` (Number of people who declined the event) as int if present. + * + * @return int|null + */ + public function getDeclinedCount() + { + return $this->getField('declined_count'); + } + + /** + * Returns the `maybe_count` (Number of people who maybe going to the event) as int if present. + * + * @return int|null + */ + public function getMaybeCount() + { + return $this->getField('maybe_count'); + } + + /** + * Returns the `noreply_count` (Number of people who did not reply to the event) as int if present. + * + * @return int|null + */ + public function getNoreplyCount() + { + return $this->getField('noreply_count'); + } + + /** + * Returns the `invited_count` (Number of people invited to the event) as int if present. + * + * @return int|null + */ + public function getInvitedCount() + { + return $this->getField('invited_count'); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphGroup.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphGroup.php new file mode 100644 index 0000000..6217bd4 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphGroup.php @@ -0,0 +1,170 @@ + '\Facebook\GraphNodes\GraphCoverPhoto', + 'venue' => '\Facebook\GraphNodes\GraphLocation', + ]; + + /** + * Returns the `id` (The Group ID) as string if present. + * + * @return string|null + */ + public function getId() + { + return $this->getField('id'); + } + + /** + * Returns the `cover` (The cover photo of the Group) as GraphCoverPhoto if present. + * + * @return GraphCoverPhoto|null + */ + public function getCover() + { + return $this->getField('cover'); + } + + /** + * Returns the `description` (A brief description of the Group) as string if present. + * + * @return string|null + */ + public function getDescription() + { + return $this->getField('description'); + } + + /** + * Returns the `email` (The email address to upload content to the Group. Only current members of the Group can use this) as string if present. + * + * @return string|null + */ + public function getEmail() + { + return $this->getField('email'); + } + + /** + * Returns the `icon` (The URL for the Group's icon) as string if present. + * + * @return string|null + */ + public function getIcon() + { + return $this->getField('icon'); + } + + /** + * Returns the `link` (The Group's website) as string if present. + * + * @return string|null + */ + public function getLink() + { + return $this->getField('link'); + } + + /** + * Returns the `name` (The name of the Group) as string if present. + * + * @return string|null + */ + public function getName() + { + return $this->getField('name'); + } + + /** + * Returns the `member_request_count` (Number of people asking to join the group.) as int if present. + * + * @return int|null + */ + public function getMemberRequestCount() + { + return $this->getField('member_request_count'); + } + + /** + * Returns the `owner` (The profile that created this Group) as GraphNode if present. + * + * @return GraphNode|null + */ + public function getOwner() + { + return $this->getField('owner'); + } + + /** + * Returns the `parent` (The parent Group of this Group, if it exists) as GraphNode if present. + * + * @return GraphNode|null + */ + public function getParent() + { + return $this->getField('parent'); + } + + /** + * Returns the `privacy` (The privacy setting of the Group) as string if present. + * + * @return string|null + */ + public function getPrivacy() + { + return $this->getField('privacy'); + } + + /** + * Returns the `updated_time` (The last time the Group was updated (this includes changes in the Group's properties and changes in posts and comments if user can see them)) as \DateTime if present. + * + * @return \DateTime|null + */ + public function getUpdatedTime() + { + return $this->getField('updated_time'); + } + + /** + * Returns the `venue` (The location for the Group) as GraphLocation if present. + * + * @return GraphLocation|null + */ + public function getVenue() + { + return $this->getField('venue'); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphList.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphList.php new file mode 100644 index 0000000..3dfbd49 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphList.php @@ -0,0 +1,36 @@ +getField('street'); + } + + /** + * Returns the city component of the location + * + * @return string|null + */ + public function getCity() + { + return $this->getField('city'); + } + + /** + * Returns the state component of the location + * + * @return string|null + */ + public function getState() + { + return $this->getField('state'); + } + + /** + * Returns the country component of the location + * + * @return string|null + */ + public function getCountry() + { + return $this->getField('country'); + } + + /** + * Returns the zipcode component of the location + * + * @return string|null + */ + public function getZip() + { + return $this->getField('zip'); + } + + /** + * Returns the latitude component of the location + * + * @return float|null + */ + public function getLatitude() + { + return $this->getField('latitude'); + } + + /** + * Returns the street component of the location + * + * @return float|null + */ + public function getLongitude() + { + return $this->getField('longitude'); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNode.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNode.php new file mode 100644 index 0000000..061e744 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNode.php @@ -0,0 +1,197 @@ +castItems($data)); + } + + /** + * Iterates over an array and detects the types each node + * should be cast to and returns all the items as an array. + * + * @TODO Add auto-casting to AccessToken entities. + * + * @param array $data The array to iterate over. + * + * @return array + */ + public function castItems(array $data) + { + $items = []; + + foreach ($data as $k => $v) { + if ($this->shouldCastAsDateTime($k) + && (is_numeric($v) + || $this->isIso8601DateString($v)) + ) { + $items[$k] = $this->castToDateTime($v); + } elseif ($k === 'birthday') { + $items[$k] = $this->castToBirthday($v); + } else { + $items[$k] = $v; + } + } + + return $items; + } + + /** + * Uncasts any auto-casted datatypes. + * Basically the reverse of castItems(). + * + * @return array + */ + public function uncastItems() + { + $items = $this->asArray(); + + return array_map(function ($v) { + if ($v instanceof \DateTime) { + return $v->format(\DateTime::ISO8601); + } + + return $v; + }, $items); + } + + /** + * Get the collection of items as JSON. + * + * @param int $options + * + * @return string + */ + public function asJson($options = 0) + { + return json_encode($this->uncastItems(), $options); + } + + /** + * Detects an ISO 8601 formatted string. + * + * @param string $string + * + * @return boolean + * + * @see https://developers.facebook.com/docs/graph-api/using-graph-api/#readmodifiers + * @see http://www.cl.cam.ac.uk/~mgk25/iso-time.html + * @see http://en.wikipedia.org/wiki/ISO_8601 + */ + public function isIso8601DateString($string) + { + // This insane regex was yoinked from here: + // http://www.pelagodesign.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/ + // ...and I'm all like: + // http://thecodinglove.com/post/95378251969/when-code-works-and-i-dont-know-why + $crazyInsaneRegexThatSomehowDetectsIso8601 = '/^([\+-]?\d{4}(?!\d{2}\b))' + . '((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?' + . '|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d' + . '|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])' + . '((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d' + . '([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/'; + + return preg_match($crazyInsaneRegexThatSomehowDetectsIso8601, $string) === 1; + } + + /** + * Determines if a value from Graph should be cast to DateTime. + * + * @param string $key + * + * @return boolean + */ + public function shouldCastAsDateTime($key) + { + return in_array($key, [ + 'created_time', + 'updated_time', + 'start_time', + 'end_time', + 'backdated_time', + 'issued_at', + 'expires_at', + 'publish_time' + ], true); + } + + /** + * Casts a date value from Graph to DateTime. + * + * @param int|string $value + * + * @return \DateTime + */ + public function castToDateTime($value) + { + if (is_int($value)) { + $dt = new \DateTime(); + $dt->setTimestamp($value); + } else { + $dt = new \DateTime($value); + } + + return $dt; + } + + /** + * Casts a birthday value from Graph to Birthday + * + * @param string $value + * + * @return Birthday + */ + public function castToBirthday($value) + { + return new Birthday($value); + } + + /** + * Getter for $graphObjectMap. + * + * @return array + */ + public static function getObjectMap() + { + return static::$graphObjectMap; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php new file mode 100644 index 0000000..6a37091 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php @@ -0,0 +1,392 @@ +response = $response; + $this->decodedBody = $response->getDecodedBody(); + } + + /** + * Tries to convert a FacebookResponse entity into a GraphNode. + * + * @param string|null $subclassName The GraphNode sub class to cast to. + * + * @return GraphNode + * + * @throws FacebookSDKException + */ + public function makeGraphNode($subclassName = null) + { + $this->validateResponseAsArray(); + $this->validateResponseCastableAsGraphNode(); + + return $this->castAsGraphNodeOrGraphEdge($this->decodedBody, $subclassName); + } + + /** + * Convenience method for creating a GraphAchievement collection. + * + * @return GraphAchievement + * + * @throws FacebookSDKException + */ + public function makeGraphAchievement() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphAchievement'); + } + + /** + * Convenience method for creating a GraphAlbum collection. + * + * @return GraphAlbum + * + * @throws FacebookSDKException + */ + public function makeGraphAlbum() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphAlbum'); + } + + /** + * Convenience method for creating a GraphPage collection. + * + * @return GraphPage + * + * @throws FacebookSDKException + */ + public function makeGraphPage() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphPage'); + } + + /** + * Convenience method for creating a GraphSessionInfo collection. + * + * @return GraphSessionInfo + * + * @throws FacebookSDKException + */ + public function makeGraphSessionInfo() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphSessionInfo'); + } + + /** + * Convenience method for creating a GraphUser collection. + * + * @return GraphUser + * + * @throws FacebookSDKException + */ + public function makeGraphUser() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphUser'); + } + + /** + * Convenience method for creating a GraphEvent collection. + * + * @return GraphEvent + * + * @throws FacebookSDKException + */ + public function makeGraphEvent() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphEvent'); + } + + /** + * Convenience method for creating a GraphGroup collection. + * + * @return GraphGroup + * + * @throws FacebookSDKException + */ + public function makeGraphGroup() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphGroup'); + } + + /** + * Tries to convert a FacebookResponse entity into a GraphEdge. + * + * @param string|null $subclassName The GraphNode sub class to cast the list items to. + * @param boolean $auto_prefix Toggle to auto-prefix the subclass name. + * + * @return GraphEdge + * + * @throws FacebookSDKException + */ + public function makeGraphEdge($subclassName = null, $auto_prefix = true) + { + $this->validateResponseAsArray(); + $this->validateResponseCastableAsGraphEdge(); + + if ($subclassName && $auto_prefix) { + $subclassName = static::BASE_GRAPH_OBJECT_PREFIX . $subclassName; + } + + return $this->castAsGraphNodeOrGraphEdge($this->decodedBody, $subclassName); + } + + /** + * Validates the decoded body. + * + * @throws FacebookSDKException + */ + public function validateResponseAsArray() + { + if (!is_array($this->decodedBody)) { + throw new FacebookSDKException('Unable to get response from Graph as array.', 620); + } + } + + /** + * Validates that the return data can be cast as a GraphNode. + * + * @throws FacebookSDKException + */ + public function validateResponseCastableAsGraphNode() + { + if (isset($this->decodedBody['data']) && static::isCastableAsGraphEdge($this->decodedBody['data'])) { + throw new FacebookSDKException( + 'Unable to convert response from Graph to a GraphNode because the response looks like a GraphEdge. Try using GraphNodeFactory::makeGraphEdge() instead.', + 620 + ); + } + } + + /** + * Validates that the return data can be cast as a GraphEdge. + * + * @throws FacebookSDKException + */ + public function validateResponseCastableAsGraphEdge() + { + if (!(isset($this->decodedBody['data']) && static::isCastableAsGraphEdge($this->decodedBody['data']))) { + throw new FacebookSDKException( + 'Unable to convert response from Graph to a GraphEdge because the response does not look like a GraphEdge. Try using GraphNodeFactory::makeGraphNode() instead.', + 620 + ); + } + } + + /** + * Safely instantiates a GraphNode of $subclassName. + * + * @param array $data The array of data to iterate over. + * @param string|null $subclassName The subclass to cast this collection to. + * + * @return GraphNode + * + * @throws FacebookSDKException + */ + public function safelyMakeGraphNode(array $data, $subclassName = null) + { + $subclassName = $subclassName ?: static::BASE_GRAPH_NODE_CLASS; + static::validateSubclass($subclassName); + + // Remember the parent node ID + $parentNodeId = isset($data['id']) ? $data['id'] : null; + + $items = []; + + foreach ($data as $k => $v) { + // Array means could be recurable + if (is_array($v)) { + // Detect any smart-casting from the $graphObjectMap array. + // This is always empty on the GraphNode collection, but subclasses can define + // their own array of smart-casting types. + $graphObjectMap = $subclassName::getObjectMap(); + $objectSubClass = isset($graphObjectMap[$k]) + ? $graphObjectMap[$k] + : null; + + // Could be a GraphEdge or GraphNode + $items[$k] = $this->castAsGraphNodeOrGraphEdge($v, $objectSubClass, $k, $parentNodeId); + } else { + $items[$k] = $v; + } + } + + return new $subclassName($items); + } + + /** + * Takes an array of values and determines how to cast each node. + * + * @param array $data The array of data to iterate over. + * @param string|null $subclassName The subclass to cast this collection to. + * @param string|null $parentKey The key of this data (Graph edge). + * @param string|null $parentNodeId The parent Graph node ID. + * + * @return GraphNode|GraphEdge + * + * @throws FacebookSDKException + */ + public function castAsGraphNodeOrGraphEdge(array $data, $subclassName = null, $parentKey = null, $parentNodeId = null) + { + if (isset($data['data'])) { + // Create GraphEdge + if (static::isCastableAsGraphEdge($data['data'])) { + return $this->safelyMakeGraphEdge($data, $subclassName, $parentKey, $parentNodeId); + } + // Sometimes Graph is a weirdo and returns a GraphNode under the "data" key + $data = $data['data']; + } + + // Create GraphNode + return $this->safelyMakeGraphNode($data, $subclassName); + } + + /** + * Return an array of GraphNode's. + * + * @param array $data The array of data to iterate over. + * @param string|null $subclassName The GraphNode subclass to cast each item in the list to. + * @param string|null $parentKey The key of this data (Graph edge). + * @param string|null $parentNodeId The parent Graph node ID. + * + * @return GraphEdge + * + * @throws FacebookSDKException + */ + public function safelyMakeGraphEdge(array $data, $subclassName = null, $parentKey = null, $parentNodeId = null) + { + if (!isset($data['data'])) { + throw new FacebookSDKException('Cannot cast data to GraphEdge. Expected a "data" key.', 620); + } + + $dataList = []; + foreach ($data['data'] as $graphNode) { + $dataList[] = $this->safelyMakeGraphNode($graphNode, $subclassName); + } + + $metaData = $this->getMetaData($data); + + // We'll need to make an edge endpoint for this in case it's a GraphEdge (for cursor pagination) + $parentGraphEdgeEndpoint = $parentNodeId && $parentKey ? '/' . $parentNodeId . '/' . $parentKey : null; + $className = static::BASE_GRAPH_EDGE_CLASS; + + return new $className($this->response->getRequest(), $dataList, $metaData, $parentGraphEdgeEndpoint, $subclassName); + } + + /** + * Get the meta data from a list in a Graph response. + * + * @param array $data The Graph response. + * + * @return array + */ + public function getMetaData(array $data) + { + unset($data['data']); + + return $data; + } + + /** + * Determines whether or not the data should be cast as a GraphEdge. + * + * @param array $data + * + * @return boolean + */ + public static function isCastableAsGraphEdge(array $data) + { + if ($data === []) { + return true; + } + + // Checks for a sequential numeric array which would be a GraphEdge + return array_keys($data) === range(0, count($data) - 1); + } + + /** + * Ensures that the subclass in question is valid. + * + * @param string $subclassName The GraphNode subclass to validate. + * + * @throws FacebookSDKException + */ + public static function validateSubclass($subclassName) + { + if ($subclassName == static::BASE_GRAPH_NODE_CLASS || is_subclass_of($subclassName, static::BASE_GRAPH_NODE_CLASS)) { + return; + } + + throw new FacebookSDKException('The given subclass "' . $subclassName . '" is not valid. Cannot cast to an object that is not a GraphNode subclass.', 620); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphObject.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphObject.php new file mode 100644 index 0000000..0633c40 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphObject.php @@ -0,0 +1,36 @@ +makeGraphNode($subclassName); + } + + /** + * Convenience method for creating a GraphEvent collection. + * + * @return GraphEvent + * + * @throws FacebookSDKException + */ + public function makeGraphEvent() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphEvent'); + } + + /** + * Tries to convert a FacebookResponse entity into a GraphEdge. + * + * @param string|null $subclassName The GraphNode sub class to cast the list items to. + * @param boolean $auto_prefix Toggle to auto-prefix the subclass name. + * + * @return GraphEdge + * + * @deprecated 5.0.0 GraphObjectFactory has been renamed to GraphNodeFactory + */ + public function makeGraphList($subclassName = null, $auto_prefix = true) + { + return $this->makeGraphEdge($subclassName, $auto_prefix); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPage.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPage.php new file mode 100644 index 0000000..3dfb0e0 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPage.php @@ -0,0 +1,147 @@ + '\Facebook\GraphNodes\GraphPage', + 'global_brand_parent_page' => '\Facebook\GraphNodes\GraphPage', + 'location' => '\Facebook\GraphNodes\GraphLocation', + 'cover' => '\Facebook\GraphNodes\GraphCoverPhoto', + 'picture' => '\Facebook\GraphNodes\GraphPicture', + ]; + + /** + * Returns the ID for the user's page as a string if present. + * + * @return string|null + */ + public function getId() + { + return $this->getField('id'); + } + + /** + * Returns the Category for the user's page as a string if present. + * + * @return string|null + */ + public function getCategory() + { + return $this->getField('category'); + } + + /** + * Returns the Name of the user's page as a string if present. + * + * @return string|null + */ + public function getName() + { + return $this->getField('name'); + } + + /** + * Returns the best available Page on Facebook. + * + * @return GraphPage|null + */ + public function getBestPage() + { + return $this->getField('best_page'); + } + + /** + * Returns the brand's global (parent) Page. + * + * @return GraphPage|null + */ + public function getGlobalBrandParentPage() + { + return $this->getField('global_brand_parent_page'); + } + + /** + * Returns the location of this place. + * + * @return GraphLocation|null + */ + public function getLocation() + { + return $this->getField('location'); + } + + /** + * Returns CoverPhoto of the Page. + * + * @return GraphCoverPhoto|null + */ + public function getCover() + { + return $this->getField('cover'); + } + + /** + * Returns Picture of the Page. + * + * @return GraphPicture|null + */ + public function getPicture() + { + return $this->getField('picture'); + } + + /** + * Returns the page access token for the admin user. + * + * Only available in the `/me/accounts` context. + * + * @return string|null + */ + public function getAccessToken() + { + return $this->getField('access_token'); + } + + /** + * Returns the roles of the page admin user. + * + * Only available in the `/me/accounts` context. + * + * @return array|null + */ + public function getPerms() + { + return $this->getField('perms'); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPicture.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPicture.php new file mode 100644 index 0000000..10274ec --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPicture.php @@ -0,0 +1,72 @@ +getField('is_silhouette'); + } + + /** + * Returns the url of user picture if it exists + * + * @return string|null + */ + public function getUrl() + { + return $this->getField('url'); + } + + /** + * Returns the width of user picture if it exists + * + * @return int|null + */ + public function getWidth() + { + return $this->getField('width'); + } + + /** + * Returns the height of user picture if it exists + * + * @return int|null + */ + public function getHeight() + { + return $this->getField('height'); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphSessionInfo.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphSessionInfo.php new file mode 100644 index 0000000..df8dd35 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphSessionInfo.php @@ -0,0 +1,102 @@ +getField('app_id'); + } + + /** + * Returns the application name the token was issued for. + * + * @return string|null + */ + public function getApplication() + { + return $this->getField('application'); + } + + /** + * Returns the date & time that the token expires. + * + * @return \DateTime|null + */ + public function getExpiresAt() + { + return $this->getField('expires_at'); + } + + /** + * Returns whether the token is valid. + * + * @return boolean + */ + public function getIsValid() + { + return $this->getField('is_valid'); + } + + /** + * Returns the date & time the token was issued at. + * + * @return \DateTime|null + */ + public function getIssuedAt() + { + return $this->getField('issued_at'); + } + + /** + * Returns the scope permissions associated with the token. + * + * @return array + */ + public function getScopes() + { + return $this->getField('scopes'); + } + + /** + * Returns the login id of the user associated with the token. + * + * @return string|null + */ + public function getUserId() + { + return $this->getField('user_id'); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphUser.php b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphUser.php new file mode 100644 index 0000000..6e1ed8f --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphUser.php @@ -0,0 +1,172 @@ + '\Facebook\GraphNodes\GraphPage', + 'location' => '\Facebook\GraphNodes\GraphPage', + 'significant_other' => '\Facebook\GraphNodes\GraphUser', + 'picture' => '\Facebook\GraphNodes\GraphPicture', + ]; + + /** + * Returns the ID for the user as a string if present. + * + * @return string|null + */ + public function getId() + { + return $this->getField('id'); + } + + /** + * Returns the name for the user as a string if present. + * + * @return string|null + */ + public function getName() + { + return $this->getField('name'); + } + + /** + * Returns the first name for the user as a string if present. + * + * @return string|null + */ + public function getFirstName() + { + return $this->getField('first_name'); + } + + /** + * Returns the middle name for the user as a string if present. + * + * @return string|null + */ + public function getMiddleName() + { + return $this->getField('middle_name'); + } + + /** + * Returns the last name for the user as a string if present. + * + * @return string|null + */ + public function getLastName() + { + return $this->getField('last_name'); + } + + /** + * Returns the email for the user as a string if present. + * + * @return string|null + */ + public function getEmail() + { + return $this->getField('email'); + } + + /** + * Returns the gender for the user as a string if present. + * + * @return string|null + */ + public function getGender() + { + return $this->getField('gender'); + } + + /** + * Returns the Facebook URL for the user as a string if available. + * + * @return string|null + */ + public function getLink() + { + return $this->getField('link'); + } + + /** + * Returns the users birthday, if available. + * + * @return Birthday|null + */ + public function getBirthday() + { + return $this->getField('birthday'); + } + + /** + * Returns the current location of the user as a GraphPage. + * + * @return GraphPage|null + */ + public function getLocation() + { + return $this->getField('location'); + } + + /** + * Returns the current location of the user as a GraphPage. + * + * @return GraphPage|null + */ + public function getHometown() + { + return $this->getField('hometown'); + } + + /** + * Returns the current location of the user as a GraphUser. + * + * @return GraphUser|null + */ + public function getSignificantOther() + { + return $this->getField('significant_other'); + } + + /** + * Returns the picture of the user as a GraphPicture + * + * @return GraphPicture|null + */ + public function getPicture() + { + return $this->getField('picture'); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookCanvasHelper.php b/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookCanvasHelper.php new file mode 100644 index 0000000..7f3466f --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookCanvasHelper.php @@ -0,0 +1,52 @@ +signedRequest ? $this->signedRequest->get('app_data') : null; + } + + /** + * Get raw signed request from POST. + * + * @return string|null + */ + public function getRawSignedRequest() + { + return $this->getRawSignedRequestFromPost() ?: null; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookJavaScriptHelper.php b/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookJavaScriptHelper.php new file mode 100644 index 0000000..01a76b8 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookJavaScriptHelper.php @@ -0,0 +1,42 @@ +getRawSignedRequestFromCookie(); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookPageTabHelper.php b/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookPageTabHelper.php new file mode 100644 index 0000000..da2c356 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookPageTabHelper.php @@ -0,0 +1,95 @@ +signedRequest) { + return; + } + + $this->pageData = $this->signedRequest->get('page'); + } + + /** + * Returns a value from the page data. + * + * @param string $key + * @param mixed|null $default + * + * @return mixed|null + */ + public function getPageData($key, $default = null) + { + if (isset($this->pageData[$key])) { + return $this->pageData[$key]; + } + + return $default; + } + + /** + * Returns true if the user is an admin. + * + * @return boolean + */ + public function isAdmin() + { + return $this->getPageData('admin') === true; + } + + /** + * Returns the page id if available. + * + * @return string|null + */ + public function getPageId() + { + return $this->getPageData('id'); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookRedirectLoginHelper.php b/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookRedirectLoginHelper.php new file mode 100644 index 0000000..3240ba8 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookRedirectLoginHelper.php @@ -0,0 +1,333 @@ +oAuth2Client = $oAuth2Client; + $this->persistentDataHandler = $persistentDataHandler ?: new FacebookSessionPersistentDataHandler(); + $this->urlDetectionHandler = $urlHandler ?: new FacebookUrlDetectionHandler(); + $this->pseudoRandomStringGenerator = PseudoRandomStringGeneratorFactory::createPseudoRandomStringGenerator($prsg); + } + + /** + * Returns the persistent data handler. + * + * @return PersistentDataInterface + */ + public function getPersistentDataHandler() + { + return $this->persistentDataHandler; + } + + /** + * Returns the URL detection handler. + * + * @return UrlDetectionInterface + */ + public function getUrlDetectionHandler() + { + return $this->urlDetectionHandler; + } + + /** + * Returns the cryptographically secure pseudo-random string generator. + * + * @return PseudoRandomStringGeneratorInterface + */ + public function getPseudoRandomStringGenerator() + { + return $this->pseudoRandomStringGenerator; + } + + /** + * Stores CSRF state and returns a URL to which the user should be sent to in order to continue the login process with Facebook. + * + * @param string $redirectUrl The URL Facebook should redirect users to after login. + * @param array $scope List of permissions to request during login. + * @param array $params An array of parameters to generate URL. + * @param string $separator The separator to use in http_build_query(). + * + * @return string + */ + private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&') + { + $state = $this->persistentDataHandler->get('state') ?: $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH); + $this->persistentDataHandler->set('state', $state); + + return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator); + } + + /** + * Returns the URL to send the user in order to login to Facebook. + * + * @param string $redirectUrl The URL Facebook should redirect users to after login. + * @param array $scope List of permissions to request during login. + * @param string $separator The separator to use in http_build_query(). + * + * @return string + */ + public function getLoginUrl($redirectUrl, array $scope = [], $separator = '&') + { + return $this->makeUrl($redirectUrl, $scope, [], $separator); + } + + /** + * Returns the URL to send the user in order to log out of Facebook. + * + * @param AccessToken|string $accessToken The access token that will be logged out. + * @param string $next The url Facebook should redirect the user to after a successful logout. + * @param string $separator The separator to use in http_build_query(). + * + * @return string + * + * @throws FacebookSDKException + */ + public function getLogoutUrl($accessToken, $next, $separator = '&') + { + if (!$accessToken instanceof AccessToken) { + $accessToken = new AccessToken($accessToken); + } + + if ($accessToken->isAppAccessToken()) { + throw new FacebookSDKException('Cannot generate a logout URL with an app access token.', 722); + } + + $params = [ + 'next' => $next, + 'access_token' => $accessToken->getValue(), + ]; + + return 'https://www.facebook.com/logout.php?' . http_build_query($params, null, $separator); + } + + /** + * Returns the URL to send the user in order to login to Facebook with permission(s) to be re-asked. + * + * @param string $redirectUrl The URL Facebook should redirect users to after login. + * @param array $scope List of permissions to request during login. + * @param string $separator The separator to use in http_build_query(). + * + * @return string + */ + public function getReRequestUrl($redirectUrl, array $scope = [], $separator = '&') + { + $params = ['auth_type' => 'rerequest']; + + return $this->makeUrl($redirectUrl, $scope, $params, $separator); + } + + /** + * Returns the URL to send the user in order to login to Facebook with user to be re-authenticated. + * + * @param string $redirectUrl The URL Facebook should redirect users to after login. + * @param array $scope List of permissions to request during login. + * @param string $separator The separator to use in http_build_query(). + * + * @return string + */ + public function getReAuthenticationUrl($redirectUrl, array $scope = [], $separator = '&') + { + $params = ['auth_type' => 'reauthenticate']; + + return $this->makeUrl($redirectUrl, $scope, $params, $separator); + } + + /** + * Takes a valid code from a login redirect, and returns an AccessToken entity. + * + * @param string|null $redirectUrl The redirect URL. + * + * @return AccessToken|null + * + * @throws FacebookSDKException + */ + public function getAccessToken($redirectUrl = null) + { + if (!$code = $this->getCode()) { + return null; + } + + $this->validateCsrf(); + $this->resetCsrf(); + + $redirectUrl = $redirectUrl ?: $this->urlDetectionHandler->getCurrentUrl(); + // At minimum we need to remove the 'state' and 'code' params + $redirectUrl = FacebookUrlManipulator::removeParamsFromUrl($redirectUrl, ['code', 'state']); + + return $this->oAuth2Client->getAccessTokenFromCode($code, $redirectUrl); + } + + /** + * Validate the request against a cross-site request forgery. + * + * @throws FacebookSDKException + */ + protected function validateCsrf() + { + $state = $this->getState(); + if (!$state) { + throw new FacebookSDKException('Cross-site request forgery validation failed. Required GET param "state" missing.'); + } + $savedState = $this->persistentDataHandler->get('state'); + if (!$savedState) { + throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing from persistent data.'); + } + + if (\hash_equals($savedState, $state)) { + return; + } + + throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.'); + } + + /** + * Resets the CSRF so that it doesn't get reused. + */ + private function resetCsrf() + { + $this->persistentDataHandler->set('state', null); + } + + /** + * Return the code. + * + * @return string|null + */ + protected function getCode() + { + return $this->getInput('code'); + } + + /** + * Return the state. + * + * @return string|null + */ + protected function getState() + { + return $this->getInput('state'); + } + + /** + * Return the error code. + * + * @return string|null + */ + public function getErrorCode() + { + return $this->getInput('error_code'); + } + + /** + * Returns the error. + * + * @return string|null + */ + public function getError() + { + return $this->getInput('error'); + } + + /** + * Returns the error reason. + * + * @return string|null + */ + public function getErrorReason() + { + return $this->getInput('error_reason'); + } + + /** + * Returns the error description. + * + * @return string|null + */ + public function getErrorDescription() + { + return $this->getInput('error_description'); + } + + /** + * Returns a value from a GET param. + * + * @param string $key + * + * @return string|null + */ + private function getInput($key) + { + return isset($_GET[$key]) ? $_GET[$key] : null; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookSignedRequestFromInputHelper.php b/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookSignedRequestFromInputHelper.php new file mode 100644 index 0000000..4044da1 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookSignedRequestFromInputHelper.php @@ -0,0 +1,166 @@ +app = $app; + $graphVersion = $graphVersion ?: Facebook::DEFAULT_GRAPH_VERSION; + $this->oAuth2Client = new OAuth2Client($this->app, $client, $graphVersion); + + $this->instantiateSignedRequest(); + } + + /** + * Instantiates a new SignedRequest entity. + * + * @param string|null + */ + public function instantiateSignedRequest($rawSignedRequest = null) + { + $rawSignedRequest = $rawSignedRequest ?: $this->getRawSignedRequest(); + + if (!$rawSignedRequest) { + return; + } + + $this->signedRequest = new SignedRequest($this->app, $rawSignedRequest); + } + + /** + * Returns an AccessToken entity from the signed request. + * + * @return AccessToken|null + * + * @throws \Facebook\Exceptions\FacebookSDKException + */ + public function getAccessToken() + { + if ($this->signedRequest && $this->signedRequest->hasOAuthData()) { + $code = $this->signedRequest->get('code'); + $accessToken = $this->signedRequest->get('oauth_token'); + + if ($code && !$accessToken) { + return $this->oAuth2Client->getAccessTokenFromCode($code); + } + + $expiresAt = $this->signedRequest->get('expires', 0); + + return new AccessToken($accessToken, $expiresAt); + } + + return null; + } + + /** + * Returns the SignedRequest entity. + * + * @return SignedRequest|null + */ + public function getSignedRequest() + { + return $this->signedRequest; + } + + /** + * Returns the user_id if available. + * + * @return string|null + */ + public function getUserId() + { + return $this->signedRequest ? $this->signedRequest->getUserId() : null; + } + + /** + * Get raw signed request from input. + * + * @return string|null + */ + abstract public function getRawSignedRequest(); + + /** + * Get raw signed request from POST input. + * + * @return string|null + */ + public function getRawSignedRequestFromPost() + { + if (isset($_POST['signed_request'])) { + return $_POST['signed_request']; + } + + return null; + } + + /** + * Get raw signed request from cookie set from the Javascript SDK. + * + * @return string|null + */ + public function getRawSignedRequestFromCookie() + { + if (isset($_COOKIE['fbsr_' . $this->app->getId()])) { + return $_COOKIE['fbsr_' . $this->app->getId()]; + } + + return null; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Http/GraphRawResponse.php b/vendor/facebook/graph-sdk/src/Facebook/Http/GraphRawResponse.php new file mode 100644 index 0000000..d1a7241 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Http/GraphRawResponse.php @@ -0,0 +1,137 @@ +httpResponseCode = (int)$httpStatusCode; + } + + if (is_array($headers)) { + $this->headers = $headers; + } else { + $this->setHeadersFromString($headers); + } + + $this->body = $body; + } + + /** + * Return the response headers. + * + * @return array + */ + public function getHeaders() + { + return $this->headers; + } + + /** + * Return the body of the response. + * + * @return string + */ + public function getBody() + { + return $this->body; + } + + /** + * Return the HTTP response code. + * + * @return int + */ + public function getHttpResponseCode() + { + return $this->httpResponseCode; + } + + /** + * Sets the HTTP response code from a raw header. + * + * @param string $rawResponseHeader + */ + public function setHttpResponseCodeFromHeader($rawResponseHeader) + { + preg_match('|HTTP/\d\.\d\s+(\d+)\s+.*|', $rawResponseHeader, $match); + $this->httpResponseCode = (int)$match[1]; + } + + /** + * Parse the raw headers and set as an array. + * + * @param string $rawHeaders The raw headers from the response. + */ + protected function setHeadersFromString($rawHeaders) + { + // Normalize line breaks + $rawHeaders = str_replace("\r\n", "\n", $rawHeaders); + + // There will be multiple headers if a 301 was followed + // or a proxy was followed, etc + $headerCollection = explode("\n\n", trim($rawHeaders)); + // We just want the last response (at the end) + $rawHeader = array_pop($headerCollection); + + $headerComponents = explode("\n", $rawHeader); + foreach ($headerComponents as $line) { + if (strpos($line, ': ') === false) { + $this->setHttpResponseCodeFromHeader($line); + } else { + list($key, $value) = explode(': ', $line, 2); + $this->headers[$key] = $value; + } + } + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyInterface.php b/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyInterface.php new file mode 100644 index 0000000..1c03f4f --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyInterface.php @@ -0,0 +1,39 @@ +params = $params; + $this->files = $files; + $this->boundary = $boundary ?: uniqid(); + } + + /** + * @inheritdoc + */ + public function getBody() + { + $body = ''; + + // Compile normal params + $params = $this->getNestedParams($this->params); + foreach ($params as $k => $v) { + $body .= $this->getParamString($k, $v); + } + + // Compile files + foreach ($this->files as $k => $v) { + $body .= $this->getFileString($k, $v); + } + + // Peace out + $body .= "--{$this->boundary}--\r\n"; + + return $body; + } + + /** + * Get the boundary + * + * @return string + */ + public function getBoundary() + { + return $this->boundary; + } + + /** + * Get the string needed to transfer a file. + * + * @param string $name + * @param FacebookFile $file + * + * @return string + */ + private function getFileString($name, FacebookFile $file) + { + return sprintf( + "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"%s\r\n\r\n%s\r\n", + $this->boundary, + $name, + $file->getFileName(), + $this->getFileHeaders($file), + $file->getContents() + ); + } + + /** + * Get the string needed to transfer a POST field. + * + * @param string $name + * @param string $value + * + * @return string + */ + private function getParamString($name, $value) + { + return sprintf( + "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n", + $this->boundary, + $name, + $value + ); + } + + /** + * Returns the params as an array of nested params. + * + * @param array $params + * + * @return array + */ + private function getNestedParams(array $params) + { + $query = http_build_query($params, null, '&'); + $params = explode('&', $query); + $result = []; + + foreach ($params as $param) { + list($key, $value) = explode('=', $param, 2); + $result[urldecode($key)] = urldecode($value); + } + + return $result; + } + + /** + * Get the headers needed before transferring the content of a POST file. + * + * @param FacebookFile $file + * + * @return string + */ + protected function getFileHeaders(FacebookFile $file) + { + return "\r\nContent-Type: {$file->getMimetype()}"; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyUrlEncoded.php b/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyUrlEncoded.php new file mode 100644 index 0000000..c1e35f4 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyUrlEncoded.php @@ -0,0 +1,55 @@ +params = $params; + } + + /** + * @inheritdoc + */ + public function getBody() + { + return http_build_query($this->params, null, '&'); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurl.php b/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurl.php new file mode 100644 index 0000000..28e4ba5 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurl.php @@ -0,0 +1,129 @@ +curl = curl_init(); + } + + /** + * Set a curl option + * + * @param $key + * @param $value + */ + public function setopt($key, $value) + { + curl_setopt($this->curl, $key, $value); + } + + /** + * Set an array of options to a curl resource + * + * @param array $options + */ + public function setoptArray(array $options) + { + curl_setopt_array($this->curl, $options); + } + + /** + * Send a curl request + * + * @return mixed + */ + public function exec() + { + return curl_exec($this->curl); + } + + /** + * Return the curl error number + * + * @return int + */ + public function errno() + { + return curl_errno($this->curl); + } + + /** + * Return the curl error message + * + * @return string + */ + public function error() + { + return curl_error($this->curl); + } + + /** + * Get info from a curl reference + * + * @param $type + * + * @return mixed + */ + public function getinfo($type) + { + return curl_getinfo($this->curl, $type); + } + + /** + * Get the currently installed curl version + * + * @return array + */ + public function version() + { + return curl_version(); + } + + /** + * Close the resource connection to curl + */ + public function close() + { + curl_close($this->curl); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurlHttpClient.php b/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurlHttpClient.php new file mode 100644 index 0000000..9516cc8 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurlHttpClient.php @@ -0,0 +1,163 @@ +facebookCurl = $facebookCurl ?: new FacebookCurl(); + } + + /** + * @inheritdoc + */ + public function send($url, $method, $body, array $headers, $timeOut) + { + $this->openConnection($url, $method, $body, $headers, $timeOut); + $this->sendRequest(); + + if ($curlErrorCode = $this->facebookCurl->errno()) { + throw new FacebookSDKException($this->facebookCurl->error(), $curlErrorCode); + } + + // Separate the raw headers from the raw body + list($rawHeaders, $rawBody) = $this->extractResponseHeadersAndBody(); + + $this->closeConnection(); + + return new GraphRawResponse($rawHeaders, $rawBody); + } + + /** + * Opens a new curl connection. + * + * @param string $url The endpoint to send the request to. + * @param string $method The request method. + * @param string $body The body of the request. + * @param array $headers The request headers. + * @param int $timeOut The timeout in seconds for the request. + */ + public function openConnection($url, $method, $body, array $headers, $timeOut) + { + $options = [ + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_HTTPHEADER => $this->compileRequestHeaders($headers), + CURLOPT_URL => $url, + CURLOPT_CONNECTTIMEOUT => 10, + CURLOPT_TIMEOUT => $timeOut, + CURLOPT_RETURNTRANSFER => true, // Return response as string + CURLOPT_HEADER => true, // Enable header processing + CURLOPT_SSL_VERIFYHOST => 2, + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_CAINFO => __DIR__ . '/certs/DigiCertHighAssuranceEVRootCA.pem', + ]; + + if ($method !== "GET") { + $options[CURLOPT_POSTFIELDS] = $body; + } + + $this->facebookCurl->init(); + $this->facebookCurl->setoptArray($options); + } + + /** + * Closes an existing curl connection + */ + public function closeConnection() + { + $this->facebookCurl->close(); + } + + /** + * Send the request and get the raw response from curl + */ + public function sendRequest() + { + $this->rawResponse = $this->facebookCurl->exec(); + } + + /** + * Compiles the request headers into a curl-friendly format. + * + * @param array $headers The request headers. + * + * @return array + */ + public function compileRequestHeaders(array $headers) + { + $return = []; + + foreach ($headers as $key => $value) { + $return[] = $key . ': ' . $value; + } + + return $return; + } + + /** + * Extracts the headers and the body into a two-part array + * + * @return array + */ + public function extractResponseHeadersAndBody() + { + $parts = explode("\r\n\r\n", $this->rawResponse); + $rawBody = array_pop($parts); + $rawHeaders = implode("\r\n\r\n", $parts); + + return [trim($rawHeaders), trim($rawBody)]; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookGuzzleHttpClient.php b/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookGuzzleHttpClient.php new file mode 100644 index 0000000..8feb7cb --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookGuzzleHttpClient.php @@ -0,0 +1,97 @@ +guzzleClient = $guzzleClient ?: new Client(); + } + + /** + * @inheritdoc + */ + public function send($url, $method, $body, array $headers, $timeOut) + { + $options = [ + 'headers' => $headers, + 'body' => $body, + 'timeout' => $timeOut, + 'connect_timeout' => 10, + 'verify' => __DIR__ . '/certs/DigiCertHighAssuranceEVRootCA.pem', + ]; + $request = $this->guzzleClient->createRequest($method, $url, $options); + + try { + $rawResponse = $this->guzzleClient->send($request); + } catch (RequestException $e) { + $rawResponse = $e->getResponse(); + + if ($e->getPrevious() instanceof RingException || !$rawResponse instanceof ResponseInterface) { + throw new FacebookSDKException($e->getMessage(), $e->getCode()); + } + } + + $rawHeaders = $this->getHeadersAsString($rawResponse); + $rawBody = $rawResponse->getBody(); + $httpStatusCode = $rawResponse->getStatusCode(); + + return new GraphRawResponse($rawHeaders, $rawBody, $httpStatusCode); + } + + /** + * Returns the Guzzle array of headers as a string. + * + * @param ResponseInterface $response The Guzzle response. + * + * @return string + */ + public function getHeadersAsString(ResponseInterface $response) + { + $headers = $response->getHeaders(); + $rawHeaders = []; + foreach ($headers as $name => $values) { + $rawHeaders[] = $name . ": " . implode(", ", $values); + } + + return implode("\r\n", $rawHeaders); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookHttpClientInterface.php b/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookHttpClientInterface.php new file mode 100644 index 0000000..1fbf953 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookHttpClientInterface.php @@ -0,0 +1,47 @@ +stream = stream_context_create($options); + } + + /** + * The response headers from the stream wrapper + * + * @return array + */ + public function getResponseHeaders() + { + return $this->responseHeaders; + } + + /** + * Send a stream wrapped request + * + * @param string $url + * + * @return mixed + */ + public function fileGetContents($url) + { + $rawResponse = file_get_contents($url, false, $this->stream); + $this->responseHeaders = $http_response_header ?: []; + + return $rawResponse; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookStreamHttpClient.php b/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookStreamHttpClient.php new file mode 100644 index 0000000..1cdfd53 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookStreamHttpClient.php @@ -0,0 +1,94 @@ +facebookStream = $facebookStream ?: new FacebookStream(); + } + + /** + * @inheritdoc + */ + public function send($url, $method, $body, array $headers, $timeOut) + { + $options = [ + 'http' => [ + 'method' => $method, + 'header' => $this->compileHeader($headers), + 'content' => $body, + 'timeout' => $timeOut, + 'ignore_errors' => true + ], + 'ssl' => [ + 'verify_peer' => true, + 'verify_peer_name' => true, + 'allow_self_signed' => true, // All root certificates are self-signed + 'cafile' => __DIR__ . '/certs/DigiCertHighAssuranceEVRootCA.pem', + ], + ]; + + $this->facebookStream->streamContextCreate($options); + $rawBody = $this->facebookStream->fileGetContents($url); + $rawHeaders = $this->facebookStream->getResponseHeaders(); + + if ($rawBody === false || empty($rawHeaders)) { + throw new FacebookSDKException('Stream returned an empty response', 660); + } + + $rawHeaders = implode("\r\n", $rawHeaders); + + return new GraphRawResponse($rawHeaders, $rawBody); + } + + /** + * Formats the headers for use in the stream wrapper. + * + * @param array $headers The request headers. + * + * @return string + */ + public function compileHeader(array $headers) + { + $header = []; + foreach ($headers as $k => $v) { + $header[] = $k . ': ' . $v; + } + + return implode("\r\n", $header); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/HttpClients/HttpClientsFactory.php b/vendor/facebook/graph-sdk/src/Facebook/HttpClients/HttpClientsFactory.php new file mode 100644 index 0000000..d9f2a8d --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/HttpClients/HttpClientsFactory.php @@ -0,0 +1,99 @@ +sessionData[$key]) ? $this->sessionData[$key] : null; + } + + /** + * @inheritdoc + */ + public function set($key, $value) + { + $this->sessionData[$key] = $value; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/PersistentData/FacebookSessionPersistentDataHandler.php b/vendor/facebook/graph-sdk/src/Facebook/PersistentData/FacebookSessionPersistentDataHandler.php new file mode 100644 index 0000000..9123e3d --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/PersistentData/FacebookSessionPersistentDataHandler.php @@ -0,0 +1,76 @@ +sessionPrefix . $key])) { + return $_SESSION[$this->sessionPrefix . $key]; + } + + return null; + } + + /** + * @inheritdoc + */ + public function set($key, $value) + { + $_SESSION[$this->sessionPrefix . $key] = $value; + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/PersistentData/PersistentDataFactory.php b/vendor/facebook/graph-sdk/src/Facebook/PersistentData/PersistentDataFactory.php new file mode 100644 index 0000000..18fb8fd --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/PersistentData/PersistentDataFactory.php @@ -0,0 +1,65 @@ +validateLength($length); + + $binaryString = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); + + if ($binaryString === false) { + throw new FacebookSDKException( + static::ERROR_MESSAGE . + 'mcrypt_create_iv() returned an error.' + ); + } + + return $this->binToHex($binaryString, $length); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/OpenSslPseudoRandomStringGenerator.php b/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/OpenSslPseudoRandomStringGenerator.php new file mode 100644 index 0000000..4b4276d --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/OpenSslPseudoRandomStringGenerator.php @@ -0,0 +1,67 @@ +validateLength($length); + + $wasCryptographicallyStrong = false; + $binaryString = openssl_random_pseudo_bytes($length, $wasCryptographicallyStrong); + + if ($binaryString === false) { + throw new FacebookSDKException(static::ERROR_MESSAGE . 'openssl_random_pseudo_bytes() returned an unknown error.'); + } + + if ($wasCryptographicallyStrong !== true) { + throw new FacebookSDKException(static::ERROR_MESSAGE . 'openssl_random_pseudo_bytes() returned a pseudo-random string but it was not cryptographically secure and cannot be used.'); + } + + return $this->binToHex($binaryString, $length); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorFactory.php b/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorFactory.php new file mode 100644 index 0000000..412f481 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorFactory.php @@ -0,0 +1,101 @@ +validateLength($length); + + return $this->binToHex(random_bytes($length), $length); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/UrandomPseudoRandomStringGenerator.php b/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/UrandomPseudoRandomStringGenerator.php new file mode 100644 index 0000000..5ab434e --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/UrandomPseudoRandomStringGenerator.php @@ -0,0 +1,89 @@ +validateLength($length); + + $stream = fopen('/dev/urandom', 'rb'); + if (!is_resource($stream)) { + throw new FacebookSDKException( + static::ERROR_MESSAGE . + 'Unable to open stream to /dev/urandom.' + ); + } + + if (!defined('HHVM_VERSION')) { + stream_set_read_buffer($stream, 0); + } + + $binaryString = fread($stream, $length); + fclose($stream); + + if (!$binaryString) { + throw new FacebookSDKException( + static::ERROR_MESSAGE . + 'Stream to /dev/urandom returned no data.' + ); + } + + return $this->binToHex($binaryString, $length); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/SignedRequest.php b/vendor/facebook/graph-sdk/src/Facebook/SignedRequest.php new file mode 100644 index 0000000..6a175a0 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/SignedRequest.php @@ -0,0 +1,326 @@ +app = $facebookApp; + + if (!$rawSignedRequest) { + return; + } + + $this->rawSignedRequest = $rawSignedRequest; + + $this->parse(); + } + + /** + * Returns the raw signed request data. + * + * @return string|null + */ + public function getRawSignedRequest() + { + return $this->rawSignedRequest; + } + + /** + * Returns the parsed signed request data. + * + * @return array|null + */ + public function getPayload() + { + return $this->payload; + } + + /** + * Returns a property from the signed request data if available. + * + * @param string $key + * @param mixed|null $default + * + * @return mixed|null + */ + public function get($key, $default = null) + { + if (isset($this->payload[$key])) { + return $this->payload[$key]; + } + + return $default; + } + + /** + * Returns user_id from signed request data if available. + * + * @return string|null + */ + public function getUserId() + { + return $this->get('user_id'); + } + + /** + * Checks for OAuth data in the payload. + * + * @return boolean + */ + public function hasOAuthData() + { + return $this->get('oauth_token') || $this->get('code'); + } + + /** + * Creates a signed request from an array of data. + * + * @param array $payload + * + * @return string + */ + public function make(array $payload) + { + $payload['algorithm'] = isset($payload['algorithm']) ? $payload['algorithm'] : 'HMAC-SHA256'; + $payload['issued_at'] = isset($payload['issued_at']) ? $payload['issued_at'] : time(); + $encodedPayload = $this->base64UrlEncode(json_encode($payload)); + + $hashedSig = $this->hashSignature($encodedPayload); + $encodedSig = $this->base64UrlEncode($hashedSig); + + return $encodedSig . '.' . $encodedPayload; + } + + /** + * Validates and decodes a signed request and saves + * the payload to an array. + */ + protected function parse() + { + list($encodedSig, $encodedPayload) = $this->split(); + + // Signature validation + $sig = $this->decodeSignature($encodedSig); + $hashedSig = $this->hashSignature($encodedPayload); + $this->validateSignature($hashedSig, $sig); + + $this->payload = $this->decodePayload($encodedPayload); + + // Payload validation + $this->validateAlgorithm(); + } + + /** + * Splits a raw signed request into signature and payload. + * + * @return array + * + * @throws FacebookSDKException + */ + protected function split() + { + if (strpos($this->rawSignedRequest, '.') === false) { + throw new FacebookSDKException('Malformed signed request.', 606); + } + + return explode('.', $this->rawSignedRequest, 2); + } + + /** + * Decodes the raw signature from a signed request. + * + * @param string $encodedSig + * + * @return string + * + * @throws FacebookSDKException + */ + protected function decodeSignature($encodedSig) + { + $sig = $this->base64UrlDecode($encodedSig); + + if (!$sig) { + throw new FacebookSDKException('Signed request has malformed encoded signature data.', 607); + } + + return $sig; + } + + /** + * Decodes the raw payload from a signed request. + * + * @param string $encodedPayload + * + * @return array + * + * @throws FacebookSDKException + */ + protected function decodePayload($encodedPayload) + { + $payload = $this->base64UrlDecode($encodedPayload); + + if ($payload) { + $payload = json_decode($payload, true); + } + + if (!is_array($payload)) { + throw new FacebookSDKException('Signed request has malformed encoded payload data.', 607); + } + + return $payload; + } + + /** + * Validates the algorithm used in a signed request. + * + * @throws FacebookSDKException + */ + protected function validateAlgorithm() + { + if ($this->get('algorithm') !== 'HMAC-SHA256') { + throw new FacebookSDKException('Signed request is using the wrong algorithm.', 605); + } + } + + /** + * Hashes the signature used in a signed request. + * + * @param string $encodedData + * + * @return string + * + * @throws FacebookSDKException + */ + protected function hashSignature($encodedData) + { + $hashedSig = hash_hmac( + 'sha256', + $encodedData, + $this->app->getSecret(), + $raw_output = true + ); + + if (!$hashedSig) { + throw new FacebookSDKException('Unable to hash signature from encoded payload data.', 602); + } + + return $hashedSig; + } + + /** + * Validates the signature used in a signed request. + * + * @param string $hashedSig + * @param string $sig + * + * @throws FacebookSDKException + */ + protected function validateSignature($hashedSig, $sig) + { + if (\hash_equals($hashedSig, $sig)) { + return; + } + + throw new FacebookSDKException('Signed request has an invalid signature.', 602); + } + + /** + * Base64 decoding which replaces characters: + * + instead of - + * / instead of _ + * + * @link http://en.wikipedia.org/wiki/Base64#URL_applications + * + * @param string $input base64 url encoded input + * + * @return string decoded string + */ + public function base64UrlDecode($input) + { + $urlDecodedBase64 = strtr($input, '-_', '+/'); + $this->validateBase64($urlDecodedBase64); + + return base64_decode($urlDecodedBase64); + } + + /** + * Base64 encoding which replaces characters: + * + instead of - + * / instead of _ + * + * @link http://en.wikipedia.org/wiki/Base64#URL_applications + * + * @param string $input string to encode + * + * @return string base64 url encoded input + */ + public function base64UrlEncode($input) + { + return strtr(base64_encode($input), '+/', '-_'); + } + + /** + * Validates a base64 string. + * + * @param string $input base64 value to validate + * + * @throws FacebookSDKException + */ + protected function validateBase64($input) + { + if (!preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $input)) { + throw new FacebookSDKException('Signed request contains malformed base64 encoding.', 608); + } + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlDetectionHandler.php b/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlDetectionHandler.php new file mode 100644 index 0000000..1d134dd --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlDetectionHandler.php @@ -0,0 +1,182 @@ +getHttpScheme() . '://' . $this->getHostName() . $this->getServerVar('REQUEST_URI'); + } + + /** + * Get the currently active URL scheme. + * + * @return string + */ + protected function getHttpScheme() + { + return $this->isBehindSsl() ? 'https' : 'http'; + } + + /** + * Tries to detect if the server is running behind an SSL. + * + * @return boolean + */ + protected function isBehindSsl() + { + // Check for proxy first + $protocol = $this->getHeader('X_FORWARDED_PROTO'); + if ($protocol) { + return $this->protocolWithActiveSsl($protocol); + } + + $protocol = $this->getServerVar('HTTPS'); + if ($protocol) { + return $this->protocolWithActiveSsl($protocol); + } + + return (string)$this->getServerVar('SERVER_PORT') === '443'; + } + + /** + * Detects an active SSL protocol value. + * + * @param string $protocol + * + * @return boolean + */ + protected function protocolWithActiveSsl($protocol) + { + $protocol = strtolower((string)$protocol); + + return in_array($protocol, ['on', '1', 'https', 'ssl'], true); + } + + /** + * Tries to detect the host name of the server. + * + * Some elements adapted from + * + * @see https://github.com/symfony/HttpFoundation/blob/master/Request.php + * + * @return string + */ + protected function getHostName() + { + // Check for proxy first + $header = $this->getHeader('X_FORWARDED_HOST'); + if ($header && $this->isValidForwardedHost($header)) { + $elements = explode(',', $header); + $host = $elements[count($elements) - 1]; + } elseif (!$host = $this->getHeader('HOST')) { + if (!$host = $this->getServerVar('SERVER_NAME')) { + $host = $this->getServerVar('SERVER_ADDR'); + } + } + + // trim and remove port number from host + // host is lowercase as per RFC 952/2181 + $host = strtolower(preg_replace('/:\d+$/', '', trim($host))); + + // Port number + $scheme = $this->getHttpScheme(); + $port = $this->getCurrentPort(); + $appendPort = ':' . $port; + + // Don't append port number if a normal port. + if (($scheme == 'http' && $port == '80') || ($scheme == 'https' && $port == '443')) { + $appendPort = ''; + } + + return $host . $appendPort; + } + + protected function getCurrentPort() + { + // Check for proxy first + $port = $this->getHeader('X_FORWARDED_PORT'); + if ($port) { + return (string)$port; + } + + $protocol = (string)$this->getHeader('X_FORWARDED_PROTO'); + if ($protocol === 'https') { + return '443'; + } + + return (string)$this->getServerVar('SERVER_PORT'); + } + + /** + * Returns the a value from the $_SERVER super global. + * + * @param string $key + * + * @return string + */ + protected function getServerVar($key) + { + return isset($_SERVER[$key]) ? $_SERVER[$key] : ''; + } + + /** + * Gets a value from the HTTP request headers. + * + * @param string $key + * + * @return string + */ + protected function getHeader($key) + { + return $this->getServerVar('HTTP_' . $key); + } + + /** + * Checks if the value in X_FORWARDED_HOST is a valid hostname + * Could prevent unintended redirections + * + * @param string $header + * + * @return boolean + */ + protected function isValidForwardedHost($header) + { + $elements = explode(',', $header); + $host = $elements[count($elements) - 1]; + + return preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $host) //valid chars check + && 0 < strlen($host) && strlen($host) < 254 //overall length check + && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $host); //length of each label + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlManipulator.php b/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlManipulator.php new file mode 100644 index 0000000..daeab9c --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlManipulator.php @@ -0,0 +1,167 @@ + 0) { + $query = '?' . http_build_query($params, null, '&'); + } + } + + $scheme = isset($parts['scheme']) ? $parts['scheme'] . '://' : ''; + $host = isset($parts['host']) ? $parts['host'] : ''; + $port = isset($parts['port']) ? ':' . $parts['port'] : ''; + $path = isset($parts['path']) ? $parts['path'] : ''; + $fragment = isset($parts['fragment']) ? '#' . $parts['fragment'] : ''; + + return $scheme . $host . $port . $path . $query . $fragment; + } + + /** + * Gracefully appends params to the URL. + * + * @param string $url The URL that will receive the params. + * @param array $newParams The params to append to the URL. + * + * @return string + */ + public static function appendParamsToUrl($url, array $newParams = []) + { + if (empty($newParams)) { + return $url; + } + + if (strpos($url, '?') === false) { + return $url . '?' . http_build_query($newParams, null, '&'); + } + + list($path, $query) = explode('?', $url, 2); + $existingParams = []; + parse_str($query, $existingParams); + + // Favor params from the original URL over $newParams + $newParams = array_merge($newParams, $existingParams); + + // Sort for a predicable order + ksort($newParams); + + return $path . '?' . http_build_query($newParams, null, '&'); + } + + /** + * Returns the params from a URL in the form of an array. + * + * @param string $url The URL to parse the params from. + * + * @return array + */ + public static function getParamsAsArray($url) + { + $query = parse_url($url, PHP_URL_QUERY); + if (!$query) { + return []; + } + $params = []; + parse_str($query, $params); + + return $params; + } + + /** + * Adds the params of the first URL to the second URL. + * + * Any params that already exist in the second URL will go untouched. + * + * @param string $urlToStealFrom The URL harvest the params from. + * @param string $urlToAddTo The URL that will receive the new params. + * + * @return string The $urlToAddTo with any new params from $urlToStealFrom. + */ + public static function mergeUrlParams($urlToStealFrom, $urlToAddTo) + { + $newParams = static::getParamsAsArray($urlToStealFrom); + // Nothing new to add, return as-is + if (!$newParams) { + return $urlToAddTo; + } + + return static::appendParamsToUrl($urlToAddTo, $newParams); + } + + /** + * Check for a "/" prefix and prepend it if not exists. + * + * @param string|null $string + * + * @return string|null + */ + public static function forceSlashPrefix($string) + { + if (!$string) { + return $string; + } + + return strpos($string, '/') === 0 ? $string : '/' . $string; + } + + /** + * Trims off the hostname and Graph version from a URL. + * + * @param string $urlToTrim The URL the needs the surgery. + * + * @return string The $urlToTrim with the hostname and Graph version removed. + */ + public static function baseGraphUrlEndpoint($urlToTrim) + { + return '/' . preg_replace('/^https:\/\/.+\.facebook\.com(\/v.+?)?\//', '', $urlToTrim); + } +} diff --git a/vendor/facebook/graph-sdk/src/Facebook/Url/UrlDetectionInterface.php b/vendor/facebook/graph-sdk/src/Facebook/Url/UrlDetectionInterface.php new file mode 100644 index 0000000..dca38a0 --- /dev/null +++ b/vendor/facebook/graph-sdk/src/Facebook/Url/UrlDetectionInterface.php @@ -0,0 +1,39 @@ +