From 62c30501a00f6b0835b45d474ceb2987c77bf40e Mon Sep 17 00:00:00 2001 From: AkankshaBodhankar Date: Fri, 3 Jun 2016 11:54:26 +0530 Subject: [PATCH 01/16] Update README.md --- README.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/README.md b/README.md index 81867e7..fadd951 100644 --- a/README.md +++ b/README.md @@ -1 +1,50 @@ # PCSA-web +## FirstAide - PCSA(Peace Corps Safety App) for Web + +The project repo of PCSA-Web : [PCSA-web repo](https://github.com/systers/PCSA-web) + +FirstAide is a web application also called PCSA web. Peace Corps provides support to all the volunteers who have been sexully assulated. The volunteers can get reporting procedures and other relevant information. The initiative is to provide commitment to the volunteers who are victims of sexual assault via the web app. + +The project is built using the following technologies: + 1. PHP (Backend) + 2. HTML and CSS (Frontend) + 3. Jquery and Javascript + 4. MySql (Database) + +![working](https://cloud.githubusercontent.com/assets/14356938/15768596/d4ae5218-296f-11e6-9102-0d39e2bcd1da.jpg) + +The welcome page of project + +![recommended pages](https://cloud.githubusercontent.com/assets/14356938/15768497/001cb95e-296f-11e6-8cf4-052ffc24e154.png) + +## Getting Started + +### Installation +Download XAMPP from here [XAMPP download](https://www.apachefriends.org/download.html).You will also need a text editor (Sublime or Notepad++) + +Go to your terminal and execute this command + + $ git clone https://github.com/systers/PCSA-web + +Or download the ZIP file from above + +###Opening and Running +1. Launch XAMPP by opening XAMPP control panel +2. Start 'Apache' and 'MySQL' +3. Check if XAMPP had started using the url 'http://localhost:8080/' (Here 8080 is the port number, use the one which you have configured) +4. Now extract the ZIP file of the project PCSA-web which you have downloaded and paste it in the C:\xampp\htdocs (the path where your xampp is present) +5. Open the file which you want to work with using the text editor you have downloaded +6. Make changes and save the file +7. Now, run the project using the url http://localhost:8080/directory_name/file_name.extension Example: 'http://localhost:8080/PCSA-web/login.html' + +###Documentation + +The documentation can be found here +1.[project docs](https://github.com/AkankshaBodhankar/GSOC16Work/tree/master/project-docs) +2.[other docs](https://github.com/AkankshaBodhankar/GSOC16Work/tree/master/work-docs) + + + + + + From 17da2b3222d6762ade2ca7b0d153c7d0f26d8782 Mon Sep 17 00:00:00 2001 From: AkankshaBodhankar Date: Fri, 3 Jun 2016 12:04:16 +0530 Subject: [PATCH 02/16] small changes --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fadd951..980e686 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,9 @@ Or download the ZIP file from above ###Documentation The documentation can be found here -1.[project docs](https://github.com/AkankshaBodhankar/GSOC16Work/tree/master/project-docs) -2.[other docs](https://github.com/AkankshaBodhankar/GSOC16Work/tree/master/work-docs) + +[project docs](https://github.com/AkankshaBodhankar/GSOC16Work/tree/master/project-docs) + From cd34f9659d943d6ce9cbcff9d5b918b6db3203ce Mon Sep 17 00:00:00 2001 From: AkankshaBodhankar Date: Sat, 13 Aug 2016 12:55:20 +0530 Subject: [PATCH 03/16] Added readme file --- README.md | 69 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 980e686..11bb885 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # PCSA-web -## FirstAide - PCSA(Peace Corps Safety App) for Web + +## FirstAide - PCSA(Peace Corps Safety App) Web App The project repo of PCSA-Web : [PCSA-web repo](https://github.com/systers/PCSA-web) -FirstAide is a web application also called PCSA web. Peace Corps provides support to all the volunteers who have been sexully assulated. The volunteers can get reporting procedures and other relevant information. The initiative is to provide commitment to the volunteers who are victims of sexual assault via the web app. +FirstAide is a web application also called PCSA web. Peace Corps provides support to all the volunteers who have been sexually assulated. The volunteers can get reporting procedures and other relevant information. The initiative is to provide commitment to the volunteers who are victims of sexual assault via the web app. The project is built using the following technologies: 1. PHP (Backend) @@ -41,11 +42,59 @@ Or download the ZIP file from above The documentation can be found here -[project docs](https://github.com/AkankshaBodhankar/GSOC16Work/tree/master/project-docs) - - - - - - - +1.[project docs](https://github.com/AkankshaBodhankar/GSOC16Work/tree/master/project-docs) + +2.[other docs](https://github.com/AkankshaBodhankar/GSOC16Work/tree/master/work-docs) + +###Guide to Naming Convention Used +[Conventions and rules](https://google.github.io/styleguide/htmlcssguide.xml) + +###How to Use CALL and SMS feature +This project makes use of Twilio for sending SMS and making CALLS. Twilio is a third party platform which provides API in PHP for serving the purpose. +SMS and Call had been used in: +Get Help Now module +Group SMS in : +Circle of Trust module + +Read more about Twilio here: [Twilio](https://www.twilio.com/) + +####Steps to enable Twilio in your localhost +1. Get started with SMS and Call by creating an Account on Twilio here : [Twilio Register](https://www.twilio.com/try-twilio) +2. Setting Account SID and Token + + Take the Account SID and Token provided by Twilio here [Your Twilio Credentials](https://www.twilio.com/console) + + Paste them at the correct places in the twilioSMS.php, twilioCall.php and groupsms.php files +3. Setting From Number + Get a phone number from Twilio here: [Twilio phone number](https://www.twilio.com/console/phone-numbers/dashboard). + + Use this as the from number in the files twilioSMS.php, twilioCall.php and groupsms.php +4. Setting To Numbers : + If you are using Twilio Trial Account you can send a SMS or make a Call to a Twilio verified number only. Upgraded accounts may not need to verify a number + + Procedure to verify a number in Twilio + 1. Go to (https://www.twilio.com/console/phone-numbers/dashboard) + 2. Then on the left side vertical menu select Verified Caller IDs + 3. Click the + symbol and verify a number + + After getting the numbers verified it's time to use this numbers to test the feature + While adding the numbers make sure you enter the country code as well else, it won't work. + #####Use in Get Help Now module + 1. Go to javascripts/getHelpNowPhNo.js + 2. Replace the sample numbers to your verified numbers + 3. Make Call or Send SMS from the App + + #####Use in Circle of Trust module + 1. Open the app + 2. Go to Circle of Trust from the menu + 3. Click edit icon + 4. Add your verified numbers there + 5. Submit and go back to Circle of Trust + 6. Click Help Me icon and select a message + 7. An alert pops out saying 'Success' once messages are sent + +References : + +[Tutorial for SMS](https://www.youtube.com/watch?v=jZPeNfLD5Yc) + +[Tutorial for Group SMS](https://www.youtube.com/watch?v=G4oluQf_7S4) From 3c0e1e1fc93ac97a195f62fafd254ae5b0804caf Mon Sep 17 00:00:00 2001 From: AkankshaBodhankar Date: Mon, 15 Aug 2016 22:50:49 +0530 Subject: [PATCH 04/16] pushed work done in GSOC16 --- .htaccess | 1 + PCSaves.php | 56 ++ Services/Twilio.php | 826 ++++++++++++++++ Services/Twilio/AccessToken.php | 135 +++ Services/Twilio/Auth/ConversationsGrant.php | 54 + Services/Twilio/Auth/Grant.php | 18 + Services/Twilio/Auth/IpMessagingGrant.php | 136 +++ Services/Twilio/AutoPagingIterator.php | 110 +++ Services/Twilio/Capability.php | 185 ++++ Services/Twilio/HttpException.php | 3 + Services/Twilio/HttpStream.php | 99 ++ .../Twilio/IPMessagingInstanceResource.php | 15 + Services/Twilio/IPMessagingListResource.php | 18 + Services/Twilio/InstanceResource.php | 84 ++ Services/Twilio/JWT.php | 164 +++ Services/Twilio/ListResource.php | 182 ++++ Services/Twilio/LookupsInstanceResource.php | 15 + Services/Twilio/LookupsListResource.php | 39 + Services/Twilio/MonitorInstanceResource.php | 15 + Services/Twilio/MonitorListResource.php | 18 + Services/Twilio/NextGenInstanceResource.php | 23 + Services/Twilio/NextGenListResource.php | 60 ++ Services/Twilio/NumberType.php | 35 + Services/Twilio/Page.php | 68 ++ Services/Twilio/PartialApplicationHelper.php | 41 + Services/Twilio/PricingInstanceResource.php | 14 + Services/Twilio/PricingListResource.php | 14 + Services/Twilio/RequestValidator.php | 67 ++ Services/Twilio/Resource.php | 134 +++ Services/Twilio/Rest/Account.php | 36 + Services/Twilio/Rest/Accounts.php | 25 + Services/Twilio/Rest/Address.php | 22 + Services/Twilio/Rest/Addresses.php | 22 + Services/Twilio/Rest/Application.php | 6 + Services/Twilio/Rest/Applications.php | 12 + Services/Twilio/Rest/AuthorizedConnectApp.php | 6 + .../Twilio/Rest/AuthorizedConnectApps.php | 10 + Services/Twilio/Rest/AvailablePhoneNumber.php | 7 + .../Twilio/Rest/AvailablePhoneNumbers.php | 54 + Services/Twilio/Rest/Call.php | 116 +++ Services/Twilio/Rest/Calls.php | 77 ++ Services/Twilio/Rest/Conference.php | 12 + Services/Twilio/Rest/Conferences.php | 6 + Services/Twilio/Rest/ConnectApp.php | 6 + Services/Twilio/Rest/ConnectApps.php | 10 + Services/Twilio/Rest/Credential.php | 30 + Services/Twilio/Rest/CredentialList.php | 42 + .../Twilio/Rest/CredentialListMapping.php | 37 + .../Twilio/Rest/CredentialListMappings.php | 24 + Services/Twilio/Rest/CredentialLists.php | 24 + Services/Twilio/Rest/Credentials.php | 28 + Services/Twilio/Rest/DependentPhoneNumber.php | 6 + .../Twilio/Rest/DependentPhoneNumbers.php | 6 + Services/Twilio/Rest/Domain.php | 70 ++ Services/Twilio/Rest/Domains.php | 28 + Services/Twilio/Rest/Feedback.php | 34 + Services/Twilio/Rest/FeedbackSummary.php | 33 + Services/Twilio/Rest/IPMessaging/Channel.php | 10 + Services/Twilio/Rest/IPMessaging/Channels.php | 23 + .../Twilio/Rest/IPMessaging/Credential.php | 5 + .../Twilio/Rest/IPMessaging/Credentials.php | 23 + Services/Twilio/Rest/IPMessaging/Member.php | 5 + Services/Twilio/Rest/IPMessaging/Members.php | 23 + Services/Twilio/Rest/IPMessaging/Message.php | 5 + Services/Twilio/Rest/IPMessaging/Messages.php | 23 + Services/Twilio/Rest/IPMessaging/Role.php | 5 + Services/Twilio/Rest/IPMessaging/Roles.php | 23 + Services/Twilio/Rest/IPMessaging/Service.php | 11 + Services/Twilio/Rest/IPMessaging/Services.php | 23 + Services/Twilio/Rest/IPMessaging/User.php | 5 + Services/Twilio/Rest/IPMessaging/Users.php | 23 + Services/Twilio/Rest/IncomingPhoneNumber.php | 95 ++ Services/Twilio/Rest/IncomingPhoneNumbers.php | 59 ++ Services/Twilio/Rest/IpAccessControlList.php | 40 + .../Rest/IpAccessControlListMapping.php | 37 + .../Rest/IpAccessControlListMappings.php | 25 + Services/Twilio/Rest/IpAccessControlLists.php | 27 + Services/Twilio/Rest/IpAddress.php | 34 + Services/Twilio/Rest/IpAddresses.php | 33 + Services/Twilio/Rest/Key.php | 5 + Services/Twilio/Rest/Keys.php | 22 + Services/Twilio/Rest/Lookups/PhoneNumber.php | 3 + Services/Twilio/Rest/Lookups/PhoneNumbers.php | 3 + Services/Twilio/Rest/Media.php | 31 + Services/Twilio/Rest/MediaInstance.php | 37 + Services/Twilio/Rest/Member.php | 22 + Services/Twilio/Rest/Members.php | 28 + Services/Twilio/Rest/Message.php | 68 ++ Services/Twilio/Rest/Messages.php | 73 ++ Services/Twilio/Rest/Monitor/Alert.php | 5 + Services/Twilio/Rest/Monitor/Alerts.php | 5 + Services/Twilio/Rest/Monitor/Event.php | 5 + Services/Twilio/Rest/Monitor/Events.php | 5 + Services/Twilio/Rest/Notification.php | 6 + Services/Twilio/Rest/Notifications.php | 6 + Services/Twilio/Rest/OutgoingCallerId.php | 6 + Services/Twilio/Rest/OutgoingCallerIds.php | 12 + Services/Twilio/Rest/Participant.php | 10 + Services/Twilio/Rest/Participants.php | 10 + .../Rest/Pricing/MessagingCountries.php | 24 + .../Twilio/Rest/Pricing/MessagingCountry.php | 5 + .../Rest/Pricing/PhoneNumberCountries.php | 23 + .../Rest/Pricing/PhoneNumberCountry.php | 4 + .../Twilio/Rest/Pricing/VoiceCountries.php | 24 + Services/Twilio/Rest/Pricing/VoiceCountry.php | 5 + Services/Twilio/Rest/Pricing/VoiceNumber.php | 5 + Services/Twilio/Rest/Pricing/VoiceNumbers.php | 11 + Services/Twilio/Rest/Queue.php | 10 + Services/Twilio/Rest/Queues.php | 19 + Services/Twilio/Rest/Recording.php | 9 + Services/Twilio/Rest/Recordings.php | 6 + Services/Twilio/Rest/Sandbox.php | 6 + Services/Twilio/Rest/ShortCode.php | 6 + Services/Twilio/Rest/ShortCodes.php | 10 + Services/Twilio/Rest/Sip.php | 19 + Services/Twilio/Rest/SmsMessage.php | 6 + Services/Twilio/Rest/SmsMessages.php | 18 + .../Twilio/Rest/TaskRouter/Activities.php | 15 + Services/Twilio/Rest/TaskRouter/Activity.php | 5 + Services/Twilio/Rest/TaskRouter/Event.php | 5 + Services/Twilio/Rest/TaskRouter/Events.php | 5 + .../Twilio/Rest/TaskRouter/Reservation.php | 5 + .../Twilio/Rest/TaskRouter/Reservations.php | 5 + .../Twilio/Rest/TaskRouter/Statistics.php | 8 + Services/Twilio/Rest/TaskRouter/Task.php | 9 + Services/Twilio/Rest/TaskRouter/TaskQueue.php | 8 + .../Rest/TaskRouter/TaskQueueStatistics.php | 5 + .../Twilio/Rest/TaskRouter/TaskQueues.php | 15 + .../Rest/TaskRouter/TaskQueuesStatistics.php | 9 + Services/Twilio/Rest/TaskRouter/Tasks.php | 11 + Services/Twilio/Rest/TaskRouter/Worker.php | 9 + .../Rest/TaskRouter/WorkerStatistics.php | 5 + Services/Twilio/Rest/TaskRouter/Workers.php | 13 + .../Rest/TaskRouter/WorkersStatistics.php | 5 + Services/Twilio/Rest/TaskRouter/Workflow.php | 8 + .../Rest/TaskRouter/WorkflowStatistics.php | 5 + Services/Twilio/Rest/TaskRouter/Workflows.php | 11 + Services/Twilio/Rest/TaskRouter/Workspace.php | 17 + .../Rest/TaskRouter/WorkspaceStatistics.php | 5 + .../Twilio/Rest/TaskRouter/Workspaces.php | 9 + Services/Twilio/Rest/Token.php | 5 + Services/Twilio/Rest/Tokens.php | 24 + Services/Twilio/Rest/Transcription.php | 6 + Services/Twilio/Rest/Transcriptions.php | 6 + .../Twilio/Rest/Trunking/CredentialList.php | 5 + .../Twilio/Rest/Trunking/CredentialLists.php | 24 + .../Rest/Trunking/IpAccessControlList.php | 5 + .../Rest/Trunking/IpAccessControlLists.php | 24 + .../Twilio/Rest/Trunking/OriginationUrl.php | 5 + .../Twilio/Rest/Trunking/OriginationUrls.php | 24 + Services/Twilio/Rest/Trunking/PhoneNumber.php | 5 + .../Twilio/Rest/Trunking/PhoneNumbers.php | 23 + Services/Twilio/Rest/Trunking/Trunk.php | 13 + Services/Twilio/Rest/Trunking/Trunks.php | 5 + Services/Twilio/Rest/UsageRecord.php | 6 + Services/Twilio/Rest/UsageRecords.php | 33 + Services/Twilio/Rest/UsageTrigger.php | 5 + Services/Twilio/Rest/UsageTriggers.php | 27 + Services/Twilio/RestException.php | 44 + Services/Twilio/SIPListResource.php | 14 + Services/Twilio/TaskRouter/Capability.php | 169 ++++ Services/Twilio/TaskRouter/CapabilityAPI.php | 153 +++ .../TaskRouter/TaskQueue/Capability.php | 21 + .../Twilio/TaskRouter/Worker/Capability.php | 49 + .../TaskRouter/Workspace/Capability.php | 21 + .../Twilio/TaskRouterInstanceResource.php | 22 + Services/Twilio/TaskRouterListResource.php | 26 + Services/Twilio/TimeRangeResource.php | 31 + Services/Twilio/TinyHttp.php | 134 +++ Services/Twilio/TrunkingInstanceResource.php | 15 + Services/Twilio/TrunkingListResource.php | 38 + Services/Twilio/Twiml.php | 137 +++ Services/Twilio/UsageResource.php | 20 + Services/Twilio/WorkflowConfiguration.php | 101 ++ bystanderIntervention.php | 87 ++ circleOfTrust.php | 75 ++ commonalitiesOfSexualPredators.php | 108 ++ copingWithUnwantedAttentionStrategies.php | 77 ++ css files/circle-of-trust.css | 173 ++++ css files/gethelpnow-style.css | 219 ++++ css files/index-style.css | 37 + css files/loginAndRegistration.css | 117 +++ css files/menu-css.css | 138 +++ css files/progress-bar.css | 50 + css files/safety-tools.css | 183 ++++ css files/sweetalert.css | 932 ++++++++++++++++++ css files/welcome-style.css | 84 ++ database/pcsa_web.sql | 99 ++ dbconnect.php | 11 + editComrades.php | 130 +++ getHelpNow.php | 107 ++ getHelpNow2.php | 60 ++ groupsms.php | 74 ++ images/PClogoWhite.png | Bin 0 -> 77481 bytes images/bw-arrow.png | Bin 0 -> 20832 bytes images/close-button.png | Bin 0 -> 5299 bytes images/drag_hand.png | Bin 0 -> 25133 bytes images/fw-arrow.png | Bin 0 -> 22898 bytes images/ic_comrade.png | Bin 0 -> 6820 bytes images/ic_edit_button.png | Bin 0 -> 9729 bytes images/ic_help_me.png | Bin 0 -> 10851 bytes images/mail.png | Bin 0 -> 6897 bytes images/phone.png | Bin 0 -> 262892 bytes images/photothumb.db | Bin 0 -> 3072 bytes images/secure.png | Bin 0 -> 4999 bytes images/settings.png | Bin 0 -> 7639 bytes index.php | 18 + javascripts/PCMOpopup.js | 24 + javascripts/SARLpopup.js | 24 + javascripts/SSMpopup.js | 24 + javascripts/changeloc.js | 11 + javascripts/circleOfTrustMessage.js | 56 ++ javascripts/closePopup.js | 7 + javascripts/dragscroll.js | 86 ++ javascripts/gethelpnowPhNo.js | 53 + javascripts/jquery-1.12.4.min.js | 5 + javascripts/menu.js | 14 + javascripts/popup.js | 25 + javascripts/progressBar.js | 17 + javascripts/sweetalert.js | 6 + javascripts/sweetalert.min.js | 1 + javascripts/twilio-call.js | 18 + javascripts/twilio-sms.js | 19 + javascripts/validation-v12.js | 46 + loadComradeNumbers.php | 32 + login.php | 78 ++ logout.php | 9 + menu.php | 89 ++ officeOfCivilRightsAndDiversity.php | 57 ++ officeOfInspectorGeneral.php | 56 ++ officeOfVictimAdvocacy.php | 56 ++ personalSecurityStrategies.php | 47 + progressBar.php | 37 + project-docs/db.png | Bin 0 -> 62195 bytes project-docs/diagrams PCSA.pdf | Bin 0 -> 630623 bytes project-docs/mockup final.pdf | Bin 0 -> 2277396 bytes project-docs/pcsa requirements.docx | Bin 0 -> 92334 bytes project-docs/prj images/Picture1.png | Bin 0 -> 171599 bytes project-docs/prj images/Picture2.png | Bin 0 -> 128595 bytes project-docs/prj images/Screenshot (600).png | Bin 0 -> 18093 bytes project-docs/prj images/Screenshot (601).png | Bin 0 -> 22635 bytes project-docs/prj images/Screenshot (602).png | Bin 0 -> 21373 bytes project-docs/prj images/Screenshot (603).png | Bin 0 -> 18729 bytes project-docs/prj images/Screenshot (604).png | Bin 0 -> 13619 bytes project-docs/prj images/Screenshot (605).png | Bin 0 -> 56260 bytes project-docs/prj images/Screenshot (606).png | Bin 0 -> 55326 bytes project-docs/prj images/Screenshot (607).png | Bin 0 -> 45660 bytes project-docs/prj images/Screenshot (608).png | Bin 0 -> 45545 bytes project-docs/prj images/Screenshot (609).png | Bin 0 -> 40919 bytes project-docs/prj images/Screenshot (610).png | Bin 0 -> 33297 bytes project-docs/prj images/Screenshot (621).png | Bin 0 -> 90085 bytes project-docs/prj images/Screenshot (622).png | Bin 0 -> 62493 bytes project-docs/prj images/Screenshot (623).png | Bin 0 -> 50713 bytes project-docs/prj images/slide-menu.jpg | Bin 0 -> 62124 bytes radar.php | 97 ++ registration.php | 100 ++ safetyPlanBasics.php | 80 ++ safetyPlanWorksheet.php | 222 +++++ safetyTools1.php | 58 ++ safetyTools2.php | 55 ++ twilioCall.php | 88 ++ twilioSMS.php | 98 ++ welcome.php | 57 ++ work-docs/Timeline for gsoc - KanbanFlow.pdf | Bin 0 -> 68563 bytes work-docs/mid-evaluation.pdf | Bin 0 -> 852621 bytes work-docs/milestones.png | Bin 0 -> 49017 bytes 266 files changed, 10510 insertions(+) create mode 100644 .htaccess create mode 100644 PCSaves.php create mode 100644 Services/Twilio.php create mode 100644 Services/Twilio/AccessToken.php create mode 100644 Services/Twilio/Auth/ConversationsGrant.php create mode 100644 Services/Twilio/Auth/Grant.php create mode 100644 Services/Twilio/Auth/IpMessagingGrant.php create mode 100644 Services/Twilio/AutoPagingIterator.php create mode 100644 Services/Twilio/Capability.php create mode 100644 Services/Twilio/HttpException.php create mode 100644 Services/Twilio/HttpStream.php create mode 100644 Services/Twilio/IPMessagingInstanceResource.php create mode 100644 Services/Twilio/IPMessagingListResource.php create mode 100644 Services/Twilio/InstanceResource.php create mode 100644 Services/Twilio/JWT.php create mode 100644 Services/Twilio/ListResource.php create mode 100644 Services/Twilio/LookupsInstanceResource.php create mode 100644 Services/Twilio/LookupsListResource.php create mode 100644 Services/Twilio/MonitorInstanceResource.php create mode 100644 Services/Twilio/MonitorListResource.php create mode 100644 Services/Twilio/NextGenInstanceResource.php create mode 100644 Services/Twilio/NextGenListResource.php create mode 100644 Services/Twilio/NumberType.php create mode 100644 Services/Twilio/Page.php create mode 100644 Services/Twilio/PartialApplicationHelper.php create mode 100644 Services/Twilio/PricingInstanceResource.php create mode 100644 Services/Twilio/PricingListResource.php create mode 100644 Services/Twilio/RequestValidator.php create mode 100644 Services/Twilio/Resource.php create mode 100644 Services/Twilio/Rest/Account.php create mode 100644 Services/Twilio/Rest/Accounts.php create mode 100644 Services/Twilio/Rest/Address.php create mode 100644 Services/Twilio/Rest/Addresses.php create mode 100644 Services/Twilio/Rest/Application.php create mode 100644 Services/Twilio/Rest/Applications.php create mode 100644 Services/Twilio/Rest/AuthorizedConnectApp.php create mode 100644 Services/Twilio/Rest/AuthorizedConnectApps.php create mode 100644 Services/Twilio/Rest/AvailablePhoneNumber.php create mode 100644 Services/Twilio/Rest/AvailablePhoneNumbers.php create mode 100644 Services/Twilio/Rest/Call.php create mode 100644 Services/Twilio/Rest/Calls.php create mode 100644 Services/Twilio/Rest/Conference.php create mode 100644 Services/Twilio/Rest/Conferences.php create mode 100644 Services/Twilio/Rest/ConnectApp.php create mode 100644 Services/Twilio/Rest/ConnectApps.php create mode 100644 Services/Twilio/Rest/Credential.php create mode 100644 Services/Twilio/Rest/CredentialList.php create mode 100644 Services/Twilio/Rest/CredentialListMapping.php create mode 100644 Services/Twilio/Rest/CredentialListMappings.php create mode 100644 Services/Twilio/Rest/CredentialLists.php create mode 100644 Services/Twilio/Rest/Credentials.php create mode 100644 Services/Twilio/Rest/DependentPhoneNumber.php create mode 100644 Services/Twilio/Rest/DependentPhoneNumbers.php create mode 100644 Services/Twilio/Rest/Domain.php create mode 100644 Services/Twilio/Rest/Domains.php create mode 100644 Services/Twilio/Rest/Feedback.php create mode 100644 Services/Twilio/Rest/FeedbackSummary.php create mode 100644 Services/Twilio/Rest/IPMessaging/Channel.php create mode 100644 Services/Twilio/Rest/IPMessaging/Channels.php create mode 100644 Services/Twilio/Rest/IPMessaging/Credential.php create mode 100644 Services/Twilio/Rest/IPMessaging/Credentials.php create mode 100644 Services/Twilio/Rest/IPMessaging/Member.php create mode 100644 Services/Twilio/Rest/IPMessaging/Members.php create mode 100644 Services/Twilio/Rest/IPMessaging/Message.php create mode 100644 Services/Twilio/Rest/IPMessaging/Messages.php create mode 100644 Services/Twilio/Rest/IPMessaging/Role.php create mode 100644 Services/Twilio/Rest/IPMessaging/Roles.php create mode 100644 Services/Twilio/Rest/IPMessaging/Service.php create mode 100644 Services/Twilio/Rest/IPMessaging/Services.php create mode 100644 Services/Twilio/Rest/IPMessaging/User.php create mode 100644 Services/Twilio/Rest/IPMessaging/Users.php create mode 100644 Services/Twilio/Rest/IncomingPhoneNumber.php create mode 100644 Services/Twilio/Rest/IncomingPhoneNumbers.php create mode 100644 Services/Twilio/Rest/IpAccessControlList.php create mode 100644 Services/Twilio/Rest/IpAccessControlListMapping.php create mode 100644 Services/Twilio/Rest/IpAccessControlListMappings.php create mode 100644 Services/Twilio/Rest/IpAccessControlLists.php create mode 100644 Services/Twilio/Rest/IpAddress.php create mode 100644 Services/Twilio/Rest/IpAddresses.php create mode 100644 Services/Twilio/Rest/Key.php create mode 100644 Services/Twilio/Rest/Keys.php create mode 100644 Services/Twilio/Rest/Lookups/PhoneNumber.php create mode 100644 Services/Twilio/Rest/Lookups/PhoneNumbers.php create mode 100644 Services/Twilio/Rest/Media.php create mode 100644 Services/Twilio/Rest/MediaInstance.php create mode 100644 Services/Twilio/Rest/Member.php create mode 100644 Services/Twilio/Rest/Members.php create mode 100644 Services/Twilio/Rest/Message.php create mode 100644 Services/Twilio/Rest/Messages.php create mode 100644 Services/Twilio/Rest/Monitor/Alert.php create mode 100644 Services/Twilio/Rest/Monitor/Alerts.php create mode 100644 Services/Twilio/Rest/Monitor/Event.php create mode 100644 Services/Twilio/Rest/Monitor/Events.php create mode 100644 Services/Twilio/Rest/Notification.php create mode 100644 Services/Twilio/Rest/Notifications.php create mode 100644 Services/Twilio/Rest/OutgoingCallerId.php create mode 100644 Services/Twilio/Rest/OutgoingCallerIds.php create mode 100644 Services/Twilio/Rest/Participant.php create mode 100644 Services/Twilio/Rest/Participants.php create mode 100644 Services/Twilio/Rest/Pricing/MessagingCountries.php create mode 100644 Services/Twilio/Rest/Pricing/MessagingCountry.php create mode 100644 Services/Twilio/Rest/Pricing/PhoneNumberCountries.php create mode 100644 Services/Twilio/Rest/Pricing/PhoneNumberCountry.php create mode 100644 Services/Twilio/Rest/Pricing/VoiceCountries.php create mode 100644 Services/Twilio/Rest/Pricing/VoiceCountry.php create mode 100644 Services/Twilio/Rest/Pricing/VoiceNumber.php create mode 100644 Services/Twilio/Rest/Pricing/VoiceNumbers.php create mode 100644 Services/Twilio/Rest/Queue.php create mode 100644 Services/Twilio/Rest/Queues.php create mode 100644 Services/Twilio/Rest/Recording.php create mode 100644 Services/Twilio/Rest/Recordings.php create mode 100644 Services/Twilio/Rest/Sandbox.php create mode 100644 Services/Twilio/Rest/ShortCode.php create mode 100644 Services/Twilio/Rest/ShortCodes.php create mode 100644 Services/Twilio/Rest/Sip.php create mode 100644 Services/Twilio/Rest/SmsMessage.php create mode 100644 Services/Twilio/Rest/SmsMessages.php create mode 100644 Services/Twilio/Rest/TaskRouter/Activities.php create mode 100644 Services/Twilio/Rest/TaskRouter/Activity.php create mode 100644 Services/Twilio/Rest/TaskRouter/Event.php create mode 100644 Services/Twilio/Rest/TaskRouter/Events.php create mode 100644 Services/Twilio/Rest/TaskRouter/Reservation.php create mode 100644 Services/Twilio/Rest/TaskRouter/Reservations.php create mode 100644 Services/Twilio/Rest/TaskRouter/Statistics.php create mode 100644 Services/Twilio/Rest/TaskRouter/Task.php create mode 100644 Services/Twilio/Rest/TaskRouter/TaskQueue.php create mode 100644 Services/Twilio/Rest/TaskRouter/TaskQueueStatistics.php create mode 100644 Services/Twilio/Rest/TaskRouter/TaskQueues.php create mode 100644 Services/Twilio/Rest/TaskRouter/TaskQueuesStatistics.php create mode 100644 Services/Twilio/Rest/TaskRouter/Tasks.php create mode 100644 Services/Twilio/Rest/TaskRouter/Worker.php create mode 100644 Services/Twilio/Rest/TaskRouter/WorkerStatistics.php create mode 100644 Services/Twilio/Rest/TaskRouter/Workers.php create mode 100644 Services/Twilio/Rest/TaskRouter/WorkersStatistics.php create mode 100644 Services/Twilio/Rest/TaskRouter/Workflow.php create mode 100644 Services/Twilio/Rest/TaskRouter/WorkflowStatistics.php create mode 100644 Services/Twilio/Rest/TaskRouter/Workflows.php create mode 100644 Services/Twilio/Rest/TaskRouter/Workspace.php create mode 100644 Services/Twilio/Rest/TaskRouter/WorkspaceStatistics.php create mode 100644 Services/Twilio/Rest/TaskRouter/Workspaces.php create mode 100644 Services/Twilio/Rest/Token.php create mode 100644 Services/Twilio/Rest/Tokens.php create mode 100644 Services/Twilio/Rest/Transcription.php create mode 100644 Services/Twilio/Rest/Transcriptions.php create mode 100644 Services/Twilio/Rest/Trunking/CredentialList.php create mode 100644 Services/Twilio/Rest/Trunking/CredentialLists.php create mode 100644 Services/Twilio/Rest/Trunking/IpAccessControlList.php create mode 100644 Services/Twilio/Rest/Trunking/IpAccessControlLists.php create mode 100644 Services/Twilio/Rest/Trunking/OriginationUrl.php create mode 100644 Services/Twilio/Rest/Trunking/OriginationUrls.php create mode 100644 Services/Twilio/Rest/Trunking/PhoneNumber.php create mode 100644 Services/Twilio/Rest/Trunking/PhoneNumbers.php create mode 100644 Services/Twilio/Rest/Trunking/Trunk.php create mode 100644 Services/Twilio/Rest/Trunking/Trunks.php create mode 100644 Services/Twilio/Rest/UsageRecord.php create mode 100644 Services/Twilio/Rest/UsageRecords.php create mode 100644 Services/Twilio/Rest/UsageTrigger.php create mode 100644 Services/Twilio/Rest/UsageTriggers.php create mode 100644 Services/Twilio/RestException.php create mode 100644 Services/Twilio/SIPListResource.php create mode 100644 Services/Twilio/TaskRouter/Capability.php create mode 100644 Services/Twilio/TaskRouter/CapabilityAPI.php create mode 100644 Services/Twilio/TaskRouter/TaskQueue/Capability.php create mode 100644 Services/Twilio/TaskRouter/Worker/Capability.php create mode 100644 Services/Twilio/TaskRouter/Workspace/Capability.php create mode 100644 Services/Twilio/TaskRouterInstanceResource.php create mode 100644 Services/Twilio/TaskRouterListResource.php create mode 100644 Services/Twilio/TimeRangeResource.php create mode 100644 Services/Twilio/TinyHttp.php create mode 100644 Services/Twilio/TrunkingInstanceResource.php create mode 100644 Services/Twilio/TrunkingListResource.php create mode 100644 Services/Twilio/Twiml.php create mode 100644 Services/Twilio/UsageResource.php create mode 100644 Services/Twilio/WorkflowConfiguration.php create mode 100644 bystanderIntervention.php create mode 100644 circleOfTrust.php create mode 100644 commonalitiesOfSexualPredators.php create mode 100644 copingWithUnwantedAttentionStrategies.php create mode 100644 css files/circle-of-trust.css create mode 100644 css files/gethelpnow-style.css create mode 100644 css files/index-style.css create mode 100644 css files/loginAndRegistration.css create mode 100644 css files/menu-css.css create mode 100644 css files/progress-bar.css create mode 100644 css files/safety-tools.css create mode 100644 css files/sweetalert.css create mode 100644 css files/welcome-style.css create mode 100644 database/pcsa_web.sql create mode 100644 dbconnect.php create mode 100644 editComrades.php create mode 100644 getHelpNow.php create mode 100644 getHelpNow2.php create mode 100644 groupsms.php create mode 100644 images/PClogoWhite.png create mode 100644 images/bw-arrow.png create mode 100644 images/close-button.png create mode 100644 images/drag_hand.png create mode 100644 images/fw-arrow.png create mode 100644 images/ic_comrade.png create mode 100644 images/ic_edit_button.png create mode 100644 images/ic_help_me.png create mode 100644 images/mail.png create mode 100644 images/phone.png create mode 100644 images/photothumb.db create mode 100644 images/secure.png create mode 100644 images/settings.png create mode 100644 index.php create mode 100644 javascripts/PCMOpopup.js create mode 100644 javascripts/SARLpopup.js create mode 100644 javascripts/SSMpopup.js create mode 100644 javascripts/changeloc.js create mode 100644 javascripts/circleOfTrustMessage.js create mode 100644 javascripts/closePopup.js create mode 100644 javascripts/dragscroll.js create mode 100644 javascripts/gethelpnowPhNo.js create mode 100644 javascripts/jquery-1.12.4.min.js create mode 100644 javascripts/menu.js create mode 100644 javascripts/popup.js create mode 100644 javascripts/progressBar.js create mode 100644 javascripts/sweetalert.js create mode 100644 javascripts/sweetalert.min.js create mode 100644 javascripts/twilio-call.js create mode 100644 javascripts/twilio-sms.js create mode 100644 javascripts/validation-v12.js create mode 100644 loadComradeNumbers.php create mode 100644 login.php create mode 100644 logout.php create mode 100644 menu.php create mode 100644 officeOfCivilRightsAndDiversity.php create mode 100644 officeOfInspectorGeneral.php create mode 100644 officeOfVictimAdvocacy.php create mode 100644 personalSecurityStrategies.php create mode 100644 progressBar.php create mode 100644 project-docs/db.png create mode 100644 project-docs/diagrams PCSA.pdf create mode 100644 project-docs/mockup final.pdf create mode 100644 project-docs/pcsa requirements.docx create mode 100644 project-docs/prj images/Picture1.png create mode 100644 project-docs/prj images/Picture2.png create mode 100644 project-docs/prj images/Screenshot (600).png create mode 100644 project-docs/prj images/Screenshot (601).png create mode 100644 project-docs/prj images/Screenshot (602).png create mode 100644 project-docs/prj images/Screenshot (603).png create mode 100644 project-docs/prj images/Screenshot (604).png create mode 100644 project-docs/prj images/Screenshot (605).png create mode 100644 project-docs/prj images/Screenshot (606).png create mode 100644 project-docs/prj images/Screenshot (607).png create mode 100644 project-docs/prj images/Screenshot (608).png create mode 100644 project-docs/prj images/Screenshot (609).png create mode 100644 project-docs/prj images/Screenshot (610).png create mode 100644 project-docs/prj images/Screenshot (621).png create mode 100644 project-docs/prj images/Screenshot (622).png create mode 100644 project-docs/prj images/Screenshot (623).png create mode 100644 project-docs/prj images/slide-menu.jpg create mode 100644 radar.php create mode 100644 registration.php create mode 100644 safetyPlanBasics.php create mode 100644 safetyPlanWorksheet.php create mode 100644 safetyTools1.php create mode 100644 safetyTools2.php create mode 100644 twilioCall.php create mode 100644 twilioSMS.php create mode 100644 welcome.php create mode 100644 work-docs/Timeline for gsoc - KanbanFlow.pdf create mode 100644 work-docs/mid-evaluation.pdf create mode 100644 work-docs/milestones.png diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..e029dfb --- /dev/null +++ b/.htaccess @@ -0,0 +1 @@ +AddType application/x-httpd-php .html .htm \ No newline at end of file diff --git a/PCSaves.php b/PCSaves.php new file mode 100644 index 0000000..3d26065 --- /dev/null +++ b/PCSaves.php @@ -0,0 +1,56 @@ + + + + + FirstAide + + + + +
+
+
+

PC Saves Anonymous Helpline

+
+
+ + + + +
+

+ The PC SAVES Helpline provides anonymous, confidential crisis intervention, support, and information via a call, text, or online chat to Peace Corps Volunteers and Trainees. All options are staffed by trained professionals not affiliated with Peace Corps, available 24/7. No personally identifying information will be collected. +

+ Learn More: pcsaveshelpine.org +
+ + + + +
+
+ + + + + \ No newline at end of file diff --git a/Services/Twilio.php b/Services/Twilio.php new file mode 100644 index 0000000..18cf7ce --- /dev/null +++ b/Services/Twilio.php @@ -0,0 +1,826 @@ +version = in_array($version, $this->versions) ? $version : end($this->versions); + + if (null === $_http) { + if (!in_array('openssl', get_loaded_extensions())) { + throw new Services_Twilio_HttpException("The OpenSSL extension is required but not currently enabled. For more information, see http://php.net/manual/en/book.openssl.php"); + } + if (in_array('curl', get_loaded_extensions())) { + $_http = new Services_Twilio_TinyHttp( + $this->_getBaseUri(), + array( + "curlopts" => array( + CURLOPT_USERAGENT => self::qualifiedUserAgent(phpversion()), + CURLOPT_HTTPHEADER => array('Accept-Charset: utf-8'), + ), + ) + ); + } else { + $_http = new Services_Twilio_HttpStream( + $this->_getBaseUri(), + array( + "http_options" => array( + "http" => array( + "user_agent" => self::qualifiedUserAgent(phpversion()), + "header" => "Accept-Charset: utf-8\r\n", + ), + "ssl" => array( + 'verify_peer' => true, + 'verify_depth' => 5, + ), + ), + ) + ); + } + } + $_http->authenticate($sid, $token); + $this->http = $_http; + $this->retryAttempts = $retryAttempts; + } + + /** + * Build a query string from query data + * + * :param array $queryData: An associative array of keys and values. The + * values can be a simple type or a list, in which case the list is + * converted to multiple query parameters with the same key. + * :param string $numericPrefix: optional prefix to prepend to numeric keys + * :return: The encoded query string + * :rtype: string + */ + public static function buildQuery($queryData, $numericPrefix = '') { + $query = ''; + // Loop through all of the $query_data + foreach ($queryData as $key => $value) { + // If the key is an int, add the numeric_prefix to the beginning + if (is_int($key)) { + $key = $numericPrefix . $key; + } + + // If the value is an array, we will end up recursing + if (is_array($value)) { + // Loop through the values + foreach ($value as $value2) { + // Add an arg_separator if needed + if ($query !== '') { + $query .= '&'; + } + // Recurse + $query .= self::buildQuery(array($key => $value2), $numericPrefix); + } + } else { + // Add an arg_separator if needed + if ($query !== '') { + $query .= '&'; + } + // Add the key and the urlencoded value (as a string) + $query .= $key . '=' . urlencode((string)$value); + } + } + return $query; + } + + /** + * Construct a URI based on initial path, query params, and paging + * information + * + * We want to use the query params, unless we have a next_page_uri from the + * API. + * + * :param string $path: The request path (may contain query params if it's + * a next_page_uri) + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri + * + * :return: the URI that should be requested by the library + * :returntype: string + */ + public function getRequestUri($path, $params, $full_uri = false) + { + $json_path = $full_uri ? $path : "$path.json"; + if (!$full_uri && !empty($params)) { + $query_path = $json_path . '?' . http_build_query($params, '', '&'); + } else { + $query_path = $json_path; + } + return $query_path; + } + + /** + * Fully qualified user agent with the current PHP Version. + * + * :return: the user agent + * :rtype: string + */ + public static function qualifiedUserAgent($php_version) { + return self::USER_AGENT . " (php $php_version)"; + } + + /** + * POST to the resource at the specified path. + * + * :param string $path: Path to the resource + * :param array $params: Query string parameters + * + * :return: The object representation of the resource + * :rtype: object + */ + public function createData($path, $params = array(), $full_uri = false) + { + if (!$full_uri) { + $path = "$path.json"; + } + $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); + $response = $this->http->post( + $path, $headers, self::buildQuery($params, '') + ); + return $this->_processResponse($response); + } + + /** + * DELETE the resource at the specified path. + * + * :param string $path: Path to the resource + * :param array $params: Query string parameters + * + * :return: The object representation of the resource + * :rtype: object + */ + public function deleteData($path, $params = array()) + { + $uri = $this->getRequestUri($path, $params); + return $this->_makeIdempotentRequest(array($this->http, 'delete'), + $uri, $this->retryAttempts); + } + + /** + * Get the retry attempt limit used by the rest client + * + * :return: the number of retry attempts + * :rtype: int + */ + public function getRetryAttempts() { + return $this->retryAttempts; + } + + /** + * Get the api version used by the rest client + * + * :return: the API version in use + * :returntype: string + */ + public function getVersion() { + return $this->version; + } + + /** + * GET the resource at the specified path. + * + * :param string $path: Path to the resource + * :param array $params: Query string parameters + * :param boolean $full_uri: Whether the full URI has been passed as an + * argument + * + * :return: The object representation of the resource + * :rtype: object + */ + public function retrieveData($path, $params = array(), + $full_uri = false + ) + { + $uri = $this->getRequestUri($path, $params, $full_uri); + return $this->_makeIdempotentRequest(array($this->http, 'get'), + $uri, $this->retryAttempts); + } + + /** + * Get the base URI for this client. + * + * :return: base URI + * :rtype: string + */ + protected function _getBaseUri() { + return 'https://api.twilio.com'; + } + + /** + * Helper method for implementing request retry logic + * + * :param array $callable: The function that makes an HTTP request + * :param string $uri: The URI to request + * :param int $retriesLeft: Number of times to retry + * + * :return: The object representation of the resource + * :rtype: object + */ + protected function _makeIdempotentRequest($callable, $uri, $retriesLeft) { + $response = call_user_func_array($callable, array($uri)); + list($status, $headers, $body) = $response; + if ($status >= 500 && $retriesLeft > 0) { + return $this->_makeIdempotentRequest($callable, $uri, $retriesLeft - 1); + } else { + return $this->_processResponse($response); + } + } + + /** + * Convert the JSON encoded resource into a PHP object. + * + * :param array $response: 3-tuple containing status, headers, and body + * + * :return: PHP object decoded from JSON + * :rtype: object + * :throws: A :php:class:`Services_Twilio_RestException` if the Response is + * in the 300-500 range of status codes. + */ + private function _processResponse($response) + { + list($status, $headers, $body) = $response; + if ($status === 204) { + return true; + } + $decoded = json_decode($body); + if ($decoded === null) { + throw new Services_Twilio_RestException( + $status, + 'Could not decode response body as JSON. ' . + 'This likely indicates a 500 server error' + ); + } + if (200 <= $status && $status < 300) { + $this->last_response = $decoded; + return $decoded; + } + throw new Services_Twilio_RestException( + $status, + isset($decoded->message) ? $decoded->message : '', + isset($decoded->code) ? $decoded->code : null, + isset($decoded->more_info) ? $decoded->more_info : null + ); + } +} + +/** + * Create a client to talk to the Twilio Rest API. + * + * + * :param string $sid: Your Account SID + * :param string $token: Your Auth Token from `your dashboard + * `_ + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: + * + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. + */ +class Services_Twilio extends Base_Services_Twilio +{ + protected $versions = array('2008-08-01', '2010-04-01'); + + public function __construct( + $sid, + $token, + $version = null, + Services_Twilio_TinyHttp $_http = null, + $retryAttempts = 1 + ) + { + parent::__construct($sid, $token, $version, $_http, $retryAttempts); + + $this->accounts = new Services_Twilio_Rest_Accounts($this, "/{$this->version}/Accounts"); + $this->account = $this->accounts->get($sid); + } +} + +/** + * Create a client to talk to the Twilio TaskRouter API. + * + * + * :param string $sid: Your Account SID + * :param string $token: Your Auth Token from `your dashboard + * `_ + * :param string $workspaceSid: + * Workspace SID to work with + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: + * + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new TaskRouter_Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. + */ +class TaskRouter_Services_Twilio extends Base_Services_Twilio +{ + protected $versions = array('v1'); + private $accountSid; + + public function __construct( + $sid, + $token, + $workspaceSid, + $version = null, + Services_Twilio_TinyHttp $_http = null, + $retryAttempts = 1 + ) + { + parent::__construct($sid, $token, $version, $_http, $retryAttempts); + + $this->workspaces = new Services_Twilio_Rest_TaskRouter_Workspaces($this, "/{$this->version}/Workspaces"); + $this->workspace = $this->workspaces->get($workspaceSid); + $this->accountSid = $sid; + } + + /** + * Construct a URI based on initial path, query params, and paging + * information + * + * We want to use the query params, unless we have a next_page_uri from the + * API. + * + * :param string $path: The request path (may contain query params if it's + * a next_page_uri) + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri + * + * :return: the URI that should be requested by the library + * :returntype: string + */ + public function getRequestUri($path, $params, $full_uri = false) + { + if (!$full_uri && !empty($params)) { + $query_path = $path . '?' . http_build_query($params, '', '&'); + } else { + $query_path = $path; + } + return $query_path; + } + + public static function createWorkspace($sid, $token, $friendlyName, array $params = array(), Services_Twilio_TinyHttp $_http = null) + { + $taskrouterClient = new TaskRouter_Services_Twilio($sid, $token, null, null, $_http); + return $taskrouterClient->workspaces->create($friendlyName, $params); + } + + public function getTaskQueuesStatistics(array $params = array()) + { + return $this->retrieveData("/{$this->version}/Workspaces/{$this->workspace->sid}/TaskQueues/Statistics", $params); + } + + public function getTaskQueueStatistics($taskQueueSid, array $params = array()) + { + return $this->retrieveData("/{$this->version}/Workspaces/{$this->workspace->sid}/TaskQueues/{$taskQueueSid}/Statistics", $params); + } + + public function getWorkersStatistics(array $params = array()) + { + return $this->retrieveData("/{$this->version}/Workspaces/{$this->workspace->sid}/Workers/Statistics", $params); + } + + public function getWorkerStatistics($workerSid, array $params = array()) + { + return $this->retrieveData("/{$this->version}/Workspaces/{$this->workspace->sid}/Workers/{$workerSid}/Statistics", $params); + } + + public function getWorkflowStatistics($workflowSid, array $params = array()) + { + return $this->retrieveData("/{$this->version}/Workspaces/{$this->workspace->sid}/Workflows/{$workflowSid}/Statistics", $params); + } + + public function getWorkspaceStatistics(array $params = array()) + { + return $this->retrieveData("/{$this->version}/Workspaces/{$this->workspace->sid}/Statistics", $params); + } + + protected function _getBaseUri() + { + return 'https://taskrouter.twilio.com'; + } +} + +/** + * Create a client to talk to the Twilio Lookups API. + * + * + * :param string $sid: Your Account SID + * :param string $token: Your Auth Token from `your dashboard + * `_ + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: + * + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new Lookups_Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. + */ +class Lookups_Services_Twilio extends Base_Services_Twilio +{ + protected $versions = array('v1'); + private $accountSid; + + public function __construct( + $sid, + $token, + $version = null, + Services_Twilio_TinyHttp $_http = null, + $retryAttempts = 1 + ) + { + parent::__construct($sid, $token, $version, $_http, $retryAttempts); + + $this->accountSid = $sid; + $this->phone_numbers = new Services_Twilio_Rest_Lookups_PhoneNumbers($this, "/{$this->version}/PhoneNumbers"); + } + + /** + * Construct a URI based on initial path, query params, and paging + * information + * + * We want to use the query params, unless we have a next_page_uri from the + * API. + * + * :param string $path: The request path (may contain query params if it's + * a next_page_uri) + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri + * + * :return: the URI that should be requested by the library + * :returntype: string + */ + public function getRequestUri($path, $params, $full_uri = false) + { + if (!$full_uri && !empty($params)) { + $query_path = $path . '?' . http_build_query($params, '', '&'); + } else { + $query_path = $path; + } + return $query_path; + } + + /** + * Get the base URI for this client. + * + * :return: base URI + * :rtype: string + */ + protected function _getBaseUri() + { + return 'https://lookups.twilio.com'; + } + +} + +/** + * Create a client to talk to the Twilio Pricing API. + * + * + * :param string $sid: Your Account SID + * :param string $token: Your Auth Token from `your dashboard + * `_ + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: + * + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new Pricing_Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. + */ +class Pricing_Services_Twilio extends Base_Services_Twilio +{ + protected $versions = array('v1'); + + public function __construct( + $sid, + $token, + $version = null, + Services_Twilio_TinyHttp $_http = null, + $retryAttempts = 1 + ) { + parent::__construct($sid, $token, $version, $_http, $retryAttempts); + + $this->voiceCountries = new Services_Twilio_Rest_Pricing_VoiceCountries( + $this, "/{$this->version}/Voice/Countries" + ); + $this->voiceNumbers = new Services_Twilio_Rest_Pricing_VoiceNumbers( + $this, "/{$this->version}/Voice/Numbers" + ); + $this->phoneNumberCountries = new Services_Twilio_Rest_Pricing_PhoneNumberCountries( + $this, "/{$this->version}/PhoneNumbers/Countries" + ); + $this->messagingCountries = new Services_Twilio_Rest_Pricing_MessagingCountries( + $this, "/{$this->version}/Messaging/Countries" + ); + } + + /** + * Construct a URI based on initial path, query params, and paging + * information + * + * We want to use the query params, unless we have a next_page_uri from the + * API. + * + * :param string $path: The request path (may contain query params if it's + * a next_page_uri) + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri + * + * :return: the URI that should be requested by the library + * :returntype: string + */ + public function getRequestUri($path, $params, $full_uri = false) + { + if (!$full_uri && !empty($params)) { + $query_path = $path . '?' . http_build_query($params, '', '&'); + } else { + $query_path = $path; + } + return $query_path; + } + + protected function _getBaseUri() { + return 'https://pricing.twilio.com'; + } + +} + +/** + * Create a client to talk to the Twilio Monitor API. + * + * + * :param string $sid: Your Account SID + * :param string $token: Your Auth Token from `your dashboard + * `_ + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: + * + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new Monitor_Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. + */ +class Monitor_Services_Twilio extends Base_Services_Twilio +{ + protected $versions = array('v1'); + + public function __construct( + $sid, + $token, + $version = null, + Services_Twilio_TinyHttp $_http = null, + $retryAttempts = 1 + ) + { + parent::__construct($sid, $token, $version, $_http, $retryAttempts); + + $this->events = new Services_Twilio_Rest_Monitor_Events($this, "/{$this->version}/Events"); + $this->alerts = new Services_Twilio_Rest_Monitor_Alerts($this, "/{$this->version}/Alerts"); + } + + /** + * Construct a URI based on initial path, query params, and paging + * information + * + * We want to use the query params, unless we have a next_page_uri from the + * API. + * + * :param string $path: The request path (may contain query params if it's + * a next_page_uri) + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri + * + * :return: the URI that should be requested by the library + * :returntype: string + */ + public function getRequestUri($path, $params, $full_uri = false) + { + if (!$full_uri && !empty($params)) { + $query_path = $path . '?' . http_build_query($params, '', '&'); + } else { + $query_path = $path; + } + return $query_path; + } + + protected function _getBaseUri() + { + return 'https://monitor.twilio.com'; + } + +} + +/** + * Create a client to talk to the Twilio SIP Trunking API. + * + * + * :param string $sid: Your Account SID + * :param string $token: Your Auth Token from `your dashboard + * `_ + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: + * + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new Trunking_Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. + */ +class Trunking_Services_Twilio extends Base_Services_Twilio +{ + protected $versions = array('v1'); + + public function __construct( + $sid, + $token, + $version = null, + Services_Twilio_TinyHttp $_http = null, + $retryAttempts = 1 + ) + { + parent::__construct($sid, $token, $version, $_http, $retryAttempts); + + $this->trunks = new Services_Twilio_Rest_Trunking_Trunks($this, "/{$this->version}/Trunks"); + } + + /** + * Construct a URI based on initial path, query params, and paging + * information + * + * We want to use the query params, unless we have a next_page_uri from the + * API. + * + * :param string $path: The request path (may contain query params if it's + * a next_page_uri) + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri + * + * :return: the URI that should be requested by the library + * :returntype: string + */ + public function getRequestUri($path, $params, $full_uri = false) + { + if (!$full_uri && !empty($params)) { + $query_path = $path . '?' . http_build_query($params, '', '&'); + } else { + $query_path = $path; + } + return $query_path; + } + + protected function _getBaseUri() + { + return 'https://trunking.twilio.com'; + } + +} + +/** + * Create a client to talk to the Twilio IP Messaging API. + * + * + * :param string $sid: Your Account SID + * :param string $token: Your Auth Token from `your dashboard + * `_ + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: + * + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new Messaging_Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. + */ +class IPMessaging_Services_Twilio extends Base_Services_Twilio +{ + protected $versions = array('v1'); + public function __construct( + $sid, + $token, + $version = null, + Services_Twilio_TinyHttp $_http = null, + $retryAttempts = 1 + ) + { + parent::__construct($sid, $token, $version, $_http, $retryAttempts); + $this->services = new Services_Twilio_Rest_IPMessaging_Services($this, "/{$this->version}/Services"); + $this->credentials = new Services_Twilio_Rest_IPMessaging_Credentials($this, "/{$this->version}/Credentials"); + } + /** + * Construct a URI based on initial path, query params, and paging + * information + * + * We want to use the query params, unless we have a next_page_uri from the + * API. + * + * :param string $path: The request path (may contain query params if it's + * a next_page_uri) + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri + * + * :return: the URI that should be requested by the library + * :returntype: string + */ + public function getRequestUri($path, $params, $full_uri = false) + { + if (!$full_uri && !empty($params)) { + $query_path = $path . '?' . http_build_query($params, '', '&'); + } else { + $query_path = $path; + } + return $query_path; + } + protected function _getBaseUri() + { + return 'https://ip-messaging.twilio.com'; + } +} diff --git a/Services/Twilio/AccessToken.php b/Services/Twilio/AccessToken.php new file mode 100644 index 0000000..1cc370c --- /dev/null +++ b/Services/Twilio/AccessToken.php @@ -0,0 +1,135 @@ +signingKeySid = $signingKeySid; + $this->accountSid = $accountSid; + $this->secret = $secret; + $this->ttl = $ttl; + + if (!is_null($identity)) { + $this->identity = $identity; + } + + $this->grants = array(); + } + + /** + * Set the identity of this access token + * + * @param string $identity identity of the grant + * + * @return Services_Twilio_AccessToken updated access token + */ + public function setIdentity($identity) + { + $this->identity = $identity; + return $this; + } + + /** + * Returns the identity of the grant + * + * @return string the identity + */ + public function getIdentity() + { + return $this->identity; + } + + /** + * Set the nbf of this access token + * + * @param integer $nbf nbf in epoch seconds of the grant + * + * @return Services_Twilio_AccessToken updated access token + */ + public function setNbf($nbf) + { + $this->nbf = $nbf; + return $this; + } + + /** + * Returns the nbf of the grant + * + * @return integer the nbf in epoch seconds + */ + public function getNbf() + { + return $this->nbf; + } + + /** + * Add a grant to the access token + * + * @param Services_Twilio_Auth_Grant $grant to be added + * + * @return $this the updated access token + */ + public function addGrant(Services_Twilio_Auth_Grant $grant) + { + $this->grants[] = $grant; + return $this; + } + + + public function toJWT($algorithm = 'HS256') + { + $header = array( + 'cty' => 'twilio-fpa;v=1', + 'typ' => 'JWT' + ); + + $now = time(); + + $grants = array(); + if ($this->identity) { + $grants['identity'] = $this->identity; + } + + foreach ($this->grants as $grant) { + $payload = $grant->getPayload(); + if (empty($payload)) { + $payload = json_decode('{}'); + } + + $grants[$grant->getGrantKey()] = $payload; + } + + if (empty($grants)) { + $grants = json_decode('{}'); + } + + $payload = array( + 'jti' => $this->signingKeySid . '-' . $now, + 'iss' => $this->signingKeySid, + 'sub' => $this->accountSid, + 'exp' => $now + $this->ttl, + 'grants' => $grants + ); + + if (!is_null($this->nbf)) { + $payload['nbf'] = $this->nbf; + } + + return JWT::encode($payload, $this->secret, $algorithm, $header); + } + + public function __toString() + { + return $this->toJWT(); + } +} diff --git a/Services/Twilio/Auth/ConversationsGrant.php b/Services/Twilio/Auth/ConversationsGrant.php new file mode 100644 index 0000000..f7e02aa --- /dev/null +++ b/Services/Twilio/Auth/ConversationsGrant.php @@ -0,0 +1,54 @@ +configurationProfileSid; + } + + /** + * @param string $configurationProfileSid the configuration profile sid + * we want to enable for this grant + * + * @return Services_Twilio_Auth_ConversationsGrant updated grant + */ + public function setConfigurationProfileSid($configurationProfileSid) + { + $this->configurationProfileSid = $configurationProfileSid; + return $this; + } + + /** + * Returns the grant type + * + * @return string type of the grant + */ + public function getGrantKey() + { + return "rtc"; + } + + /** + * Returns the grant data + * + * @return array data of the grant + */ + public function getPayload() + { + $payload = array(); + if ($this->configurationProfileSid) { + $payload['configuration_profile_sid'] = $this->configurationProfileSid; + } + + return $payload; + } + +} \ No newline at end of file diff --git a/Services/Twilio/Auth/Grant.php b/Services/Twilio/Auth/Grant.php new file mode 100644 index 0000000..5b4434b --- /dev/null +++ b/Services/Twilio/Auth/Grant.php @@ -0,0 +1,18 @@ +serviceSid; + } + + /** + * Set the service sid of this grant + * + * @param string $serviceSid service sid of the grant + * + * @return Services_Twilio_Auth_IpMessagingGrant updated grant + */ + public function setServiceSid($serviceSid) + { + $this->serviceSid = $serviceSid; + return $this; + } + + /** + * Returns the endpoint id of the grant + * + * @return string the endpoint id + */ + public function getEndpointId() + { + return $this->endpointId; + } + + /** + * Set the endpoint id of the grant + * + * @param string $endpointId endpoint id of the grant + * + * @return Services_Twilio_Auth_IpMessagingGrant updated grant + */ + public function setEndpointId($endpointId) + { + $this->endpointId = $endpointId; + return $this; + } + + /** + * Returns the deployment role sid of the grant + * + * @return string the deployment role sid + */ + public function getDeploymentRoleSid() + { + return $this->deploymentRoleSid; + } + + /** + * Set the role sid of the grant + * + * @param string $deploymentRoleSid role sid of the grant + * + * @return Services_Twilio_Auth_IpMessagingGrant updated grant + */ + public function setDeploymentRoleSid($deploymentRoleSid) + { + $this->deploymentRoleSid = $deploymentRoleSid; + return $this; + } + + /** + * Returns the push credential sid of the grant + * + * @return string the push credential sid + */ + public function getPushCredentialSid() + { + return $this->pushCredentialSid; + } + + /** + * Set the credential sid of the grant + * + * @param string $pushCredentialSid push credential sid of the grant + * + * @return Services_Twilio_Auth_IpMessagingGrant updated grant + */ + public function setPushCredentialSid($pushCredentialSid) + { + $this->pushCredentialSid = $pushCredentialSid; + return $this; + } + + /** + * Returns the grant type + * + * @return string type of the grant + */ + public function getGrantKey() + { + return "ip_messaging"; + } + + /** + * Returns the grant data + * + * @return array data of the grant + */ + public function getPayload() + { + $payload = array(); + if ($this->serviceSid) { + $payload['service_sid'] = $this->serviceSid; + } + if ($this->endpointId) { + $payload['endpoint_id'] = $this->endpointId; + } + if ($this->deploymentRoleSid) { + $payload['deployment_role_sid'] = $this->deploymentRoleSid; + } + if ($this->pushCredentialSid) { + $payload['push_credential_sid'] = $this->pushCredentialSid; + } + + return $payload; + } + +} \ No newline at end of file diff --git a/Services/Twilio/AutoPagingIterator.php b/Services/Twilio/AutoPagingIterator.php new file mode 100644 index 0000000..5aacc49 --- /dev/null +++ b/Services/Twilio/AutoPagingIterator.php @@ -0,0 +1,110 @@ +generator = $generator; + $this->page = $page; + $this->size = $size; + $this->filters = $filters; + $this->next_page_uri = null; + $this->items = array(); + + // Save a backup for rewind() + $this->_args = array( + 'page' => $page, + 'size' => $size, + 'filters' => $filters, + ); + } + + public function current() + { + return current($this->items); + } + + public function key() + { + return key($this->items); + } + + /* + * Return the next item in the list, making another HTTP call to the next + * page of resources if necessary. + */ + public function next() + { + try { + $this->loadIfNecessary(); + return next($this->items); + } + catch (Services_Twilio_RestException $e) { + // 20006 is an out of range paging error, everything else is valid + if ($e->getCode() != 20006) { + throw $e; + } + } + } + + /* + * Restore everything to the way it was before we began paging. This gets + * called at the beginning of any foreach() loop + */ + public function rewind() + { + foreach ($this->_args as $arg => $val) { + $this->$arg = $val; + } + $this->items = array(); + $this->next_page_uri = null; + } + + public function count() + { + throw new BadMethodCallException('Not allowed'); + } + + public function valid() + { + try { + $this->loadIfNecessary(); + return key($this->items) !== null; + } + catch (Services_Twilio_RestException $e) { + // 20006 is an out of range paging error, everything else is valid + if ($e->getCode() != 20006) { + throw $e; + } + } + return false; + } + + /* + * Fill $this->items with a new page from the API, if necessary. + */ + protected function loadIfNecessary() + { + if (// Empty because it's the first time or last page was empty + empty($this->items) + // null key when the items list is iterated over completely + || key($this->items) === null + ) { + $page = call_user_func_array($this->generator, array( + $this->page, + $this->size, + $this->filters, + $this->next_page_uri, + )); + $this->next_page_uri = $page->next_page_uri; + $this->items = $page->getItems(); + $this->page = $this->page + 1; + } + } +} diff --git a/Services/Twilio/Capability.php b/Services/Twilio/Capability.php new file mode 100644 index 0000000..f41956a --- /dev/null +++ b/Services/Twilio/Capability.php @@ -0,0 +1,185 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_Capability +{ + public $accountSid; + public $authToken; + public $scopes; + + /** + * Create a new TwilioCapability with zero permissions. Next steps are to + * grant access to resources by configuring this token through the + * functions allowXXXX. + * + * @param $accountSid the account sid to which this token is granted access + * @param $authToken the secret key used to sign the token. Note, this auth + * token is not visible to the user of the token. + */ + public function __construct($accountSid, $authToken) + { + $this->accountSid = $accountSid; + $this->authToken = $authToken; + $this->scopes = array(); + $this->clientName = false; + } + + /** + * If the user of this token should be allowed to accept incoming + * connections then configure the TwilioCapability through this method and + * specify the client name. + * + * @param $clientName + */ + public function allowClientIncoming($clientName) + { + + // clientName must be a non-zero length alphanumeric string + if (preg_match('/\W/', $clientName)) { + throw new InvalidArgumentException( + 'Only alphanumeric characters allowed in client name.'); + } + + if (strlen($clientName) == 0) { + throw new InvalidArgumentException( + 'Client name must not be a zero length string.'); + } + + $this->clientName = $clientName; + $this->allow('client', 'incoming', + array('clientName' => $clientName)); + } + + /** + * Allow the user of this token to make outgoing connections. + * + * @param $appSid the application to which this token grants access + * @param $appParams signed parameters that the user of this token cannot + * overwrite. + */ + public function allowClientOutgoing($appSid, array $appParams=array()) + { + $this->allow('client', 'outgoing', array( + 'appSid' => $appSid, + 'appParams' => http_build_query($appParams, '', '&'))); + } + + /** + * Allow the user of this token to access their event stream. + * + * @param $filters key/value filters to apply to the event stream + */ + public function allowEventStream(array $filters=array()) + { + $this->allow('stream', 'subscribe', array( + 'path' => '/2010-04-01/Events', + 'params' => http_build_query($filters, '', '&'), + )); + } + + /** + * Generates a new token based on the credentials and permissions that + * previously has been granted to this token. + * + * @param $ttl the expiration time of the token (in seconds). Default + * value is 3600 (1hr) + * @return the newly generated token that is valid for $ttl seconds + */ + public function generateToken($ttl = 3600) + { + $payload = array( + 'scope' => array(), + 'iss' => $this->accountSid, + 'exp' => time() + $ttl, + ); + $scopeStrings = array(); + + foreach ($this->scopes as $scope) { + if ($scope->privilege == "outgoing" && $this->clientName) + $scope->params["clientName"] = $this->clientName; + $scopeStrings[] = $scope->toString(); + } + + $payload['scope'] = implode(' ', $scopeStrings); + return JWT::encode($payload, $this->authToken, 'HS256'); + } + + protected function allow($service, $privilege, $params) { + $this->scopes[] = new ScopeURI($service, $privilege, $params); + } +} + +/** + * Scope URI implementation + * + * Simple way to represent configurable privileges in an OAuth + * friendly way. For our case, they look like this: + * + * scope::? + * + * For example: + * scope:client:incoming?name=jonas + * + * @author Jeff Lindsay + */ +class ScopeURI +{ + public $service; + public $privilege; + public $params; + + public function __construct($service, $privilege, $params = array()) + { + $this->service = $service; + $this->privilege = $privilege; + $this->params = $params; + } + + public function toString() + { + $uri = "scope:{$this->service}:{$this->privilege}"; + if (count($this->params)) { + $uri .= "?".http_build_query($this->params, '', '&'); + } + return $uri; + } + + /** + * Parse a scope URI into a ScopeURI object + * + * @param string $uri The scope URI + * @return ScopeURI The parsed scope uri + */ + public static function parse($uri) + { + if (strpos($uri, 'scope:') !== 0) { + throw new UnexpectedValueException( + 'Not a scope URI according to scheme'); + } + + $parts = explode('?', $uri, 1); + $params = null; + + if (count($parts) > 1) { + parse_str($parts[1], $params); + } + + $parts = explode(':', $parts[0], 2); + + if (count($parts) != 3) { + throw new UnexpectedValueException( + 'Not enough parts for scope URI'); + } + + list($scheme, $service, $privilege) = $parts; + return new ScopeURI($service, $privilege, $params); + } + +} \ No newline at end of file diff --git a/Services/Twilio/HttpException.php b/Services/Twilio/HttpException.php new file mode 100644 index 0000000..b79a357 --- /dev/null +++ b/Services/Twilio/HttpException.php @@ -0,0 +1,3 @@ + array( + "headers" => "", + "timeout" => 60, + "follow_location" => true, + "ignore_errors" => true, + ), + "ssl" => array(), + ); + private $options = array(); + + public function __construct($uri = '', $kwargs = array()) { + $this->uri = $uri; + if (isset($kwargs['debug'])) { + $this->debug = true; + } + if (isset($kwargs['http_options'])) { + $this->options = $kwargs['http_options'] + self::$default_options; + } else { + $this->options = self::$default_options; + } + } + + public function __call($name, $args) { + list($res, $req_headers, $req_body) = $args + array(0, array(), ''); + + if (strpos($res, 'http') === 0) { + $url = $res; + } else { + $url = $this->uri . $res; + } + + $request_options = $this->options; + + if (isset($req_body) && strlen($req_body) > 0) { + $request_options['http']['content'] = $req_body; + } + + foreach($req_headers as $key => $value) { + $request_options['http']['header'] .= sprintf("%s: %s\r\n", $key, $value); + } + + if (isset($this->auth_header)) { + $request_options['http']['header'] .= $this->auth_header; + } + + $request_options['http']['method'] = strtoupper($name); + $request_options['http']['ignore_errors'] = true; + + if ($this->debug) { + error_log(var_export($request_options, true)); + } + $ctx = stream_context_create($request_options); + $result = file_get_contents($url, false, $ctx); + + if (false === $result) { + throw new Services_Twilio_HttpStreamException( + "Unable to connect to service"); + } + + $status_header = array_shift($http_response_header); + if (1 !== preg_match('#HTTP/\d+\.\d+ (\d+)#', $status_header, $matches)) { + throw new Services_Twilio_HttpStreamException( + "Unable to detect the status code in the HTTP result."); + } + + $status_code = intval($matches[1]); + $response_headers = array(); + + foreach($http_response_header as $header) { + list($key, $val) = explode(":", $header); + $response_headers[trim($key)] = trim($val); + } + + return array($status_code, $response_headers, $result); + } + + public function authenticate($user, $pass) { + if (isset($user) && isset($pass)) { + $this->auth_header = sprintf("Authorization: Basic %s", + base64_encode(sprintf("%s:%s", $user, $pass))); + } else { + $this->auth_header = null; + } + } +} diff --git a/Services/Twilio/IPMessagingInstanceResource.php b/Services/Twilio/IPMessagingInstanceResource.php new file mode 100644 index 0000000..7cf83b0 --- /dev/null +++ b/Services/Twilio/IPMessagingInstanceResource.php @@ -0,0 +1,15 @@ +subresources[$name] = new $type( + $this->client, $this->uri . "/$constantized" + ); + } + } + +} diff --git a/Services/Twilio/IPMessagingListResource.php b/Services/Twilio/IPMessagingListResource.php new file mode 100644 index 0000000..fb265a0 --- /dev/null +++ b/Services/Twilio/IPMessagingListResource.php @@ -0,0 +1,18 @@ +getResourceName(true); + /* + * By default trim the 's' from the end of the list name to get the + * instance name (ex Accounts -> Account). This behavior can be + * overridden by child classes if the rule doesn't work. + */ + if (!isset($this->instance_name)) { + $this->instance_name = "Services_Twilio_Rest_IPMessaging_" . rtrim($name, 's'); + } + + parent::__construct($client, $uri); + } +} diff --git a/Services/Twilio/InstanceResource.php b/Services/Twilio/InstanceResource.php new file mode 100644 index 0000000..0d4932d --- /dev/null +++ b/Services/Twilio/InstanceResource.php @@ -0,0 +1,84 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + * @link http://pear.php.net/package/Services_Twilio + */ + +/** + * Abstraction of an instance resource from the Twilio API. + */ +abstract class Services_Twilio_InstanceResource extends Services_Twilio_Resource { + + /** + * Make a request to the API to update an instance resource + * + * :param mixed $params: An array of updates, or a property name + * :param mixed $value: A value with which to update the resource + * + * :rtype: null + * :throws: a :php:class:`RestException ` if + * the update fails. + */ + public function update($params, $value = null) + { + if (!is_array($params)) { + $params = array($params => $value); + } + $decamelizedParams = $this->client->createData($this->uri, $params); + $this->updateAttributes($decamelizedParams); + } + + /** + * Add all properties from an associative array (the JSON response body) as + * properties on this instance resource, except the URI + * + * :param stdClass $params: An object containing all of the parameters of + * this instance + * :return: Nothing, this is purely side effecting + * :rtype: null + */ + public function updateAttributes($params) { + unset($params->uri); + foreach ($params as $name => $value) { + $this->$name = $value; + } + } + + /** + * Get the value of a property on this resource. + * + * Instead of defining all of the properties of an object directly, we rely + * on the API to tell us which properties an object has. This method will + * query the API to retrieve a property for an object, if it is not already + * set on the object. + * + * If the call is to a subresource, eg ``$client->account->messages``, no + * request is made. + * + * To help with lazy HTTP requests, we don't actually retrieve an object + * from the API unless you really need it. Hence, this function may make API + * requests even if the property you're requesting isn't available on the + * resource. + * + * :param string $key: The property name + * + * :return mixed: Could be anything. + * :throws: a :php:class:`RestException ` if + * the update fails. + */ + public function __get($key) + { + if ($subresource = $this->getSubresources($key)) { + return $subresource; + } + if (!isset($this->$key)) { + $params = $this->client->retrieveData($this->uri); + $this->updateAttributes($params); + } + return $this->$key; + } +} diff --git a/Services/Twilio/JWT.php b/Services/Twilio/JWT.php new file mode 100644 index 0000000..1e3222f --- /dev/null +++ b/Services/Twilio/JWT.php @@ -0,0 +1,164 @@ + + */ +class JWT +{ + /** + * @param string $jwt The JWT + * @param string|null $key The secret key + * @param bool $verify Don't skip verification process + * + * @return object The JWT's payload as a PHP object + */ + public static function decode($jwt, $key = null, $verify = true) + { + $tks = explode('.', $jwt); + if (count($tks) != 3) { + throw new UnexpectedValueException('Wrong number of segments'); + } + list($headb64, $payloadb64, $cryptob64) = $tks; + if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64))) + ) { + throw new UnexpectedValueException('Invalid segment encoding'); + } + if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($payloadb64)) + ) { + throw new UnexpectedValueException('Invalid segment encoding'); + } + $sig = JWT::urlsafeB64Decode($cryptob64); + if ($verify) { + if (empty($header->alg)) { + throw new DomainException('Empty algorithm'); + } + if ($sig != JWT::sign("$headb64.$payloadb64", $key, $header->alg)) { + throw new UnexpectedValueException('Signature verification failed'); + } + } + return $payload; + } + + /** + * @param object|array $payload PHP object or array + * @param string $key The secret key + * @param string $algo The signing algorithm + * @param array $additionalHeaders Additional keys/values to add to the header + * + * @return string A JWT + */ + public static function encode($payload, $key, $algo = 'HS256', $additionalHeaders = array()) + { + $header = array('typ' => 'JWT', 'alg' => $algo); + $header = $header + $additionalHeaders; + + $segments = array(); + $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($header)); + $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($payload)); + $signing_input = implode('.', $segments); + + $signature = JWT::sign($signing_input, $key, $algo); + $segments[] = JWT::urlsafeB64Encode($signature); + + return implode('.', $segments); + } + + /** + * @param string $msg The message to sign + * @param string $key The secret key + * @param string $method The signing algorithm + * + * @return string An encrypted message + */ + public static function sign($msg, $key, $method = 'HS256') + { + $methods = array( + 'HS256' => 'sha256', + 'HS384' => 'sha384', + 'HS512' => 'sha512', + ); + if (empty($methods[$method])) { + throw new DomainException('Algorithm not supported'); + } + return hash_hmac($methods[$method], $msg, $key, true); + } + + /** + * @param string $input JSON string + * + * @return object Object representation of JSON string + */ + public static function jsonDecode($input) + { + $obj = json_decode($input); + if (function_exists('json_last_error') && $errno = json_last_error()) { + JWT::handleJsonError($errno); + } + else if ($obj === null && $input !== 'null') { + throw new DomainException('Null result with non-null input'); + } + return $obj; + } + + /** + * @param object|array $input A PHP object or array + * + * @return string JSON representation of the PHP object or array + */ + public static function jsonEncode($input) + { + $json = json_encode($input); + if (function_exists('json_last_error') && $errno = json_last_error()) { + JWT::handleJsonError($errno); + } + else if ($json === 'null' && $input !== null) { + throw new DomainException('Null result with non-null input'); + } + return $json; + } + + /** + * @param string $input A base64 encoded string + * + * @return string A decoded string + */ + public static function urlsafeB64Decode($input) + { + $padlen = 4 - strlen($input) % 4; + $input .= str_repeat('=', $padlen); + return base64_decode(strtr($input, '-_', '+/')); + } + + /** + * @param string $input Anything really + * + * @return string The base64 encode of what you passed in + */ + public static function urlsafeB64Encode($input) + { + return str_replace('=', '', strtr(base64_encode($input), '+/', '-_')); + } + + /** + * @param int $errno An error number from json_last_error() + * + * @return void + */ + private static function handleJsonError($errno) + { + $messages = array( + JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', + JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', + JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON' + ); + throw new DomainException(isset($messages[$errno]) + ? $messages[$errno] + : 'Unknown JSON error: ' . $errno + ); + } +} \ No newline at end of file diff --git a/Services/Twilio/ListResource.php b/Services/Twilio/ListResource.php new file mode 100644 index 0000000..dad1c0d --- /dev/null +++ b/Services/Twilio/ListResource.php @@ -0,0 +1,182 @@ +`_ and the `Countable + * `_ interfaces. + * + */ +abstract class Services_Twilio_ListResource extends Services_Twilio_Resource + implements IteratorAggregate +{ + + public function __construct($client, $uri) { + $name = $this->getResourceName(true); + /* + * By default trim the 's' from the end of the list name to get the + * instance name (ex Accounts -> Account). This behavior can be + * overridden by child classes if the rule doesn't work. + */ + if (!isset($this->instance_name)) { + $this->instance_name = "Services_Twilio_Rest_" . rtrim($name, 's'); + } + + parent::__construct($client, $uri); + } + + /** + * Gets a resource from this list. + * + * :param string $sid: The resource SID + * :return: The resource + * :rtype: :php:class:`InstanceResource ` + */ + public function get($sid) { + $instance = new $this->instance_name( + $this->client, $this->uri . "/$sid" + ); + // XXX check if this is actually a sid in all cases. + $instance->sid = $sid; + return $instance; + } + + /** + * Construct an :php:class:`InstanceResource + * ` with the specified params. + * + * :param array $params: usually a JSON HTTP response from the API + * :return: An instance with properties + * initialized to the values in the params array. + * :rtype: :php:class:`InstanceResource ` + */ + public function getObjectFromJson($params, $idParam = "sid") + { + if (isset($params->{$idParam})) { + $uri = $this->uri . "/" . $params->{$idParam}; + } else { + $uri = $this->uri; + } + return new $this->instance_name($this->client, $uri, $params); + } + + /** + * Deletes a resource from this list. + * + * :param string $sid: The resource SID + * :rtype: null + */ + public function delete($sid, $params = array()) + { + $this->client->deleteData($this->uri . '/' . $sid, $params); + } + + /** + * Create a resource on the list and then return its representation as an + * InstanceResource. + * + * :param array $params: The parameters with which to create the resource + * + * :return: The created resource + * :rtype: :php:class:`InstanceResource ` + */ + protected function _create($params) + { + $params = $this->client->createData($this->uri, $params); + /* Some methods like verified caller ID don't return sids. */ + if (isset($params->sid)) { + $resource_uri = $this->uri . '/' . $params->sid; + } else { + $resource_uri = $this->uri; + } + return new $this->instance_name($this->client, $resource_uri, $params); + } + + /** + * Returns a page of :php:class:`InstanceResources + * ` from this list. + * + * :param int $page: The start page + * :param int $size: Number of items per page + * :param array $filters: Optional filters + * :param string $deep_paging_uri: if provided, the $page and $size + * parameters will be ignored and this URI will be requested directly. + * + * :return: A page of resources + * :rtype: :php:class:`Services_Twilio_Page` + */ + public function getPage( + $page = 0, $size = 50, $filters = array(), $deep_paging_uri = null + ) { + $list_name = $this->getResourceName(); + if ($deep_paging_uri !== null) { + $page = $this->client->retrieveData($deep_paging_uri, array(), true); + } else { + $page = $this->client->retrieveData($this->uri, array( + 'Page' => $page, + 'PageSize' => $size, + ) + $filters); + } + + /* create a new PHP object for each json obj in the api response. */ + $page->$list_name = array_map( + array($this, 'getObjectFromJson'), + $page->$list_name + ); + if (isset($page->next_page_uri)) { + $next_page_uri = $page->next_page_uri; + } else { + $next_page_uri = null; + } + return new Services_Twilio_Page($page, $list_name, $next_page_uri); + } + + /** + * Returns an iterable list of + * :php:class:`instance resources `. + * + * :param int $page: The start page + * :param int $size: Number of items per page + * :param array $filters: Optional filters. + * The filter array can accept full datetimes when StartTime or DateCreated + * are used. Inequalities should be within the key portion of the array and + * multiple filter parameters can be combined for more specific searches. + * + * .. code-block:: php + * + * array('DateCreated>' => '2011-07-05 08:00:00', 'DateCreated<' => '2011-08-01') + * + * .. code-block:: php + * + * array('StartTime<' => '2011-07-05 08:00:00') + * + * :return: An iterator + * :rtype: :php:class:`Services_Twilio_AutoPagingIterator` + */ + public function getIterator( + $page = 0, $size = 50, $filters = array() + ) { + return new Services_Twilio_AutoPagingIterator( + array($this, 'getPageGenerator'), $page, $size, $filters + ); + } + + /** + * Retrieve a new page of API results, and update iterator parameters. This + * function is called by the paging iterator to retrieve a new page and + * shouldn't be called directly. + */ + public function getPageGenerator( + $page, $size, $filters = array(), $deep_paging_uri = null + ) { + return $this->getPage($page, $size, $filters, $deep_paging_uri); + } +} + diff --git a/Services/Twilio/LookupsInstanceResource.php b/Services/Twilio/LookupsInstanceResource.php new file mode 100644 index 0000000..63685ea --- /dev/null +++ b/Services/Twilio/LookupsInstanceResource.php @@ -0,0 +1,15 @@ +subresources[$name] = new $type( + $this->client, $this->uri . "/$constantized" + ); + } + } + +} diff --git a/Services/Twilio/LookupsListResource.php b/Services/Twilio/LookupsListResource.php new file mode 100644 index 0000000..856d31b --- /dev/null +++ b/Services/Twilio/LookupsListResource.php @@ -0,0 +1,39 @@ +getResourceName(true); + /* + * By default trim the 's' from the end of the list name to get the + * instance name (ex Accounts -> Account). This behavior can be + * overridden by child classes if the rule doesn't work. + */ + if (!isset($this->instance_name)) { + $this->instance_name = "Services_Twilio_Rest_Lookups_" . rtrim($name, 's'); + } + + parent::__construct($client, $uri); + } + + /** + * Gets a resource from this list. Overridden to add + * filter parameters. + * + * :param string $number: The phone number + * :return: The resource + * :rtype: :php:class:`InstanceResource ` + */ + public function get($number, $filters = array()) { + $number = rawurlencode($number); + $full_path = $this->uri . "/$number"; + if (!empty($filters)) { + $full_path .= '?' . http_build_query($filters, '', '&'); + } + + $instance = new $this->instance_name( + $this->client, $full_path + ); + return $instance; + } +} diff --git a/Services/Twilio/MonitorInstanceResource.php b/Services/Twilio/MonitorInstanceResource.php new file mode 100644 index 0000000..bf4c300 --- /dev/null +++ b/Services/Twilio/MonitorInstanceResource.php @@ -0,0 +1,15 @@ +subresources[$name] = new $type( + $this->client, $this->uri . "/$constantized" + ); + } + } + +} diff --git a/Services/Twilio/MonitorListResource.php b/Services/Twilio/MonitorListResource.php new file mode 100644 index 0000000..70604e3 --- /dev/null +++ b/Services/Twilio/MonitorListResource.php @@ -0,0 +1,18 @@ +getResourceName(true); + /* + * By default trim the 's' from the end of the list name to get the + * instance name (ex Accounts -> Account). This behavior can be + * overridden by child classes if the rule doesn't work. + */ + if (!isset($this->instance_name)) { + $this->instance_name = "Services_Twilio_Rest_Monitor_" . rtrim($name, 's'); + } + + parent::__construct($client, $uri); + } +} diff --git a/Services/Twilio/NextGenInstanceResource.php b/Services/Twilio/NextGenInstanceResource.php new file mode 100644 index 0000000..dd17dfe --- /dev/null +++ b/Services/Twilio/NextGenInstanceResource.php @@ -0,0 +1,23 @@ +` if + * the update fails. + */ + public function update($params, $value = null) + { + if (!is_array($params)) { + $params = array($params => $value); + } + $decamelizedParams = $this->client->createData($this->uri, $params, true); + $this->updateAttributes($decamelizedParams); + } +} \ No newline at end of file diff --git a/Services/Twilio/NextGenListResource.php b/Services/Twilio/NextGenListResource.php new file mode 100644 index 0000000..8822d1b --- /dev/null +++ b/Services/Twilio/NextGenListResource.php @@ -0,0 +1,60 @@ +client->retrieveData($deep_paging_uri, array(), true); + } else if ($page == 0) { + $page = $this->client->retrieveData($this->uri, array('Page' => $page, 'PageSize' => $size) + $filters); + } else { + return $this->emptyPage(); + } + + $list_name = $page->meta->key; + if (!isset($list_name) || $list_name === '') { + throw new Services_Twilio_HttpException("Couldn't find list key in response"); + } + + $page->$list_name = array_map( + array($this, 'getObjectFromJson'), + $page->$list_name + ); + $page->next_page_uri = $page->meta->next_page_url; + + return new Services_Twilio_Page($page, $list_name, $page->meta->next_page_url); + } + + private function emptyPage() { + $page = new stdClass(); + $page->empty = array(); + return new Services_Twilio_Page($page, 'empty'); + } + + /** + * Create a resource on the list and then return its representation as an + * InstanceResource. + * + * :param array $params: The parameters with which to create the resource + * + * :return: The created resource + * :rtype: :php:class:`InstanceResource ` + */ + protected function _create($params) + { + $params = $this->client->createData($this->uri, $params, true); + /* Some methods like verified caller ID don't return sids. */ + if (isset($params->sid)) { + $resource_uri = $this->uri . '/' . $params->sid; + } else { + $resource_uri = $this->uri; + } + return new $this->instance_name($this->client, $resource_uri, $params); + } + + public function count() { + throw new BadMethodCallException("Counting is not supported by this resource"); + } + +} diff --git a/Services/Twilio/NumberType.php b/Services/Twilio/NumberType.php new file mode 100644 index 0000000..0683d99 --- /dev/null +++ b/Services/Twilio/NumberType.php @@ -0,0 +1,35 @@ +instance_name = 'Services_Twilio_Rest_IncomingPhoneNumber'; + return $camelized ? 'IncomingPhoneNumbers' : 'incoming_phone_numbers'; + } + + /** + * Purchase a new phone number. + * + * Example usage: + * + * .. code-block:: php + * + * $marlosBurner = '+14105551234'; + * $client->account->incoming_phone_numbers->local->purchase($marlosBurner); + * + * :param string $phone_number: The phone number to purchase + * :param array $params: An optional array of parameters to pass along with + * the request (to configure the phone number) + */ + public function purchase($phone_number, array $params = array()) { + $postParams = array( + 'PhoneNumber' => $phone_number + ); + return $this->create($postParams + $params); + } + + public function create(array $params = array()) { + return parent::_create($params); + } + +} diff --git a/Services/Twilio/Page.php b/Services/Twilio/Page.php new file mode 100644 index 0000000..61ddb07 --- /dev/null +++ b/Services/Twilio/Page.php @@ -0,0 +1,68 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + * @link http://pear.php.net/package/Services_Twilio + */ +class Services_Twilio_Page + implements IteratorAggregate +{ + + /** + * The item list. + * + * @var array $items + */ + protected $items; + + /** + * Constructs a page. + * + * @param object $page The page object + * @param string $name The key of the item list + */ + public function __construct($page, $name, $next_page_uri = null) + { + $this->page = $page; + $this->items = $page->{$name}; + $this->next_page_uri = $next_page_uri; + } + + /** + * The item list of the page. + * + * @return array A list of instance resources + */ + public function getItems() + { + return $this->items; + } + + /** + * Magic method to allow retrieving the properties of the wrapped page. + * + * @param string $prop The property name + * + * @return mixed Could be anything + */ + public function __get($prop) + { + return $this->page->$prop; + } + + /** + * Implementation of IteratorAggregate::getIterator(). + * + * @return Traversable + */ + public function getIterator() + { + return $this->getItems(); + } +} + diff --git a/Services/Twilio/PartialApplicationHelper.php b/Services/Twilio/PartialApplicationHelper.php new file mode 100644 index 0000000..639ca51 --- /dev/null +++ b/Services/Twilio/PartialApplicationHelper.php @@ -0,0 +1,41 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + * @link http://pear.php.net/package/Services_Twilio + */ +class Services_Twilio_PartialApplicationHelper +{ + private $callbacks; + + public function __construct() + { + $this->callbacks = array(); + } + + public function set($method, $callback, array $args) + { + if (!is_callable($callback)) { + return FALSE; + } + $this->callbacks[$method] = array($callback, $args); + } + + public function __call($method, $args) + { + if (!isset($this->callbacks[$method])) { + throw new Exception("Method not found: $method"); + } + list($callback, $cb_args) = $this->callbacks[$method]; + return call_user_func_array( + $callback, + array_merge($cb_args, $args) + ); + } +} diff --git a/Services/Twilio/PricingInstanceResource.php b/Services/Twilio/PricingInstanceResource.php new file mode 100644 index 0000000..6ae1e18 --- /dev/null +++ b/Services/Twilio/PricingInstanceResource.php @@ -0,0 +1,14 @@ +subresources[$name] = new $type( + $this->client, $this->uri . "/$constantized" + ); + } + } +} diff --git a/Services/Twilio/PricingListResource.php b/Services/Twilio/PricingListResource.php new file mode 100644 index 0000000..cc663e4 --- /dev/null +++ b/Services/Twilio/PricingListResource.php @@ -0,0 +1,14 @@ +getResourceName(true); + + if (!isset($this->instance_name)) { + $this->instance_name = 'Services_Twilio_Rest_Pricing_'. rtrim($name, 's'); + } + + parent::__construct($client, $uri); + } + +} diff --git a/Services/Twilio/RequestValidator.php b/Services/Twilio/RequestValidator.php new file mode 100644 index 0000000..8bfa0db --- /dev/null +++ b/Services/Twilio/RequestValidator.php @@ -0,0 +1,67 @@ +AuthToken = $token; + } + + public function computeSignature($url, $data = array()) + { + // sort the array by keys + ksort($data); + + // append them to the data string in order + // with no delimiters + foreach($data as $key => $value) + $url .= "$key$value"; + + // This function calculates the HMAC hash of the data with the key + // passed in + // Note: hash_hmac requires PHP 5 >= 5.1.2 or PECL hash:1.1-1.5 + // Or http://pear.php.net/package/Crypt_HMAC/ + return base64_encode(hash_hmac("sha1", $url, $this->AuthToken, true)); + } + + public function validate($expectedSignature, $url, $data = array()) + { + return self::compare( + $this->computeSignature($url, $data), + $expectedSignature + ); + } + + /** + * Time insensitive compare, function's runtime is governed by the length + * of the first argument, not the difference between the arguments. + * @param $a string First part of the comparison pair + * @param $b string Second part of the comparison pair + * @return bool True if $a == $b, false otherwise. + */ + public static function compare($a, $b) { + $result = true; + + if (strlen($a) != strlen($b)) { + return false; + } + + if (!$a && !$b) { + return true; + } + + $limit = strlen($a); + + for ($i = 0; $i < $limit; ++$i) { + if ($a[$i] != $b[$i]) { + $result = false; + } + } + + return $result; + } + +} diff --git a/Services/Twilio/Resource.php b/Services/Twilio/Resource.php new file mode 100644 index 0000000..e6f1feb --- /dev/null +++ b/Services/Twilio/Resource.php @@ -0,0 +1,134 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + * @link http://pear.php.net/package/Services_Twilio + */ +abstract class Services_Twilio_Resource { + protected $subresources; + + public function __construct($client, $uri, $params = array()) + { + $this->subresources = array(); + $this->client = $client; + + foreach ($params as $name => $param) { + $this->$name = $param; + } + + $this->uri = $uri; + $this->init($client, $uri); + } + + protected function init($client, $uri) + { + // Left empty for derived classes to implement + } + + public function getSubresources($name = null) { + if (isset($name)) { + return isset($this->subresources[$name]) + ? $this->subresources[$name] + : null; + } + return $this->subresources; + } + + protected function setupSubresources() + { + foreach (func_get_args() as $name) { + $constantized = ucfirst(self::camelize($name)); + $type = "Services_Twilio_Rest_" . $constantized; + $this->subresources[$name] = new $type( + $this->client, $this->uri . "/$constantized" + ); + } + } + + /* + * Get the resource name from the classname + * + * Ex: Services_Twilio_Rest_Accounts -> Accounts + * + * @param boolean $camelized Whether to return camel case or not + */ + public function getResourceName($camelized = false) + { + $name = get_class($this); + $parts = explode('_', $name); + $basename = end($parts); + if ($camelized) { + return $basename; + } else { + return self::decamelize($basename); + } + } + + public static function decamelize($word) + { + $callback = create_function('$matches', + 'return strtolower(strlen("$matches[1]") ? "$matches[1]_$matches[2]" : "$matches[2]");'); + + return preg_replace_callback( + '/(^|[a-z])([A-Z])/', + $callback, + $word + ); + } + + /** + * Return camelized version of a word + * Examples: sms_messages => SMSMessages, calls => Calls, + * incoming_phone_numbers => IncomingPhoneNumbers + * + * @param string $word The word to camelize + * @return string + */ + public static function camelize($word) { + $callback = create_function('$matches', 'return strtoupper("$matches[2]");'); + + return preg_replace_callback('/(^|_)([a-z])/', + $callback, + $word); + } + + /** + * Get the value of a property on this resource. + * + * @param string $key The property name + * @return mixed Could be anything. + */ + public function __get($key) { + if ($subresource = $this->getSubresources($key)) { + return $subresource; + } + return $this->$key; + } + + /** + * Print a JSON representation of this object. Strips the HTTP client + * before returning. + * + * Note, this should mainly be used for debugging, and is not guaranteed + * to correspond 1:1 with the JSON API output. + * + * Note that echoing an object before an HTTP request has been made to + * "fill in" its properties may return an empty object + */ + public function __toString() { + $out = array(); + foreach ($this as $key => $value) { + if ($key !== 'client' && $key !== 'subresources') { + $out[$key] = $value; + } + } + return json_encode($out, true); + } + +} + diff --git a/Services/Twilio/Rest/Account.php b/Services/Twilio/Rest/Account.php new file mode 100644 index 0000000..dc137d3 --- /dev/null +++ b/Services/Twilio/Rest/Account.php @@ -0,0 +1,36 @@ +setupSubresources( + 'applications', + 'available_phone_numbers', + 'outgoing_caller_ids', + 'calls', + 'conferences', + 'incoming_phone_numbers', + 'keys', + 'media', + 'messages', + 'notifications', + 'outgoing_callerids', + 'recordings', + 'sms_messages', + 'short_codes', + 'tokens', + 'transcriptions', + 'connect_apps', + 'authorized_connect_apps', + 'usage_records', + 'usage_triggers', + 'queues', + 'sip', + 'addresses' + ); + + $this->sandbox = new Services_Twilio_Rest_Sandbox( + $client, $uri . '/Sandbox' + ); + } +} diff --git a/Services/Twilio/Rest/Accounts.php b/Services/Twilio/Rest/Accounts.php new file mode 100644 index 0000000..0e7ea0a --- /dev/null +++ b/Services/Twilio/Rest/Accounts.php @@ -0,0 +1,25 @@ +`_ documentation. + */ +class Services_Twilio_Rest_Accounts extends Services_Twilio_ListResource { + + /** + * Create a new subaccount. + * + * :param array $params: An array of parameters describing the new + * subaccount. The ``$params`` array can contain the following keys: + * + * *FriendlyName* + * A description of this account, up to 64 characters long + * + * :returns: The new subaccount + * :rtype: :php:class:`Services_Twilio_Rest_Account` + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/Address.php b/Services/Twilio/Rest/Address.php new file mode 100644 index 0000000..c8a9839 --- /dev/null +++ b/Services/Twilio/Rest/Address.php @@ -0,0 +1,22 @@ +setupSubresources( + 'dependent_phone_numbers' + ); + } + + /** + * Make a request to delete the specified resource. + * + * :rtype: boolean + */ + public function delete() + { + return $this->client->deleteData($this->uri); + } +} diff --git a/Services/Twilio/Rest/Addresses.php b/Services/Twilio/Rest/Addresses.php new file mode 100644 index 0000000..070574e --- /dev/null +++ b/Services/Twilio/Rest/Addresses.php @@ -0,0 +1,22 @@ +instance_name = "Services_Twilio_Rest_Address"; + parent::__construct($client, $uri); + } + + public function create($customerName, $street, $city, $region, $postalCode, $isoCountry, array $params = array()) + { + $params["CustomerName"] = $customerName; + $params["Street"] = $street; + $params["City"] = $city; + $params["Region"] = $region; + $params["PostalCode"] = $postalCode; + $params["IsoCountry"] = $isoCountry; + + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/Application.php b/Services/Twilio/Rest/Application.php new file mode 100644 index 0000000..0db8a05 --- /dev/null +++ b/Services/Twilio/Rest/Application.php @@ -0,0 +1,6 @@ + $name + ) + $params); + } +} diff --git a/Services/Twilio/Rest/AuthorizedConnectApp.php b/Services/Twilio/Rest/AuthorizedConnectApp.php new file mode 100644 index 0000000..0372629 --- /dev/null +++ b/Services/Twilio/Rest/AuthorizedConnectApp.php @@ -0,0 +1,6 @@ +set( + 'getList', + array($this, 'getList'), + array($country, 'Local') + ); + return $curried; + } + public function getTollFree($country) { + $curried = new Services_Twilio_PartialApplicationHelper(); + $curried->set( + 'getList', + array($this, 'getList'), + array($country, 'TollFree') + ); + return $curried; + } + + public function getMobile($country) + { + $curried = new Services_Twilio_PartialApplicationHelper(); + $curried->set( + 'getList', + array($this, 'getList'), + array($country, 'Mobile') + ); + return $curried; + } + + /** + * Get a list of available phone numbers. + * + * @param string $country The 2-digit country code you'd like to search for + * numbers e.g. ('US', 'CA', 'GB') + * @param string $type The type of number ('Local', 'TollFree', or 'Mobile') + * @return object The object representation of the resource + */ + public function getList($country, $type, array $params = array()) + { + return $this->client->retrieveData($this->uri . "/$country/$type", $params); + } + + public function getResourceName($camelized = false) { + // You can't page through the list of available phone numbers. + $this->instance_name = 'Services_Twilio_Rest_AvailablePhoneNumber'; + return $camelized ? 'Countries' : 'countries'; + } +} diff --git a/Services/Twilio/Rest/Call.php b/Services/Twilio/Rest/Call.php new file mode 100644 index 0000000..1a9f696 --- /dev/null +++ b/Services/Twilio/Rest/Call.php @@ -0,0 +1,116 @@ +`_ documentation. + * + * .. php:attr:: sid + * + * A 34 character string that uniquely identifies this resource. + * + * .. php:attr:: parent_call_sid + * + * A 34 character string that uniquely identifies the call that created this leg. + * + * .. php:attr:: date_created + * + * The date that this resource was created, given as GMT in RFC 2822 format. + * + * .. php:attr:: date_updated + * + * The date that this resource was last updated, given as GMT in RFC 2822 format. + * + * .. php:attr:: account_sid + * + * The unique id of the Account responsible for creating this call. + * + * .. php:attr:: to + * + * The phone number that received this call. e.g., +16175551212 (E.164 format) + * + * .. php:attr:: from + * + * The phone number that made this call. e.g., +16175551212 (E.164 format) + * + * .. php:attr:: phone_number_sid + * + * If the call was inbound, this is the Sid of the IncomingPhoneNumber that + * received the call. If the call was outbound, it is the Sid of the + * OutgoingCallerId from which the call was placed. + * + * .. php:attr:: status + * + * A string representing the status of the call. May be `QUEUED`, `RINGING`, + * `IN-PROGRESS`, `COMPLETED`, `FAILED`, `BUSY` or `NO_ANSWER`. + * + * .. php:attr:: start_time + * + * The start time of the call, given as GMT in RFC 2822 format. Empty if the call has not yet been dialed. + * + * .. php:attr:: end_time + * + * The end time of the call, given as GMT in RFC 2822 format. Empty if the call did not complete successfully. + * + * .. php:attr:: duration + * + * The length of the call in seconds. This value is empty for busy, failed, unanswered or ongoing calls. + * + * .. php:attr:: price + * + * The charge for this call in USD. Populated after the call is completed. May not be immediately available. + * + * .. php:attr:: direction + * + * A string describing the direction of the call. inbound for inbound + * calls, outbound-api for calls initiated via the REST API or + * outbound-dial for calls initiated by a verb. + * + * .. php:attr:: answered_by + * + * If this call was initiated with answering machine detection, either human or machine. Empty otherwise. + * + * .. php:attr:: forwarded_from + * + * If this call was an incoming call forwarded from another number, the + * forwarding phone number (depends on carrier supporting forwarding). + * Empty otherwise. + * + * .. php:attr:: caller_name + * + * If this call was an incoming call from a phone number with Caller ID Lookup enabled, the caller's name. Empty otherwise. + */ +class Services_Twilio_Rest_Call extends Services_Twilio_InstanceResource { + + /** + * Hang up the call + */ + public function hangup() { + $this->update('Status', 'completed'); + } + + /** + * Redirect the call to a new URL + * + * :param string $url: the new URL to retrieve call flow from. + */ + public function route($url) { + $this->update('Url', $url); + } + + protected function init($client, $uri) { + $this->setupSubresources( + 'notifications', + 'recordings', + 'feedback' + ); + } + + /** + * Make a request to delete the specified resource. + * + * :rtype: boolean + */ + public function delete() + { + return $this->client->deleteData($this->uri); + } +} diff --git a/Services/Twilio/Rest/Calls.php b/Services/Twilio/Rest/Calls.php new file mode 100644 index 0000000..a140654 --- /dev/null +++ b/Services/Twilio/Rest/Calls.php @@ -0,0 +1,77 @@ +setupSubresources( + 'feedback_summary' + ); + } + + public static function isApplicationSid($value) + { + return strlen($value) == 34 + && !(strpos($value, "AP") === false); + } + + public function create($from, $to, $url, array $params = array()) + { + + $params["To"] = $to; + $params["From"] = $from; + + if (self::isApplicationSid($url)) { + $params["ApplicationSid"] = $url; + } else { + $params["Url"] = $url; + } + + return parent::_create($params); + } + + /** + * Create a feedback for a call. + * + * @param $callSid + * @param $qualityScore + * @param array $issue + * @return Services_Twilio_Rest_Feedback + */ + public function createFeedback($callSid, $qualityScore, array $issue = array()) + { + $params["QualityScore"] = $qualityScore; + $params["Issue"] = $issue; + + $feedbackUri = $this->uri . '/' . $callSid . '/Feedback'; + + $response = $this->client->createData($feedbackUri, $params); + return new Services_Twilio_Rest_Feedback($this->client, $feedbackUri, $response); + } + + /** + * Delete a feedback for a call. + * + * @param $callSid + */ + public function deleteFeedback($callSid) + { + $feedbackUri = $this->uri . '/' . $callSid . '/Feedback'; + $this->client->deleteData($feedbackUri); + } + + /** + * Get a feedback for a call. + * + * @param $callSid + * @return Services_Twilio_Rest_Feedback + */ + public function getFeedback($callSid) + { + $feedbackUri = $this->uri . '/' . $callSid . '/Feedback'; + $response = $this->client->retrieveData($feedbackUri); + return new Services_Twilio_Rest_Feedback($this->client, $feedbackUri, $response); + } +} diff --git a/Services/Twilio/Rest/Conference.php b/Services/Twilio/Rest/Conference.php new file mode 100644 index 0000000..9a36916 --- /dev/null +++ b/Services/Twilio/Rest/Conference.php @@ -0,0 +1,12 @@ +setupSubresources( + 'participants' + ); + } +} diff --git a/Services/Twilio/Rest/Conferences.php b/Services/Twilio/Rest/Conferences.php new file mode 100644 index 0000000..5e92e37 --- /dev/null +++ b/Services/Twilio/Rest/Conferences.php @@ -0,0 +1,6 @@ +setupSubresources( + 'credentials' + ); + } +} + diff --git a/Services/Twilio/Rest/CredentialListMapping.php b/Services/Twilio/Rest/CredentialListMapping.php new file mode 100644 index 0000000..3f9c305 --- /dev/null +++ b/Services/Twilio/Rest/CredentialListMapping.php @@ -0,0 +1,37 @@ +setupSubresources( + 'credentials' + ); + } +} diff --git a/Services/Twilio/Rest/CredentialListMappings.php b/Services/Twilio/Rest/CredentialListMappings.php new file mode 100644 index 0000000..ab34f60 --- /dev/null +++ b/Services/Twilio/Rest/CredentialListMappings.php @@ -0,0 +1,24 @@ +account->sip->domains->get('SDXXX')->credential_list_mappings->create("CLXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); + * + * :param string $credential_list_sid: the sid of the CredentialList you're adding to this domain. + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($credential_list_sid, $params = array()) { + return parent::_create(array( + 'CredentialListSid' => $credential_list_sid, + ) + $params); + } +} + diff --git a/Services/Twilio/Rest/CredentialLists.php b/Services/Twilio/Rest/CredentialLists.php new file mode 100644 index 0000000..e8eb1a6 --- /dev/null +++ b/Services/Twilio/Rest/CredentialLists.php @@ -0,0 +1,24 @@ +account->sip->credential_lists->create("MyFriendlyName"); + * + * :param string $friendly_name: the friendly name of this credential list + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($friendly_name, $params = array()) { + return parent::_create(array( + 'FriendlyName' => $friendly_name, + ) + $params); + } + +} diff --git a/Services/Twilio/Rest/Credentials.php b/Services/Twilio/Rest/Credentials.php new file mode 100644 index 0000000..129a44d --- /dev/null +++ b/Services/Twilio/Rest/Credentials.php @@ -0,0 +1,28 @@ +account->sip->credential_lists->get('CLXXX')->credentials->create( + * "AwesomeUsername", "SuperSecretPassword", + * ); + * + * :param string $username: the username for the new Credential object + * :param string $password: the password for the new Credential object + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($username, $password, $params = array()) { + return parent::_create(array( + 'Username' => $username, + 'Password' => $password, + ) + $params); + } + +} diff --git a/Services/Twilio/Rest/DependentPhoneNumber.php b/Services/Twilio/Rest/DependentPhoneNumber.php new file mode 100644 index 0000000..a9402d0 --- /dev/null +++ b/Services/Twilio/Rest/DependentPhoneNumber.php @@ -0,0 +1,6 @@ +setupSubresources( + 'ip_access_control_list_mappings', + 'credential_list_mappings' + ); + } +} diff --git a/Services/Twilio/Rest/Domains.php b/Services/Twilio/Rest/Domains.php new file mode 100644 index 0000000..041c080 --- /dev/null +++ b/Services/Twilio/Rest/Domains.php @@ -0,0 +1,28 @@ +account->sip->domains->create( + * "MyFriendlyName", "MyDomainName" + * ); + * + * :param string $friendly_name: the friendly name of this domain + * :param string $domain_name: the domain name for this domain + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($friendly_name, $domain_name, $params = array()) { + return parent::_create(array( + 'FriendlyName' => $friendly_name, + 'DomainName' => $domain_name, + ) + $params); + } +} + diff --git a/Services/Twilio/Rest/Feedback.php b/Services/Twilio/Rest/Feedback.php new file mode 100644 index 0000000..ed210f6 --- /dev/null +++ b/Services/Twilio/Rest/Feedback.php @@ -0,0 +1,34 @@ +instance_name = "Services_Twilio_Rest_Feedback"; + return parent::__construct($client, $uri, $params); + } + + /** + * Create feedback for the parent call + */ + public function create(array $params = array()) { + $params = $this->client->createData($this->uri, $params); + return new $this->instance_name($this->client, $this->uri, $params); + } + + /** + * Delete feedback for the parent call + */ + public function delete() { + $this->client->deleteData($this->uri); + } + + /** + * Fetch the feedback for the parent call + */ + public function get() { + return new $this->instance_name( + $this->client, $this->uri + ); + } + +} diff --git a/Services/Twilio/Rest/FeedbackSummary.php b/Services/Twilio/Rest/FeedbackSummary.php new file mode 100644 index 0000000..e6e49e0 --- /dev/null +++ b/Services/Twilio/Rest/FeedbackSummary.php @@ -0,0 +1,33 @@ +instance_name = "Services_Twilio_Rest_FeedbackSummary"; + return parent::__construct($client, $uri, $params); + } + + /** + * Create feedback summary for calls + */ + public function create(array $params = array()) { + $params = $this->client->createData($this->uri, $params); + return new $this->instance_name($this->client, $this->uri, $params); + } + + /** + * Delete a feedback summary + */ + public function delete($sid) { + $this->client->deleteData($this->uri . '/' . $sid); + } + + /** + * Get a feedback summary + */ + public function get($sid) { + return new $this->instance_name( + $this->client, $this->uri . '/' . $sid + ); + } +} diff --git a/Services/Twilio/Rest/IPMessaging/Channel.php b/Services/Twilio/Rest/IPMessaging/Channel.php new file mode 100644 index 0000000..bf8d4d0 --- /dev/null +++ b/Services/Twilio/Rest/IPMessaging/Channel.php @@ -0,0 +1,10 @@ +setupSubresources( + 'members', + 'messages' + ); + } +} diff --git a/Services/Twilio/Rest/IPMessaging/Channels.php b/Services/Twilio/Rest/IPMessaging/Channels.php new file mode 100644 index 0000000..12352c0 --- /dev/null +++ b/Services/Twilio/Rest/IPMessaging/Channels.php @@ -0,0 +1,23 @@ +services->get('SV123')->channels->create(array( + * "FriendlyName" => "TestChannel", + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/IPMessaging/Credential.php b/Services/Twilio/Rest/IPMessaging/Credential.php new file mode 100644 index 0000000..715403e --- /dev/null +++ b/Services/Twilio/Rest/IPMessaging/Credential.php @@ -0,0 +1,5 @@ +credentials->create(array( + * "FriendlyName" => "TestCredential", + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/IPMessaging/Member.php b/Services/Twilio/Rest/IPMessaging/Member.php new file mode 100644 index 0000000..7a83792 --- /dev/null +++ b/Services/Twilio/Rest/IPMessaging/Member.php @@ -0,0 +1,5 @@ +channels->get('CH123')->members->create(array( + * "FriendlyName" => "TestMember", + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/IPMessaging/Message.php b/Services/Twilio/Rest/IPMessaging/Message.php new file mode 100644 index 0000000..b65cf6d --- /dev/null +++ b/Services/Twilio/Rest/IPMessaging/Message.php @@ -0,0 +1,5 @@ +channels->get('CH123')->messages->create(array( + * "Body" => "TestMessage", + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/IPMessaging/Role.php b/Services/Twilio/Rest/IPMessaging/Role.php new file mode 100644 index 0000000..08eba7f --- /dev/null +++ b/Services/Twilio/Rest/IPMessaging/Role.php @@ -0,0 +1,5 @@ +services->get('SV123')->roles->create(array( + * "FriendlyName" => "TestRole", + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/IPMessaging/Service.php b/Services/Twilio/Rest/IPMessaging/Service.php new file mode 100644 index 0000000..775591c --- /dev/null +++ b/Services/Twilio/Rest/IPMessaging/Service.php @@ -0,0 +1,11 @@ +setupSubresources( + 'channels', + 'roles', + 'users' + ); + } +} diff --git a/Services/Twilio/Rest/IPMessaging/Services.php b/Services/Twilio/Rest/IPMessaging/Services.php new file mode 100644 index 0000000..c1f30e3 --- /dev/null +++ b/Services/Twilio/Rest/IPMessaging/Services.php @@ -0,0 +1,23 @@ +services->create(array( + * "Ttl" => 100, + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/IPMessaging/User.php b/Services/Twilio/Rest/IPMessaging/User.php new file mode 100644 index 0000000..c0225b6 --- /dev/null +++ b/Services/Twilio/Rest/IPMessaging/User.php @@ -0,0 +1,5 @@ +credentials->create(array( + * "FriendlyName" => "TestUser", + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/IncomingPhoneNumber.php b/Services/Twilio/Rest/IncomingPhoneNumber.php new file mode 100644 index 0000000..37658fa --- /dev/null +++ b/Services/Twilio/Rest/IncomingPhoneNumber.php @@ -0,0 +1,95 @@ +`_ + * documentation. + * + * .. php:attr:: sid + * + * A 34 character string that uniquely idetifies this resource. + * + * .. php:attr:: date_created + * + * The date that this resource was created, given as GMT RFC 2822 format. + * + * .. php:attr:: date_updated + * + * The date that this resource was last updated, given as GMT RFC 2822 format. + * + * .. php:attr:: friendly_name + * + * A human readable descriptive text for this resource, up to 64 + * characters long. By default, the FriendlyName is a nicely formatted + * version of the phone number. + * + * .. php:attr:: account_sid + * + * The unique id of the Account responsible for this phone number. + * + * .. php:attr:: phone_number + * + * The incoming phone number. e.g., +16175551212 (E.164 format) + * + * .. php:attr:: api_version + * + * Calls to this phone number will start a new TwiML session with this + * API version. + * + * .. php:attr:: voice_caller_id_lookup + * + * Look up the caller's caller-ID name from the CNAM database (additional charges apply). Either true or false. + * + * .. php:attr:: voice_url + * + * The URL Twilio will request when this phone number receives a call. + * + * .. php:attr:: voice_method + * + * The HTTP method Twilio will use when requesting the above Url. Either GET or POST. + * + * .. php:attr:: voice_fallback_url + * + * The URL that Twilio will request if an error occurs retrieving or executing the TwiML requested by Url. + * + * .. php:attr:: voice_fallback_method + * + * The HTTP method Twilio will use when requesting the VoiceFallbackUrl. Either GET or POST. + * + * .. php:attr:: status_callback + * + * The URL that Twilio will request to pass status parameters (such as call ended) to your application. + * + * .. php:attr:: status_callback_method + * + * The HTTP method Twilio will use to make requests to the StatusCallback URL. Either GET or POST. + * + * .. php:attr:: sms_url + * + * The URL Twilio will request when receiving an incoming SMS message to this number. + * + * .. php:attr:: sms_method + * + * The HTTP method Twilio will use when making requests to the SmsUrl. Either GET or POST. + * + * .. php:attr:: sms_fallback_url + * + * The URL that Twilio will request if an error occurs retrieving or executing the TwiML from SmsUrl. + * + * .. php:attr:: sms_fallback_method + * + * The HTTP method Twilio will use when requesting the above URL. Either GET or POST. + * + * .. php:attr:: beta + * + * Whether this number is new to Twilio's inventory. + * + * .. php:attr:: uri + * + * The URI for this resource, relative to https://api.twilio.com. + */ +class Services_Twilio_Rest_IncomingPhoneNumber + extends Services_Twilio_InstanceResource +{ +} diff --git a/Services/Twilio/Rest/IncomingPhoneNumbers.php b/Services/Twilio/Rest/IncomingPhoneNumbers.php new file mode 100644 index 0000000..48ce4ca --- /dev/null +++ b/Services/Twilio/Rest/IncomingPhoneNumbers.php @@ -0,0 +1,59 @@ +`_ + * documentation at twilio.com. + */ +class Services_Twilio_Rest_IncomingPhoneNumbers extends Services_Twilio_ListResource { + function init($client, $uri) { + $this->setupSubresources( + 'local', + 'toll_free', + 'mobile' + ); + } + + function create(array $params = array()) { + return parent::_create($params); + } + + function getList($type, array $params = array()) + { + return $this->client->retrieveData($this->uri . "/$type", $params); + } + + /** + * Return a phone number instance from its E.164 representation. If more + * than one number matches the search string, returns the first one. + * + * Example usage: + * + * .. code-block:: php + * + * $number = $client->account->incoming_phone_numbers->getNumber('+14105551234'); + * echo $number->sid; + * + * :param string $number: The number in E.164 format, eg "+684105551234" + * :return: A :php:class:`Services_Twilio_Rest_IncomingPhoneNumber` object, or null + * :raises: a A :php:class:`Services_Twilio_RestException` if the number is + * invalid, not provided in E.164 format or for any other API exception. + */ + public function getNumber($number) { + $page = $this->getPage(0, 1, array( + 'PhoneNumber' => $number + )); + $items = $page->getItems(); + if (is_null($items) || empty($items)) { + return null; + } + return $items[0]; + } +} + +class Services_Twilio_Rest_Local extends Services_Twilio_NumberType { } + +class Services_Twilio_Rest_Mobile extends Services_Twilio_NumberType { } + +class Services_Twilio_Rest_TollFree extends Services_Twilio_NumberType { } diff --git a/Services/Twilio/Rest/IpAccessControlList.php b/Services/Twilio/Rest/IpAccessControlList.php new file mode 100644 index 0000000..5ba83f3 --- /dev/null +++ b/Services/Twilio/Rest/IpAccessControlList.php @@ -0,0 +1,40 @@ +setupSubresources( + 'ip_addresses' + ); + } +} diff --git a/Services/Twilio/Rest/IpAccessControlListMapping.php b/Services/Twilio/Rest/IpAccessControlListMapping.php new file mode 100644 index 0000000..ce5bc5a --- /dev/null +++ b/Services/Twilio/Rest/IpAccessControlListMapping.php @@ -0,0 +1,37 @@ +setupSubresources( + 'ip_addresses' + ); + } +} + diff --git a/Services/Twilio/Rest/IpAccessControlListMappings.php b/Services/Twilio/Rest/IpAccessControlListMappings.php new file mode 100644 index 0000000..f58e1b9 --- /dev/null +++ b/Services/Twilio/Rest/IpAccessControlListMappings.php @@ -0,0 +1,25 @@ +account->sip->domains->get('SDXXX')->ip_access_control_list_mappings->create("ALXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); + * + * :param string $ip_access_control_list_sid: the sid of the IpAccessControList + * you're adding to this domain. + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($ip_access_control_list_sid, $params = array()) { + return parent::_create(array( + 'IpAccessControlListSid' => $ip_access_control_list_sid, + ) + $params); + } +} + diff --git a/Services/Twilio/Rest/IpAccessControlLists.php b/Services/Twilio/Rest/IpAccessControlLists.php new file mode 100644 index 0000000..88b9d14 --- /dev/null +++ b/Services/Twilio/Rest/IpAccessControlLists.php @@ -0,0 +1,27 @@ +account->sip->ip_access_control_lists->create("MyFriendlyName"); + * + * :param string $friendly_name: the friendly name of this ip access control list + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * :return: the created list + * :rtype: :class:`Services_Twilio_Rest_IpAccessControlList` + * + */ + public function create($friendly_name, $params = array()) { + return parent::_create(array( + 'FriendlyName' => $friendly_name, + ) + $params); + } + +} diff --git a/Services/Twilio/Rest/IpAddress.php b/Services/Twilio/Rest/IpAddress.php new file mode 100644 index 0000000..38b716e --- /dev/null +++ b/Services/Twilio/Rest/IpAddress.php @@ -0,0 +1,34 @@ +instance_name = "Services_Twilio_Rest_IpAddress"; + parent::__construct($client, $uri); + } + + /** + * Creates a new IpAddress instance + * + * Example usage: + * + * .. code-block:: php + * + * $client->account->sip->ip_access_control_lists->get('ALXXX')->ip_addresses->create( + * "FriendlyName", "127.0.0.1" + * ); + * + * :param string $friendly_name: the friendly name for the new IpAddress object + * :param string $ip_address: the ip address for the new IpAddress object + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($friendly_name, $ip_address, $params = array()) { + return parent::_create(array( + 'FriendlyName' => $friendly_name, + 'IpAddress' => $ip_address, + ) + $params); + } +} + diff --git a/Services/Twilio/Rest/Key.php b/Services/Twilio/Rest/Key.php new file mode 100644 index 0000000..4750f5b --- /dev/null +++ b/Services/Twilio/Rest/Key.php @@ -0,0 +1,5 @@ +` objects. + * For the definitive reference, see the `Twilio Media List Documentation + * `_. + */ +class Services_Twilio_Rest_Media extends Services_Twilio_ListResource { + + + // This is overridden because the list key in the Twilio response + // is "media_list", not "media". + public function getResourceName($camelized = false) + { + if ($camelized) { + return "MediaList"; + } else { + return "media_list"; + } + } + + // We manually set the instance name here so that the parent + // constructor doesn't attempt to figure out it. It would do it + // incorrectly because we override getResourceName above. + public function __construct($client, $uri) { + $this->instance_name = "Services_Twilio_Rest_MediaInstance"; + parent::__construct($client, $uri); + } + +} + diff --git a/Services/Twilio/Rest/MediaInstance.php b/Services/Twilio/Rest/MediaInstance.php new file mode 100644 index 0000000..1a152b2 --- /dev/null +++ b/Services/Twilio/Rest/MediaInstance.php @@ -0,0 +1,37 @@ +`_. + * + * .. php:attr:: sid + * + * A 34 character string that identifies this object + * + * .. php:attr:: account_sid + * + * A 34 character string representing the account that sent the message + * + * .. php:attr:: parent_sid + * + * The sid of the message that created this media. + * + * .. php:attr:: date_created + * + * The date the message was created + * + * .. php:attr:: date_updated + * + * The date the message was updated + * + * .. php:attr:: content_type + * + * The content-type of the media. + */ +class Services_Twilio_Rest_MediaInstance extends Services_Twilio_InstanceResource { + public function __construct($client, $uri) { + $uri = str_replace('MediaInstance', 'Media', $uri); + parent::__construct($client, $uri); + } +} + diff --git a/Services/Twilio/Rest/Member.php b/Services/Twilio/Rest/Member.php new file mode 100644 index 0000000..8067cdd --- /dev/null +++ b/Services/Twilio/Rest/Member.php @@ -0,0 +1,22 @@ + $url, + 'Method' => $method, + )); + } +} diff --git a/Services/Twilio/Rest/Members.php b/Services/Twilio/Rest/Members.php new file mode 100644 index 0000000..61e05de --- /dev/null +++ b/Services/Twilio/Rest/Members.php @@ -0,0 +1,28 @@ +instance_name($this->client, $this->uri . '/Front'); + } + + /* Participants are identified by CallSid, not like ME123 */ + public function getObjectFromJson($params, $idParam = 'sid') { + return parent::getObjectFromJson($params, 'call_sid'); + } + + public function getResourceName($camelized = false) + { + // The JSON property name is atypical. + return $camelized ? 'Members' : 'queue_members'; + } +} + diff --git a/Services/Twilio/Rest/Message.php b/Services/Twilio/Rest/Message.php new file mode 100644 index 0000000..2ca32e8 --- /dev/null +++ b/Services/Twilio/Rest/Message.php @@ -0,0 +1,68 @@ +setupSubresources( + 'media' + ); + } + + public function redact() { + $postParams = array('Body' => ''); + self::update($postParams); + } + + /** + * Make a request to delete the specified resource. + * + * :rtype: boolean + */ + public function delete() + { + return $this->client->deleteData($this->uri); + } +} + diff --git a/Services/Twilio/Rest/Messages.php b/Services/Twilio/Rest/Messages.php new file mode 100644 index 0000000..355fce0 --- /dev/null +++ b/Services/Twilio/Rest/Messages.php @@ -0,0 +1,73 @@ +account->messages->create(array( + * "Body" => "foo", + * "From" => "+14105551234", + * "To" => "+14105556789", + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. You may find it easier to use the + * sendMessage helper instead of this function. + * + */ + public function create($params = array()) { + return parent::_create($params); + } + + /** + * Send a message + * + * .. code-block:: php + * + * $client = new Services_Twilio('AC123', '123'); + * $message = $client->account->messages->sendMessage( + * '+14105551234', // From a Twilio number in your account + * '+14105556789', // Text any number + * 'Come at the king, you best not miss.' // Message body (if any) + * array('https://demo.twilio.com/owl.png'), // An array of MediaUrls + * ); + * + * :param string $from: the from number for the message, this must be a + * number you purchased from Twilio + * :param string $to: the message recipient's phone number + * :param $mediaUrls: the URLs of images to send in this MMS + * :type $mediaUrls: null (don't include media), a single URL, or an array + * of URLs to send as media with this message + * :param string $body: the text to include along with this MMS + * :param array $params: Any additional params (callback, etc) you'd like to + * send with this request, these are serialized and sent as POST + * parameters + * + * :return: The created :class:`Services_Twilio_Rest_Message` + * :raises: :class:`Services_Twilio_RestException` + * An exception if the parameters are invalid (for example, the from + * number is not a Twilio number registered to your account, or is + * unable to send MMS) + */ + public function sendMessage($from, $to, $body = null, $mediaUrls = null, + $params = array() + ) { + $postParams = array( + 'From' => $from, + 'To' => $to, + ); + // When the request is made, this will get serialized into MediaUrl=a&MediaUrl=b + if (!is_null($mediaUrls)) { + $postParams['MediaUrl'] = $mediaUrls; + } + if (!is_null($body)) { + $postParams['Body'] = $body; + } + return self::create($postParams + $params); + } +} diff --git a/Services/Twilio/Rest/Monitor/Alert.php b/Services/Twilio/Rest/Monitor/Alert.php new file mode 100644 index 0000000..31bc1b4 --- /dev/null +++ b/Services/Twilio/Rest/Monitor/Alert.php @@ -0,0 +1,5 @@ + $phoneNumber, + ) + $params); + } +} diff --git a/Services/Twilio/Rest/Participant.php b/Services/Twilio/Rest/Participant.php new file mode 100644 index 0000000..b62920b --- /dev/null +++ b/Services/Twilio/Rest/Participant.php @@ -0,0 +1,10 @@ +update('Muted', 'true'); + } +} diff --git a/Services/Twilio/Rest/Participants.php b/Services/Twilio/Rest/Participants.php new file mode 100644 index 0000000..3b0464e --- /dev/null +++ b/Services/Twilio/Rest/Participants.php @@ -0,0 +1,10 @@ +instance_name = "Services_Twilio_Rest_Pricing_MessagingCountry"; + parent::__construct($client, $uri); + } + + public function get($isoCountry) { + $instance = new $this->instance_name($this->client, $this->uri . "/$isoCountry"); + $instance->iso_country = $isoCountry; + return $instance; + } +} diff --git a/Services/Twilio/Rest/Pricing/MessagingCountry.php b/Services/Twilio/Rest/Pricing/MessagingCountry.php new file mode 100644 index 0000000..e39cc4e --- /dev/null +++ b/Services/Twilio/Rest/Pricing/MessagingCountry.php @@ -0,0 +1,5 @@ +instance_name = 'Services_Twilio_Rest_Pricing_PhoneNumberCountry'; + parent::__construct($client, $uri); + } + + public function getResourceName($camelized = false) { + if ($camelized) { + return 'Countries'; + } + return 'countries'; + } + + public function get($isoCountry) { + $instance = new $this->instance_name($this->client, $this->uri . "/$isoCountry"); + $instance->iso_country = $isoCountry; + return $instance; + } +} \ No newline at end of file diff --git a/Services/Twilio/Rest/Pricing/PhoneNumberCountry.php b/Services/Twilio/Rest/Pricing/PhoneNumberCountry.php new file mode 100644 index 0000000..ac840b8 --- /dev/null +++ b/Services/Twilio/Rest/Pricing/PhoneNumberCountry.php @@ -0,0 +1,4 @@ +instance_name = "Services_Twilio_Rest_Pricing_VoiceCountry"; + parent::__construct($client, $uri); + } + + public function get($isoCountry) { + $instance = new $this->instance_name($this->client, $this->uri . "/$isoCountry"); + $instance->iso_country = $isoCountry; + return $instance; + } +} \ No newline at end of file diff --git a/Services/Twilio/Rest/Pricing/VoiceCountry.php b/Services/Twilio/Rest/Pricing/VoiceCountry.php new file mode 100644 index 0000000..5252694 --- /dev/null +++ b/Services/Twilio/Rest/Pricing/VoiceCountry.php @@ -0,0 +1,5 @@ +instance_name($this->client, $this->uri . "/$number"); + $instance->number = $number; + return $instance; + } +} \ No newline at end of file diff --git a/Services/Twilio/Rest/Queue.php b/Services/Twilio/Rest/Queue.php new file mode 100644 index 0000000..fa0f2f7 --- /dev/null +++ b/Services/Twilio/Rest/Queue.php @@ -0,0 +1,10 @@ +setupSubresources('members'); + } +} + diff --git a/Services/Twilio/Rest/Queues.php b/Services/Twilio/Rest/Queues.php new file mode 100644 index 0000000..bc35c83 --- /dev/null +++ b/Services/Twilio/Rest/Queues.php @@ -0,0 +1,19 @@ + $friendly_name, + ) + $params); + } +} + diff --git a/Services/Twilio/Rest/Recording.php b/Services/Twilio/Rest/Recording.php new file mode 100644 index 0000000..a76014c --- /dev/null +++ b/Services/Twilio/Rest/Recording.php @@ -0,0 +1,9 @@ +setupSubresources('transcriptions'); + } +} diff --git a/Services/Twilio/Rest/Recordings.php b/Services/Twilio/Rest/Recordings.php new file mode 100644 index 0000000..47ec0d5 --- /dev/null +++ b/Services/Twilio/Rest/Recordings.php @@ -0,0 +1,6 @@ +setupSubresources( + 'domains', + 'ip_access_control_lists', + 'credential_lists' + ); + } + + public function getResourceName($camelized = false) { + return "SIP"; + } +} diff --git a/Services/Twilio/Rest/SmsMessage.php b/Services/Twilio/Rest/SmsMessage.php new file mode 100644 index 0000000..6bd3f9c --- /dev/null +++ b/Services/Twilio/Rest/SmsMessage.php @@ -0,0 +1,6 @@ + $from, + 'To' => $to, + 'Body' => $body + ) + $params); + } +} diff --git a/Services/Twilio/Rest/TaskRouter/Activities.php b/Services/Twilio/Rest/TaskRouter/Activities.php new file mode 100644 index 0000000..9b1f90f --- /dev/null +++ b/Services/Twilio/Rest/TaskRouter/Activities.php @@ -0,0 +1,15 @@ +instance_name = "Services_Twilio_Rest_TaskRouter_Activity"; + parent::__construct($client, $uri); + } + + public function create($friendlyName, $available) { + $params['FriendlyName'] = $friendlyName; + $params['Available'] = $available; + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/TaskRouter/Activity.php b/Services/Twilio/Rest/TaskRouter/Activity.php new file mode 100644 index 0000000..08f0633 --- /dev/null +++ b/Services/Twilio/Rest/TaskRouter/Activity.php @@ -0,0 +1,5 @@ +client->retrieveData($this->uri, $filters); + } +} diff --git a/Services/Twilio/Rest/TaskRouter/Task.php b/Services/Twilio/Rest/TaskRouter/Task.php new file mode 100644 index 0000000..ace660b --- /dev/null +++ b/Services/Twilio/Rest/TaskRouter/Task.php @@ -0,0 +1,9 @@ +setupSubresources('reservations'); + } + +} diff --git a/Services/Twilio/Rest/TaskRouter/TaskQueue.php b/Services/Twilio/Rest/TaskRouter/TaskQueue.php new file mode 100644 index 0000000..2e6fae6 --- /dev/null +++ b/Services/Twilio/Rest/TaskRouter/TaskQueue.php @@ -0,0 +1,8 @@ +setupSubresource('statistics'); + } +} diff --git a/Services/Twilio/Rest/TaskRouter/TaskQueueStatistics.php b/Services/Twilio/Rest/TaskRouter/TaskQueueStatistics.php new file mode 100644 index 0000000..73ce98e --- /dev/null +++ b/Services/Twilio/Rest/TaskRouter/TaskQueueStatistics.php @@ -0,0 +1,5 @@ +setupSubresource('statistics'); + } +} diff --git a/Services/Twilio/Rest/TaskRouter/TaskQueuesStatistics.php b/Services/Twilio/Rest/TaskRouter/TaskQueuesStatistics.php new file mode 100644 index 0000000..e2b25b5 --- /dev/null +++ b/Services/Twilio/Rest/TaskRouter/TaskQueuesStatistics.php @@ -0,0 +1,9 @@ +instance_name = "Services_Twilio_Rest_TaskRouter_TaskQueueStatistics"; + parent::__construct($client, $uri); + } +} diff --git a/Services/Twilio/Rest/TaskRouter/Tasks.php b/Services/Twilio/Rest/TaskRouter/Tasks.php new file mode 100644 index 0000000..d9d193b --- /dev/null +++ b/Services/Twilio/Rest/TaskRouter/Tasks.php @@ -0,0 +1,11 @@ +setupSubresource('statistics'); + $this->setupSubresources('reservations'); + } +} diff --git a/Services/Twilio/Rest/TaskRouter/WorkerStatistics.php b/Services/Twilio/Rest/TaskRouter/WorkerStatistics.php new file mode 100644 index 0000000..4c8c26a --- /dev/null +++ b/Services/Twilio/Rest/TaskRouter/WorkerStatistics.php @@ -0,0 +1,5 @@ +setupSubresource('statistics'); + } +} diff --git a/Services/Twilio/Rest/TaskRouter/WorkersStatistics.php b/Services/Twilio/Rest/TaskRouter/WorkersStatistics.php new file mode 100644 index 0000000..95455dd --- /dev/null +++ b/Services/Twilio/Rest/TaskRouter/WorkersStatistics.php @@ -0,0 +1,5 @@ +setupSubresource('statistics'); + } +} diff --git a/Services/Twilio/Rest/TaskRouter/WorkflowStatistics.php b/Services/Twilio/Rest/TaskRouter/WorkflowStatistics.php new file mode 100644 index 0000000..98b9693 --- /dev/null +++ b/Services/Twilio/Rest/TaskRouter/WorkflowStatistics.php @@ -0,0 +1,5 @@ +setupSubresources( + 'activities', + 'events', + 'tasks', + 'task_queues', + 'workers', + 'workflows' + ); + $this->setupSubresource('statistics'); + } +} diff --git a/Services/Twilio/Rest/TaskRouter/WorkspaceStatistics.php b/Services/Twilio/Rest/TaskRouter/WorkspaceStatistics.php new file mode 100644 index 0000000..f5eae06 --- /dev/null +++ b/Services/Twilio/Rest/TaskRouter/WorkspaceStatistics.php @@ -0,0 +1,5 @@ +account->tokens->create(array( + * "Ttl" => 100, + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } + +} diff --git a/Services/Twilio/Rest/Transcription.php b/Services/Twilio/Rest/Transcription.php new file mode 100644 index 0000000..83c139c --- /dev/null +++ b/Services/Twilio/Rest/Transcription.php @@ -0,0 +1,6 @@ +trunks->get('TK123')->credential_lists->create(array( + * "CredentialListSid" => "CL1234xxxxx", + * .... + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/Trunking/IpAccessControlList.php b/Services/Twilio/Rest/Trunking/IpAccessControlList.php new file mode 100644 index 0000000..f66eae6 --- /dev/null +++ b/Services/Twilio/Rest/Trunking/IpAccessControlList.php @@ -0,0 +1,5 @@ +trunks->get('TK123')->ip_access_control_lists->create(array( + * "IpAccessControlListSid" => "AL1234xxxx", + * .... + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/Trunking/OriginationUrl.php b/Services/Twilio/Rest/Trunking/OriginationUrl.php new file mode 100644 index 0000000..0d56c78 --- /dev/null +++ b/Services/Twilio/Rest/Trunking/OriginationUrl.php @@ -0,0 +1,5 @@ +trunks->get('TK123')->origination_urls->create(array( + * "FriendlyName" => "TestUrl", + * .... + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/Trunking/PhoneNumber.php b/Services/Twilio/Rest/Trunking/PhoneNumber.php new file mode 100644 index 0000000..9495f81 --- /dev/null +++ b/Services/Twilio/Rest/Trunking/PhoneNumber.php @@ -0,0 +1,5 @@ +trunks->get('TK123')->phone_numbers->create(array( + * "PhoneNumberSid" => "PN1234xxxx" + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/Services/Twilio/Rest/Trunking/Trunk.php b/Services/Twilio/Rest/Trunking/Trunk.php new file mode 100644 index 0000000..0d93b9e --- /dev/null +++ b/Services/Twilio/Rest/Trunking/Trunk.php @@ -0,0 +1,13 @@ +setupSubresources( + 'credential_lists', + 'ip_access_control_lists', + 'origination_urls', + 'phone_numbers' + ); + } +} diff --git a/Services/Twilio/Rest/Trunking/Trunks.php b/Services/Twilio/Rest/Trunking/Trunks.php new file mode 100644 index 0000000..9c76ef2 --- /dev/null +++ b/Services/Twilio/Rest/Trunking/Trunks.php @@ -0,0 +1,5 @@ +setupSubresources( + 'today', + 'yesterday', + 'all_time', + 'this_month', + 'last_month', + 'daily', + 'monthly', + 'yearly' + ); + } +} + +class Services_Twilio_Rest_Today extends Services_Twilio_TimeRangeResource { } + +class Services_Twilio_Rest_Yesterday extends Services_Twilio_TimeRangeResource { } + +class Services_Twilio_Rest_LastMonth extends Services_Twilio_TimeRangeResource { } + +class Services_Twilio_Rest_ThisMonth extends Services_Twilio_TimeRangeResource { } + +class Services_Twilio_Rest_AllTime extends Services_Twilio_TimeRangeResource { } + +class Services_Twilio_Rest_Daily extends Services_Twilio_UsageResource { } + +class Services_Twilio_Rest_Monthly extends Services_Twilio_UsageResource { } + +class Services_Twilio_Rest_Yearly extends Services_Twilio_UsageResource { } diff --git a/Services/Twilio/Rest/UsageTrigger.php b/Services/Twilio/Rest/UsageTrigger.php new file mode 100644 index 0000000..44c8cf5 --- /dev/null +++ b/Services/Twilio/Rest/UsageTrigger.php @@ -0,0 +1,5 @@ +`_. + * @param string $value Fire the trigger when usage crosses this value. + * @param string $url The URL to request when the trigger fires. + * @param array $params Optional parameters for this trigger. A full list of parameters can be found in the `Usage Trigger documentation `_. + * @return Services_Twilio_Rest_UsageTrigger The created trigger + */ + function create($category, $value, $url, array $params = array()) { + return parent::_create(array( + 'UsageCategory' => $category, + 'TriggerValue' => $value, + 'CallbackUrl' => $url, + ) + $params); + } + +} + diff --git a/Services/Twilio/RestException.php b/Services/Twilio/RestException.php new file mode 100644 index 0000000..c7de16c --- /dev/null +++ b/Services/Twilio/RestException.php @@ -0,0 +1,44 @@ +status = $status; + $this->info = $info; + parent::__construct($message, $code); + } + + /** + * Get the HTTP status code + */ + public function getStatus() { + return $this->status; + } + + /** + * Get a link to more information + */ + public function getInfo() { + return $this->info; + } +} diff --git a/Services/Twilio/SIPListResource.php b/Services/Twilio/SIPListResource.php new file mode 100644 index 0000000..1e63b67 --- /dev/null +++ b/Services/Twilio/SIPListResource.php @@ -0,0 +1,14 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_TaskRouter_Capability extends Services_Twilio_TaskRouter_CapabilityAPI +{ + protected $baseUrl = 'https://taskrouter.twilio.com/v1'; + protected $baseWsUrl = 'https://event-bridge.twilio.com/v1/wschannels'; + protected $version = 'v1'; + + protected $workspaceSid; + protected $channelId; + protected $resourceUrl; + + protected $required = array("required" => true); + protected $optional = array("required" => false); + + public function __construct($accountSid, $authToken, $workspaceSid, $channelId, $resourceUrl = null, $overrideBaseUrl = null, $overrideBaseWSUrl = null) { + parent::__construct($accountSid, $authToken, $this->version, $channelId); + + $this->workspaceSid = $workspaceSid; + $this->channelId = $channelId; + if(isset($overrideBaseUrl)) { + $this->baseUrl = $overrideBaseUrl; + } + if(isset($overrideBaseWSUrl)) { + $this->baseWsUrl = $overrideBaseWSUrl; + } + $this->baseUrl = $this->baseUrl.'/Workspaces/'.$workspaceSid; + + $this->validateJWT(); + + if(!isset($resourceUrl)) { + $this->setupResource(); + } + + //add permissions to GET and POST to the event-bridge channel + $this->allow($this->baseWsUrl."/".$this->accountSid."/".$this->channelId, "GET", null, null); + $this->allow($this->baseWsUrl."/".$this->accountSid."/".$this->channelId, "POST", null, null); + + //add permissions to fetch the instance resource + $this->allow($this->resourceUrl, "GET", null, null); + } + + protected function setupResource() { + if(substr($this->channelId,0,2) == 'WS') { + $this->resourceUrl = $this->baseUrl; + }else if(substr($this->channelId,0,2) == 'WK') { + $this->resourceUrl = $this->baseUrl.'/Workers/'.$this->channelId; + + //add permissions to fetch the list of activities, tasks and worker reservations + $activityUrl = $this->baseUrl.'/Activities'; + $this->allow($activityUrl, "GET", null, null); + + $tasksUrl = $this->baseUrl.'/Tasks/**'; + $this->allow($tasksUrl, "GET", null, null); + + $workerReservationsUrl = $this->resourceUrl.'/Reservations/**'; + $this->allow($workerReservationsUrl, "GET", null, null); + + }else if(substr($this->channelId,0,2) == 'WQ') { + $this->resourceUrl = $this->baseUrl.'/TaskQueues/'.$this->channelId; + } + } + + private function validateJWT() { + if(!isset($this->accountSid) || substr($this->accountSid,0,2) != 'AC') { + throw new Exception("Invalid AccountSid provided: ".$this->accountSid); + } + if(!isset($this->workspaceSid) || substr($this->workspaceSid,0,2) != 'WS') { + throw new Exception("Invalid WorkspaceSid provided: ".$this->workspaceSid); + } + if(!isset($this->channelId)) { + throw new Exception("ChannelId not provided"); + } + $prefix = substr($this->channelId,0,2); + if($prefix != 'WS' && $prefix != 'WK' && $prefix != 'WQ') { + throw new Exception("Invalid ChannelId provided: ".$this->channelId); + } + } + + public function allowFetchSubresources() { + $method = 'GET'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->resourceUrl.'/**', $method, $queryFilter, $postFilter); + } + + public function allowUpdates() { + $method = 'POST'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->resourceUrl, $method, $queryFilter, $postFilter); + } + + public function allowUpdatesSubresources() { + $method = 'POST'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->resourceUrl.'/**', $method, $queryFilter, $postFilter); + } + + public function allowDelete() { + $method = 'DELETE'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->resourceUrl, $method, $queryFilter, $postFilter); + } + + public function allowDeleteSubresources() { + $method = 'DELETE'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->resourceUrl.'/**', $method, $queryFilter, $postFilter); + } + + /** + * @deprecated Please use {Services_Twilio_TaskRouter_Worker_Capability.allowActivityUpdates} instead + */ + public function allowWorkerActivityUpdates() { + $method = 'POST'; + $queryFilter = array(); + $postFilter = array("ActivitySid" => $this->required); + $this->allow($this->resourceUrl, $method, $queryFilter, $postFilter); + } + + /** + * @deprecated Please use {Services_Twilio_TaskRouter_Worker_Capability} instead; added automatically in constructor + */ + public function allowWorkerFetchAttributes() { + $method = 'GET'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->resourceUrl, $method, $queryFilter, $postFilter); + } + + /** + * @deprecated Please use {Services_Twilio_TaskRouter_Worker_Capability.allowReservationUpdates} instead + */ + public function allowTaskReservationUpdates() { + $method = 'POST'; + $queryFilter = array(); + $postFilter = array(); + $reservationsUrl = $this->baseUrl.'/Tasks/**'; + $this->allow($reservationsUrl, $method, $queryFilter, $postFilter); + } + + public function generateToken($ttl = 3600, $extraAttributes = null) { + $taskRouterAttributes = array( + 'account_sid' => $this->accountSid, + 'channel' => $this->channelId, + 'workspace_sid' => $this->workspaceSid + ); + + if(substr($this->channelId,0,2) == 'WK') { + $taskRouterAttributes['worker_sid'] = $this->channelId; + }else if(substr($this->channelId,0,2) == 'WQ') { + $taskRouterAttributes['taskqueue_sid'] = $this->channelId; + } + + return parent::generateToken($ttl, $taskRouterAttributes); + } +} \ No newline at end of file diff --git a/Services/Twilio/TaskRouter/CapabilityAPI.php b/Services/Twilio/TaskRouter/CapabilityAPI.php new file mode 100644 index 0000000..737b40a --- /dev/null +++ b/Services/Twilio/TaskRouter/CapabilityAPI.php @@ -0,0 +1,153 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_TaskRouter_CapabilityAPI +{ + protected $accountSid; + protected $authToken; + private $version; + private $friendlyName; + private $policies; + + public function __construct($accountSid, $authToken, $version, $friendlyName) + { + $this->accountSid = $accountSid; + $this->authToken = $authToken; + $this->version = $version; + $this->friendlyName = $friendlyName; + $this->policies = array(); + } + + public function addPolicyDeconstructed($url, $method, $queryFilter = array(), $postFilter = array(), $allow = true) { + $policy = new Policy($url, $method, $queryFilter, $postFilter, $allow); + array_push($this->policies, $policy); + return $policy; + } + + public function allow($url, $method, $queryFilter = array(), $postFilter = array()) { + $this->addPolicyDeconstructed($url, $method, $queryFilter, $postFilter, true); + } + + public function deny($url, $method, $queryFilter = array(), $postFilter = array()) { + $this->addPolicyDeconstructed($url, $method, $queryFilter, $postFilter, false); + } + + /** + * @deprecated Please use {Services_Twilio_API_Capability.allow, Services_Twilio_API_Capability.disallow} instead + */ + public function addPolicy($policy) { + array_push($this->policies, $policy); + } + + /** + * @deprecated Please use {Services_Twilio_API_Capability.allow, Services_Twilio_API_Capability.disallow} instead + */ + public function generatePolicy($url, $method, $queryFilter = array(), $postFilter = array(), $allow = true) + { + return $this->addPolicyDeconstructed($url, $method, $queryFilter, $postFilter, $allow); + } + + /** + * @deprecated Please use {Services_Twilio_API_Capability.allow, Services_Twilio_API_Capability.disallow} instead + */ + public function generateAndAddPolicy($url, $method, $queryFilter = array(), $postFilter = array(), $allow = true) { + $this->addPolicyDeconstructed($url, $method, $queryFilter, $postFilter, $allow); + } + + /** + * Generates a new token based on the credentials and permissions that + * previously has been granted to this token. + * + * @param $ttl the expiration time of the token (in seconds). Default + * value is 3600 (1hr) + * @param $extraAttributes extra attributes to be tied to the jwt. + * @return the newly generated token that is valid for $ttl seconds + */ + public function generateToken($ttl = 3600, $extraAttributes = null) + { + $payload = array( + 'version' => $this->version, + 'friendly_name' => $this->friendlyName, + 'policies' => array(), + 'iss' => $this->accountSid, + 'exp' => time() + $ttl + ); + if(isset($extraAttributes)) { + foreach ($extraAttributes as $key => $value) { + $payload[$key] = $value; + } + } + + $policyStrings = array(); + + foreach ($this->policies as $policy) { + $policyStrings[] = $policy->toArray(); + } + + $payload['policies'] = $policyStrings; + return JWT::encode($payload, $this->authToken, 'HS256'); + } +} + +/** + * Twilio API Policy constructor + * + * @category Services + * @package Services_Twilio + * @author Justin Witz + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Policy +{ + private $url; + private $method; + private $queryFilter; + private $postFilter; + private $allow; + + public function __construct($url, $method, $queryFilter = array(), $postFilter = array(), $allow = true) + { + $this->url = $url; + $this->method = $method; + $this->queryFilter = $queryFilter; + $this->postFilter = $postFilter; + $this->allow = $allow; + } + + public function addQueryFilter($queryFilter) + { + array_push($this->queryFilter, $queryFilter); + } + + public function addPostFilter($postFilter) + { + array_push($this->postFilter, $postFilter); + } + + public function toArray() { + $policy_array = array('url' => $this->url, 'method' => $this->method, 'allow' => $this->allow); + if (!is_null($this->queryFilter)) { + if (count($this->queryFilter) > 0 ) { + $policy_array['query_filter'] = $this->queryFilter; + } else { + $policy_array['query_filter'] = new stdClass(); + } + } + + if (!is_null($this->postFilter)) { + if (count($this->postFilter) > 0 ) { + $policy_array['post_filter'] = $this->postFilter; + } else { + $policy_array['post_filter'] = new stdClass(); + } + } + + return $policy_array; + } +} diff --git a/Services/Twilio/TaskRouter/TaskQueue/Capability.php b/Services/Twilio/TaskRouter/TaskQueue/Capability.php new file mode 100644 index 0000000..3ad6fe8 --- /dev/null +++ b/Services/Twilio/TaskRouter/TaskQueue/Capability.php @@ -0,0 +1,21 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_TaskRouter_TaskQueue_Capability extends Services_Twilio_TaskRouter_Capability +{ + public function __construct($accountSid, $authToken, $workspaceSid, $taskQueueSid, $overrideBaseUrl = null, $overrideBaseWSUrl = null) + { + parent::__construct($accountSid, $authToken, $workspaceSid, $taskQueueSid, null, $overrideBaseUrl, $overrideBaseWSUrl); + } + + protected function setupResource() { + $this->resourceUrl = $this->baseUrl.'/TaskQueues/'.$this->channelId; + } +} \ No newline at end of file diff --git a/Services/Twilio/TaskRouter/Worker/Capability.php b/Services/Twilio/TaskRouter/Worker/Capability.php new file mode 100644 index 0000000..4ce6c10 --- /dev/null +++ b/Services/Twilio/TaskRouter/Worker/Capability.php @@ -0,0 +1,49 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_TaskRouter_Worker_Capability extends Services_Twilio_TaskRouter_Capability +{ + private $tasksUrl; + private $workerReservationsUrl; + private $activityUrl; + + public function __construct($accountSid, $authToken, $workspaceSid, $workerSid, $overrideBaseUrl = null, $overrideBaseWSUrl = null) + { + parent::__construct($accountSid, $authToken, $workspaceSid, $workerSid, null, $overrideBaseUrl, $overrideBaseWSUrl); + + $this->tasksUrl = $this->baseUrl.'/Tasks/**'; + $this->activityUrl = $this->baseUrl.'/Activities'; + $this->workerReservationsUrl = $this->resourceUrl.'/Reservations/**'; + + //add permissions to fetch the list of activities, tasks, and worker reservations + $this->allow($this->activityUrl, "GET", null, null); + $this->allow($this->tasksUrl, "GET", null, null); + $this->allow($this->workerReservationsUrl, "GET", null, null); + } + + protected function setupResource() { + $this->resourceUrl = $this->baseUrl.'/Workers/'.$this->channelId; + } + + public function allowActivityUpdates() { + $method = 'POST'; + $queryFilter = array(); + $postFilter = array("ActivitySid" => $this->required); + $this->allow($this->resourceUrl, $method, $queryFilter, $postFilter); + } + + public function allowReservationUpdates() { + $method = 'POST'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->tasksUrl, $method, $queryFilter, $postFilter); + $this->allow($this->workerReservationsUrl, $method, $queryFilter, $postFilter); + } +} \ No newline at end of file diff --git a/Services/Twilio/TaskRouter/Workspace/Capability.php b/Services/Twilio/TaskRouter/Workspace/Capability.php new file mode 100644 index 0000000..e0a014d --- /dev/null +++ b/Services/Twilio/TaskRouter/Workspace/Capability.php @@ -0,0 +1,21 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_TaskRouter_Workspace_Capability extends Services_Twilio_TaskRouter_Capability +{ + public function __construct($accountSid, $authToken, $workspaceSid, $overrideBaseUrl = null, $overrideBaseWSUrl = null) + { + parent::__construct($accountSid, $authToken, $workspaceSid, $workspaceSid, null, $overrideBaseUrl, $overrideBaseWSUrl); + } + + protected function setupResource() { + $this->resourceUrl = $this->baseUrl; + } +} \ No newline at end of file diff --git a/Services/Twilio/TaskRouterInstanceResource.php b/Services/Twilio/TaskRouterInstanceResource.php new file mode 100644 index 0000000..0c38c5b --- /dev/null +++ b/Services/Twilio/TaskRouterInstanceResource.php @@ -0,0 +1,22 @@ +subresources[$name] = new $type( + $this->client, $this->uri . "/$constantized" + ); + } + } + + protected function setupSubresource($name) { + $constantized = ucfirst(self::camelize($name)); + $type = get_class($this) . $constantized; + $this->subresources[$name] = new $type( + $this->client, $this->uri . "/". $constantized + ); + } +} diff --git a/Services/Twilio/TaskRouterListResource.php b/Services/Twilio/TaskRouterListResource.php new file mode 100644 index 0000000..156e190 --- /dev/null +++ b/Services/Twilio/TaskRouterListResource.php @@ -0,0 +1,26 @@ +getResourceName(true); + /* + * By default trim the 's' from the end of the list name to get the + * instance name (ex Accounts -> Account). This behavior can be + * overridden by child classes if the rule doesn't work. + */ + if (!isset($this->instance_name)) { + $this->instance_name = "Services_Twilio_Rest_TaskRouter_" . rtrim($name, 's'); + } + + parent::__construct($client, $uri); + } + + protected function setupSubresource($name) { + $constantized = ucfirst(self::camelize($name)); + $type = get_class($this) . $constantized; + $this->subresources[$name] = new $type( + $this->client, $this->uri . "/". $constantized + ); + } +} diff --git a/Services/Twilio/TimeRangeResource.php b/Services/Twilio/TimeRangeResource.php new file mode 100644 index 0000000..ebf1990 --- /dev/null +++ b/Services/Twilio/TimeRangeResource.php @@ -0,0 +1,31 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + * @link http://pear.php.net/package/Services_Twilio + */ +class Services_Twilio_TimeRangeResource extends Services_Twilio_UsageResource { + + /** + * Return a UsageRecord corresponding to the given category. + * + * @param string $category The category of usage to retrieve. For a full + * list of valid categories, please see the documentation at + * http://www.twilio.com/docs/api/rest/usage-records#usage-all-categories + * @return Services_Twilio_Rest_UsageRecord + * @throws Services_Twilio_RestException + */ + public function getCategory($category) { + $page = $this->getPage(0, 1, array( + 'Category' => $category, + )); + $items = $page->getItems(); + if (!is_array($items) || count($items) === 0) { + throw new Services_Twilio_RestException( + 400, "Usage record data is unformattable."); + } + return $items[0]; + } +} diff --git a/Services/Twilio/TinyHttp.php b/Services/Twilio/TinyHttp.php new file mode 100644 index 0000000..b6ccfe2 --- /dev/null +++ b/Services/Twilio/TinyHttp.php @@ -0,0 +1,134 @@ + array( + * CURLOPT_USERAGENT => self::USER_AGENT, + * CURLOPT_HTTPHEADER => array('Accept-Charset: utf-8'), + * CURLOPT_CAINFO => dirname(__FILE__) . '/cacert.pem', + * )) + * ); + */ +class Services_Twilio_TinyHttp { + var $user, $pass, $scheme, $host, $port, $debug, $curlopts; + + public function __construct($uri = '', $kwargs = array()) { + foreach (parse_url($uri) as $name => $value) $this->$name = $value; + $this->debug = isset($kwargs['debug']) ? !!$kwargs['debug'] : NULL; + $this->curlopts = isset($kwargs['curlopts']) ? $kwargs['curlopts'] : array(); + } + + public function __call($name, $args) { + list($res, $req_headers, $req_body) = $args + array(0, array(), ''); + + if (strpos($res, 'http') === 0) { + // We got handed a complete URL, just use it + $url = $res; + } else { + // Build from path and default scheme/host. + $url = "$this->scheme://$this->host$res"; + } + + $opts = $this->curlopts + array( + CURLOPT_URL => $url, + CURLOPT_HEADER => TRUE, + CURLOPT_RETURNTRANSFER => TRUE, + CURLOPT_INFILESIZE => -1, + CURLOPT_POSTFIELDS => NULL, + CURLOPT_TIMEOUT => 60, + ); + + foreach ($req_headers as $k => $v) $opts[CURLOPT_HTTPHEADER][] = "$k: $v"; + if ($this->port) $opts[CURLOPT_PORT] = $this->port; + if ($this->debug) $opts[CURLINFO_HEADER_OUT] = TRUE; + if ($this->user && $this->pass) $opts[CURLOPT_USERPWD] = "$this->user:$this->pass"; + switch ($name) { + case 'get': + $opts[CURLOPT_HTTPGET] = TRUE; + break; + case 'post': + $opts[CURLOPT_POST] = TRUE; + $opts[CURLOPT_POSTFIELDS] = $req_body; + break; + case 'put': + $opts[CURLOPT_PUT] = TRUE; + if (strlen($req_body)) { + if ($buf = fopen('php://memory', 'w+')) { + fwrite($buf, $req_body); + fseek($buf, 0); + $opts[CURLOPT_INFILE] = $buf; + $opts[CURLOPT_INFILESIZE] = strlen($req_body); + } else throw new Services_Twilio_TinyHttpException('unable to open temporary file'); + } + break; + case 'head': + $opts[CURLOPT_NOBODY] = TRUE; + break; + default: + $opts[CURLOPT_CUSTOMREQUEST] = strtoupper($name); + break; + } + try { + if ($curl = curl_init()) { + if (curl_setopt_array($curl, $opts)) { + if ($response = curl_exec($curl)) { + $parts = explode("\r\n\r\n", $response, 3); + list($head, $body) = ($parts[0] == 'HTTP/1.1 100 Continue') + ? array($parts[1], $parts[2]) + : array($parts[0], $parts[1]); + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + if ($this->debug) { + error_log( + curl_getinfo($curl, CURLINFO_HEADER_OUT) . + $req_body + ); + } + $header_lines = explode("\r\n", $head); + array_shift($header_lines); + foreach ($header_lines as $line) { + list($key, $value) = explode(":", $line, 2); + $headers[$key] = trim($value); + } + curl_close($curl); + if (isset($buf) && is_resource($buf)) { + fclose($buf); + } + return array($status, $headers, $body); + } else { + throw new Services_Twilio_TinyHttpException(curl_error($curl)); + } + } else throw new Services_Twilio_TinyHttpException(curl_error($curl)); + } else throw new Services_Twilio_TinyHttpException('unable to initialize cURL'); + } catch (ErrorException $e) { + if (is_resource($curl)) curl_close($curl); + if (isset($buf) && is_resource($buf)) fclose($buf); + throw $e; + } + } + + public function authenticate($user, $pass) { + $this->user = $user; + $this->pass = $pass; + } +} diff --git a/Services/Twilio/TrunkingInstanceResource.php b/Services/Twilio/TrunkingInstanceResource.php new file mode 100644 index 0000000..505fe94 --- /dev/null +++ b/Services/Twilio/TrunkingInstanceResource.php @@ -0,0 +1,15 @@ +subresources[$name] = new $type( + $this->client, $this->uri . "/$constantized" + ); + } + } + +} diff --git a/Services/Twilio/TrunkingListResource.php b/Services/Twilio/TrunkingListResource.php new file mode 100644 index 0000000..dc51ede --- /dev/null +++ b/Services/Twilio/TrunkingListResource.php @@ -0,0 +1,38 @@ +getResourceName(true); + /* + * By default trim the 's' from the end of the list name to get the + * instance name (ex Accounts -> Account). This behavior can be + * overridden by child classes if the rule doesn't work. + */ + if (!isset($this->instance_name)) { + $this->instance_name = "Services_Twilio_Rest_Trunking_" . rtrim($name, 's'); + } + + parent::__construct($client, $uri); + } + + /** + * Create a new Trunk instance + * + * Example usage: + * + * .. code-block:: php + * + * $trunkingClient->trunks->create(array( + * "FriendlyName" => "TestTrunk", + * "DomainName" => "test.pstn.twilio.com" + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/Services/Twilio/Twiml.php b/Services/Twilio/Twiml.php new file mode 100644 index 0000000..6a021ca --- /dev/null +++ b/Services/Twilio/Twiml.php @@ -0,0 +1,137 @@ + + * License: http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_Twiml { + + protected $element; + + /** + * Constructs a Twiml response. + * + * :param SimpleXmlElement|array $arg: Can be any of + * + * - the element to wrap + * - attributes to add to the element + * - if null, initialize an empty element named 'Response' + */ + public function __construct($arg = null) { + switch (true) { + case $arg instanceof SimpleXmlElement: + $this->element = $arg; + break; + case $arg === null: + $this->element = new SimpleXmlElement(''); + break; + case is_array($arg): + $this->element = new SimpleXmlElement(''); + foreach ($arg as $name => $value) { + $this->element->addAttribute($name, $value); + } + break; + default: + throw new Services_Twilio_TwimlException('Invalid argument'); + } + } + + /** + * Converts method calls into Twiml verbs. + * + * A basic example: + * + * .. code-block:: php + * + * php> print $this->say('hello'); + * hello + * + * An example with attributes: + * + * .. code-block:: php + * + * print $this->say('hello', array('voice' => 'woman')); + * hello + * + * You could even just pass in an attributes array, omitting the noun: + * + * .. code-block:: php + * + * print $this->gather(array('timeout' => '20')); + * + * + * :param string $verb: The Twiml verb. + * :param array $args: + * - (noun string) + * - (noun string, attributes array) + * - (attributes array) + * + * :return: A SimpleXmlElement + * :rtype: SimpleXmlElement + */ + public function __call($verb, array $args) + { + list($noun, $attrs) = $args + array('', array()); + if (is_array($noun)) { + list($attrs, $noun) = array($noun, ''); + } + /* addChild does not escape XML, while addAttribute does. This means if + * you pass unescaped ampersands ("&") to addChild, you will generate + * an error. + * + * Some inexperienced developers will pass in unescaped ampersands, and + * we want to make their code work, by escaping the ampersands for them + * before passing the string to addChild. (with htmlentities) + * + * However other people will know what to do, and their code + * already escapes ampersands before passing them to addChild. We don't + * want to break their existing code by turning their &'s into + * &amp; + * + * We also want to use numeric entities, not named entities so that we + * are fully compatible with XML + * + * The following lines accomplish the desired behavior. + */ + $decoded = html_entity_decode($noun, ENT_COMPAT, 'UTF-8'); + $normalized = htmlspecialchars($decoded, ENT_COMPAT, 'UTF-8', false); + $child = empty($noun) + ? $this->element->addChild(ucfirst($verb)) + : $this->element->addChild(ucfirst($verb), $normalized); + foreach ($attrs as $name => $value) { + /* Note that addAttribute escapes raw ampersands by default, so we + * haven't touched its implementation. So this is the matrix for + * addAttribute: + * + * & turns into & + * & turns into &amp; + */ + if (is_bool($value)) { + $value = ($value === true) ? 'true' : 'false'; + } + $child->addAttribute($name, $value); + } + return new static($child); + } + + /** + * Returns the object as XML. + * + * :return: The response as an XML string + * :rtype: string + */ + public function __toString() + { + $xml = $this->element->asXml(); + return str_replace( + '', + '', $xml); + } +} diff --git a/Services/Twilio/UsageResource.php b/Services/Twilio/UsageResource.php new file mode 100644 index 0000000..b9b929c --- /dev/null +++ b/Services/Twilio/UsageResource.php @@ -0,0 +1,20 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + * @link http://pear.php.net/package/Services_Twilio + */ +class Services_Twilio_UsageResource extends Services_Twilio_ListResource { + public function getResourceName($camelized = false) { + $this->instance_name = 'Services_Twilio_Rest_UsageRecord'; + return $camelized ? 'UsageRecords' : 'usage_records'; + } + + public function __construct($client, $uri) { + $uri = preg_replace("#UsageRecords#", "Usage/Records", $uri); + parent::__construct($client, $uri); + } +} + diff --git a/Services/Twilio/WorkflowConfiguration.php b/Services/Twilio/WorkflowConfiguration.php new file mode 100644 index 0000000..ba4da0a --- /dev/null +++ b/Services/Twilio/WorkflowConfiguration.php @@ -0,0 +1,101 @@ +filters = $filters; + $this->default_filter = $default_filter; + } + + public function toJSON() { + return json_encode($this); + } + + public static function parse($json) { + return json_decode($json); + } + + public static function fromJson($json) { + $configJSON = self::parse($json); + $default_filter = $configJSON->task_routing->default_filter; + $filters = array(); + foreach($configJSON->task_routing->filters as $filter) { + // friendly_name and filter_friendly_name should map to same variable + $friendly_name = isset($filter->filter_friendly_name) ? $filter->filter_friendly_name : $filter->friendly_name; + $filter = new WorkflowRule($filter->expression, $filter->targets, $friendly_name); + $filters[] = $filter; + } + return new WorkflowConfiguration($filters, $default_filter); + } + + public function jsonSerialize() { + $json = array(); + $task_routing = array(); + $task_routing["filters"] = $this->filters; + $task_routing["default_filter"] = $this->default_filter; + $json["task_routing"] = $task_routing; + return $json; + } +} + +class WorkflowRule implements JsonSerializable { + public $expression; + public $friendly_name; + public $targets; + + public function __construct($expression, $targets, $friendly_name = null) + { + $this->expression = $expression; + $this->targets = $targets; + $this->friendly_name = $friendly_name; + } + + public function jsonSerialize() { + $json = array(); + $json["expression"] = $this->expression; + $json["targets"] = $this->targets; + if($this->friendly_name != null) { + $json["friendly_name"] = $this->friendly_name; + } + return $json; + } +} + +class WorkflowRuleTarget implements JsonSerializable { + public $queue; + public $expression; + public $priority; + public $timeout; + + public function __construct($queue, $priority = null, $timeout = null, $expression = null) + { + $this->queue = $queue; + $this->priority = $priority; + $this->timeout = $timeout; + $this->expression = $expression; + } + + public function jsonSerialize() { + $json = array(); + $json["queue"] = $this->queue; + if($this->priority != null) { + $json["priority"] = $this->priority; + } + if($this->timeout != null) { + $json["timeout"] = $this->timeout; + } + if($this->expression != null) { + $json["expression"] = $this->expression; + } + return $json; + } +} \ No newline at end of file diff --git a/bystanderIntervention.php b/bystanderIntervention.php new file mode 100644 index 0000000..c17fc24 --- /dev/null +++ b/bystanderIntervention.php @@ -0,0 +1,87 @@ + + + + + FirstAide + + + + +
+
+
+

Bystander Intervention

+
+
+ +
+ + + + + + + +
+ Bystander Intervention is a process of safely interrupting a situation in which others may be at risk for becoming the victim of harassment, or sexual or physical violence. +

+ In Peace Corps history, other Volunteers often witnessed the events leading up to Volunteer sexual and physical assaults. There are ways to safely intervene when you see your fellow Trainee or Volunteer in a potentially dangerous situation. +

+ #1 Rule: Your safety is your FIRST priority. Bystander intervention is a tool to be used with Volunteers. If you see a situation between locals that needs intervention, contact your SSM for guidance on how to proceed. +
+

Verbal with Potential Victim:

+
    +
  • Diffuse the situation by starting a new conversation
  • +
  • Say a friend is looking for the individual and leave together to find them
  • +
  • Tell the individual there is a previous engagement with others and they need to leave with you
  • +
  • “I need your advice…” and pull them away from the immediate space
  • +
  • “Do you need help?”
  • +
  • “Let’s walk home together”
  • +
  • “Do you want me to call someone for you?”
  • +
  • “What can I do to help you?”
  • +
  • “Do you want me to talk to so-and-so for you?”
  • +
+
+

Verbal with Potential Offender

+
    +
  • Introduce yourself- let the predator know the individual isn’t alone
  • +
  • Engage with the individual directly by starting a completely different conversation; example- sports, directions
  • +
  • Use humor to diffuse the situation
  • +
  • “How would you feel if someone did that/said that to your sister/mother?”
  • +
  • “I don’t like what you just said.”
  • +
+
+

Non-Verbal Tactics for both

+
    +
  • Get in line of vision and catch their eye
  • +
  • Take a group photo to document what the potential offender looks like
  • +
  • Ask/Assess situation with a thumbs up/down
  • +
  • Wave to your friend to indicate you are leaving to get them to come with you
  • +
  • Text or call the Volunteer
  • +
  • Use a distraction to get the predator’s attention
  • +
  • Strike up a conversation with someone nearby to physically get closer
  • +
  • Walk towards the two, alone or with others, and engage in conversation
  • +
  • Make a show of picking up the phone to indicate you are alerting others
  • +
  • Physically pull the individual away
  • +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/circleOfTrust.php b/circleOfTrust.php new file mode 100644 index 0000000..ea685e0 --- /dev/null +++ b/circleOfTrust.php @@ -0,0 +1,75 @@ + + + + + FirstAide + + + + + +
+
+
+

Circle of Trust

+
+

My Trustees

+
+ +
+ + + +
+ + +
+
+ + +
+
+ + + +
+
+ + +
+
+ + + + +
+
+ + + + + + + + \ No newline at end of file diff --git a/commonalitiesOfSexualPredators.php b/commonalitiesOfSexualPredators.php new file mode 100644 index 0000000..286332c --- /dev/null +++ b/commonalitiesOfSexualPredators.php @@ -0,0 +1,108 @@ + + + + + FirstAide + + + + + +
+
+
+

Commonalities Of Sexual Predators

+
+
+ +
+ + + + + + + +
+

+ While cultural misunderstandings can contribute to increased risk, most sexual assaults are not the result of cross-cultural misinterpretations. They are the result of deliberate planning by the sexual predator. Ultimately, sexual assault is a crime of motive and opportunity. While you can never completely protect yourself from sexual assault, there are some things you can do to help reduce your risk of being assaulted. +

+
+
    +

    Characteristics of assaults:

    +
  • + Sexual predators often plan sexual assaults. +
      +
    • + Sexual assault is not an accident. Sexual predators know what they want to do, even if they have not already identified a specific target. Most of them have a plan in mind for how they will select and control someone, or they will seek out an area where a potential victim might be isolated and unable to get help. When we say planned to some extent it may not mean days or weeks in advance but also planned in the particular + moment. +
    • +
    +
  • +
  • + Sexual predators often watch for vulnerabilities and opportunities. +
      +
    • + Sexual predators look for cues to indicate they can dominate and control a potential victim. They look for signs indicating that someone would be unlikely or unable to resist. For instance, people who are unaware of their surroundings, alone or lost; someone who is intoxicated or in some way incapacitated. +
    • +
    +
  • +
  • + Sexual predators often test the boundaries of potential victims. +
      +
    • + Testing boundaries may involve inappropriate comments, unwanted touching or invading personal space. It is a way of measuring the amount of resistance a potential victim might offer. A person who offers little or no resistance to these advances might be seen as a suitable target. +
    • +
    +
  • +
+
+

Both in Peace Corps and worldwide, the majority of sexual assault have these similarities:

+
    +
  • Predators know the victim
  • +
  • Occur when the victim is isolated.
  • +
  • Occur at night.
  • +
+
+

Tactics used by sexual predators

+
    +
  • + Attempt to isolate their potential victim. They may target someone who is already alone. For example, walking alone, or they may try to get their target alone by offering a ride in their car. +
  • +
  • + Persuasion and confidence.This is the “Smooth Talker” who puts you at ease. They make you feel comfortable and relaxed so you are not aware of their true intent. They may try to persuade you to do something you feel uncomfortable about. They might promise that they won’t try anything with you or reassure you by saying “You can trust me.” +
  • + Pressure and guilt.Sexual predators may try to coerce you by pressuring you to go farther in a relationship than you are ready or willing to go. They may try to make you feel guilty if you do not give in to their advances. They might say “You are offending me culturally” or something similar to make Volunteers feel guilty. +
  • + Threats and intimidation. Sometimes the sexual predator threatens to physically harm the Volunteer or someone they care about. They might also threaten to blackmail the Volunteer unless they comply. +
  • +
  • + Force and violence.Force and Violence involves a direct physical attack to overpower a Volunteer. It is what we frequently see on TV and in movies…like when the assailant jumps out of the bushes with a knife and attacks an unsuspecting jogger. +
  • +
  • + Drugs, including alcohol + Description to be provided.... +
  • +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/copingWithUnwantedAttentionStrategies.php b/copingWithUnwantedAttentionStrategies.php new file mode 100644 index 0000000..1a84163 --- /dev/null +++ b/copingWithUnwantedAttentionStrategies.php @@ -0,0 +1,77 @@ + + + + + FirstAide + + + + +
+
+
+

Coping With Unwanted Attention Strategies

+
+
+ + + + + + +
+ All PCVs will deal with some type of unwanted attention at some point in their service. This occurs across all cultures. The reaction someone has in response is highly personal and depends on the type of unwanted attention. Reactions may range from a slight feeling of discomfort to anger to fearing for one’s safety. You do not have to “be nice” if you feel unsafe or even uncomfortable. Peace Corps staff are here to help and have been trained on how to help PCVs cope. It’s important to report unwanted attention that is severe in nature so you can get the help and support you deserve. +

+ There’s a difference between unwanted attention and stalking. Stalking and cyber-stalking are defined as repeated threatening behavior from a single person that causes a Volunteer to fear for his or her safety or suffer substantial emotional distress. Unwanted physical contact, such as grabbing or touching, is considered assault, not unwanted attention. +
+
    +
  • + Walk purposefully.Always walk with confidence and purpose. +
  • +
  • + Look assertive. Hold your head high, shoulders back and present yourself as a professional demanding respect. +
  • +
  • + Nod (to acknowledge) and keep on walking. Simply recognizing the person can help ward off unwanted attention. Many times an inappropriate comment is an effort to get attention.
  • +
  • + Dress appropriately. Keep in mind what is culturally appropriate. +
  • +
  • + Greetings.Sometimes a polite “Good Morning” can thwart a potential unwanted comment, but at other times it can escalate the situation. If this strategy does not work, try a different one. +
  • +
  • + Pretend that you heard something else. “I agree, it HAS been really great weather recently. Have a nice day, bye!” +
  • +
  • + Humor. Use humor to lighten the moment and solicit another response. For example, if you are told that you would make a good lover, reply that your spouse is sure to agree! Keep walking. This may not work with a persistent individual, so please keep trying different strategies when needed. +
  • +
  • + Be polite but firm. It is quite normal to stand your ground. “I am offended by your comment; please do not address me in that manner.” +
  • +
  • + Maintain your composure. Try to remain calm even if you feel upset. The converse is also true; try not to show hostility as this may provoke a confrontation. It is best to remove yourself from a situation if you feel that you are losing control. +
  • +
  • + Never say “next time.” Make no promises for another time, because you can be sure that the next time they see you, they will remind you of that promise. +
  • +
+
+
+
+ + + + \ No newline at end of file diff --git a/css files/circle-of-trust.css b/css files/circle-of-trust.css new file mode 100644 index 0000000..2b7a466 --- /dev/null +++ b/css files/circle-of-trust.css @@ -0,0 +1,173 @@ +/* Created by Akanksha + Desc: Style for Circle of Trust + Used in following php files + editComrades + circleOfTrust +*/ +body { + background-color: #05d197; + margin: 0; +} +#bw-arrow { + margin-left: 0px; + margin-top: 200px; + position: absolute; +} +/* The Close Button in popup*/ +.close { + color: #ffffff; + float: right; + font-size: 28px; + font-weight: bold; +} + +.close:hover,.close:focus { + color: #000; + text-decoration: none; + cursor: pointer; +} +/*Icons style present in circleOfTrust.php*/ +.icons-container .icons-row { + margin: 50px; +} + +.icons-container .icons-row img { + cursor: pointer; + margin:0 50px; +} + +#ic-edit{ + margin: 0 700px 0 0px; +} + +.inputs input { + background-color: #ffffff; + border: 3px solid #2db58f; + color: #2db58f; + font-size: 15px; + height: 100%; + margin: 10px; + padding: 10px; + width: 500px; +} + +.line { + color: white; + width: 80%; +} + +/*popup css*/ +.popup { + background-color: #2db58f; + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ + display: none; /* Hidden by default */ + left: 0; + height: 100%; + overflow: auto; + padding-top: 100px; /* Location of the box */ + position: fixed; + top: 0; + width: 100%; + z-index: 1; /*On top of screen*/ +} +/*Style for popup when Help me clicked*/ +.popup-button { /*buttons in contact popup*/ + background-color: #2db58f; + border-width: 3px; + color: #ffffff; + cursor: pointer; + font-size: 20px; + height: 70px; + margin-top: 20px; + padding: 20px; + text-align:center; + width: 100%; +} + +.popup-button:hover { + background-color: #02845f; +} + +.popup-content { + background-color: #2db58f; + border: 3px solid #ffffff; + margin: auto; + padding: 20px; + width: 30%; +} + +.small-button {/*submit button in editComrades.php*/ + background-color: #2db58f; + border-width: 3px; + border-color: #ffffff; + color: #ffffff; + cursor: pointer; + font-size: 20px; + height: 50px; + margin-top: 20px; + text-align: center; + width: 30%; +} + +.small-button:hover { + background-color: #02845f; +} + +#table { + border-collapse:separate; + border-spacing:50px 50px; + height: 200px; + width: 100%; +} + +.text { + color: #ffffff; + font-style: bold; +} + +.window { + height: 100%; + margin-left: 25%; + padding: 1px 16px; +} + +::-webkit-input-placeholder { /* WebKit, Blink, Edge */ + color: #2db58f; + font-size: 15px; +} + +:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ + color: #2db58f; + font-size: 15px; + opacity: 1; +} + +::-moz-placeholder { /* Mozilla Firefox 19+ */ + color: #2db58f; + font-size: 15px; + opacity: 1; +} + +:-ms-input-placeholder { /* Internet Explorer 10-11 */ + color: #2db58f; + font-size: 15px; +} + +/*custom scrollbar for the app*/ +::-webkit-scrollbar { + background-color: #f5f5f5; + width: 12px; +} + +::-webkit-scrollbar-track { + background-color: #f5f5f5; + border-radius: 10px; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); +} + +::-webkit-scrollbar-thumb { + background-color: #bdbdbd; + border-radius: 10px; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); +} + diff --git a/css files/gethelpnow-style.css b/css files/gethelpnow-style.css new file mode 100644 index 0000000..448ef97 --- /dev/null +++ b/css files/gethelpnow-style.css @@ -0,0 +1,219 @@ +/* Created by Akanksha + Desc: Style for Get Help Now module and it's submodules + Use in the following php files + getHelpNow + getHelpNow2 + PCSaves + OfficeOfVictimAdvocacy + OfficeOfCivilRightsAndDiversity + OfficeOfInspectorGeneral + twilioSMS + twilioCall + */ +body { + background-color: #05d197; + margin: 0; +} + +.block { + background-color: #2db58f; + border: 3px solid #ffffff; + color: #ffffff; + cursor: pointer; + font-size: 20px; + height: 100%; + margin-top: 30px; + padding: 20px; + width: 400px; +} + +#btn-table { + border-collapse: separate; + border-spacing: 50px 50px; + width: 100%; + height: 200px; +} + +.button { /*The big green buttons*/ + background-color: #2db58f; + border-width: 3px; + border-color: #ffffff; + color: #ffffff; + cursor: pointer; + font-size: 20px; + height: 150px; + margin-top: 30px; + text-align: center; + width: 100%; +} + +.button:hover { + background-color: #02845f; +} + +#bw-arrow { + margin-top: 250px; + position: absolute; +} + +/* The Close Button in popup */ +.close { + color: #ffffff; + float: right; + font-size: 28px; + font-weight: bold; +} + +.close:hover,.close:focus { + color: #000; + cursor: pointer; + text-decoration: none; +} + +#fw-arrow { + float: right; + display: inline-block; + margin-top: 0px; +} + +#input { + background-color: #2db58f; + border: 3px solid #ffffff; + color: #ffffff; + font-size: 20px; + height: 100%; + margin-top: 30px; + padding: 20px; + width: 400px; +} + +.line { + color: white; + width: 50%; +} + +#location{ + background-color: #2db58f; + border: 1px solid #ffffff; + color: #ffffff; +} + +/*popup css*/ +.popup { + background-color: #2db58f; + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ + display: none; /* Hidden by default */ + left: 0; + height: 100%; + overflow: auto; + padding-top: 100px; /* Location of the box */ + position: fixed; + top: 0; + width: 100%; + z-index: 1; /*On top of screen*/ +} + +.popup-button { /*buttons in contact popup*/ + background-color: #2db58f; + border-width: 3px; + color: #ffffff; + cursor: pointer; + font-size: 20px; + height: 70px; + margin-top: 20px; + padding: 20px; + text-align:center; + width: 100%; +} + +.popup-button:hover { + background-color: #02845f; +} + +.popup-content { + background-color: #2db58f; + border: 3px solid #ffffff; + margin: auto; + padding: 20px; + width: 30%; +} + +.small-button {/*used in sub-modules present at getHelpNow2.php*/ + background-color: #2db58f; + border-width: 3px; + border-color: #ffffff; + color: #ffffff; + cursor: pointer; + font-size: 20px; + height: 50px; + margin-top: 20px; + text-align: center; + width: 30%; +} + +.small-button:hover { + background-color: #02845f; +} + +#SMS-body { + background-color: #2db58f; + border: 3px solid #ffffff; + color: #ffffff; + cursor: pointer; + font-size: 20px; + height: 200px; + margin-top: 30px; + padding: 20px; + width: 400px; +} + +.text { + color: #ffffff; + font-style: bold; +} + +.window { + height: 100%; + margin-left: 25%; + padding: 1px 16px; +} + +::-webkit-input-placeholder { /* WebKit, Blink, Edge */ + color: #d3d3d3; + font-size: 15px; +} + +:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ + color: #d3d3d3; + font-size: 15px; + opacity: 1; +} + +::-moz-placeholder { /* Mozilla Firefox 19+ */ + color: #d3d3d3; + font-size: 15px; + opacity: 1; +} + +:-ms-input-placeholder { /* Internet Explorer 10-11 */ + color: #d3d3d3; + font-size: 15px; +} + +/*custom scrollbar for the app*/ +::-webkit-scrollbar { + background-color: #f5f5f5; + width: 12px; +} + +::-webkit-scrollbar-track { + background-color: #f5f5f5; + border-radius: 10px; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); +} + +::-webkit-scrollbar-thumb { + background-color: #bdbdbd; + border-radius: 10px; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); +} diff --git a/css files/index-style.css b/css files/index-style.css new file mode 100644 index 0000000..2bed08e --- /dev/null +++ b/css files/index-style.css @@ -0,0 +1,37 @@ +/* Created by Akanksha + Desc: CSS for index page +*/ +body { + background-color: #05d197; + height: 240px; + left: 50%; + margin-left: -400px; + margin-top: -120px; + position: absolute; + top: 50%; + width: 800px; +} + +.title { + color: #ffffff; + font-size: 100px; + font-style: bold; +} + +/*custom scrollbar for the app*/ +::-webkit-scrollbar { + background-color: #f5f5f5; + width: 12px; +} + +::-webkit-scrollbar-track { + border-radius: 10px; + background-color: #f5f5f5; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); +} + +::-webkit-scrollbar-thumb { + background-color: #bdbdbd; + border-radius: 10px; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); +} \ No newline at end of file diff --git a/css files/loginAndRegistration.css b/css files/loginAndRegistration.css new file mode 100644 index 0000000..9da232f --- /dev/null +++ b/css files/loginAndRegistration.css @@ -0,0 +1,117 @@ +/* Created by Akanksha + CSS for login and registration pages +*/ +/*Hyperlink CSS*/ +a:link { + color: #ffffff; +} + +a:visited { + color: #ffffff; +} + +a:hover { + color: blue; +} + +body { + background-color: #05d197; +} + +.button {/*Green buttons*/ + background-color: #2db58f; + border-width: 3px; + border-color: #ffffff; + color: #ffffff; + font-size: 20px; + height: 60px; + margin-top: 30px; + text-align: center; + width: 25%; +} + +.button:hover { + background-color: #02845f !important; +} + +.div { + margin-top: 100px; +} + +.div-reg { + margin-top: 30px; +} + +.input-box {/*css for inputs*/ + background-color: transparent; + border-bottom: solid #eeeeee 1px; + border-left: none; + border-right: none; + border-top: none; + color: #eeeeee; + outline: none; + outline-style: none; + padding: 3px 10px; +} + +.input-box:focus { + box-shadow: 0px 2px; +} + +#line { + border-width: 2px; + color: #ffffff; + width: 50%; +} + +.tables { + border-collapse:separate; + border-spacing:0 45px; +} + +.text { + color: #ffffff; + font-style: bold; +} + +/*placeholder css*/ + +::-webkit-input-placeholder { /* WebKit, Blink, Edge */ + color: #d3d3d3; + font-size: 15px; +} + +:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ + color: #d3d3d3; + font-size: 15px; + opacity: 1; +} + +::-moz-placeholder { /* Mozilla Firefox 19+ */ + color: #d3d3d3; + font-size: 15px; + opacity: 1; +} + +:-ms-input-placeholder { /* Internet Explorer 10-11 */ + color: #d3d3d3; + font-size: 15px; +} + +/*custom scrollbar for the app*/ +::-webkit-scrollbar { + background-color: #f5f5f5; + width: 12px; +} + +::-webkit-scrollbar-track { + border-radius: 10px; + background-color: #f5f5f5; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); +} + +::-webkit-scrollbar-thumb { + background-color: #bdbdbd; + border-radius: 10px; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); +} diff --git a/css files/menu-css.css b/css files/menu-css.css new file mode 100644 index 0000000..698f589 --- /dev/null +++ b/css files/menu-css.css @@ -0,0 +1,138 @@ +/* Created by Akanksha + Desc: CSS for the vertical accordian menu +*/ +#accordian { + background: #ffd590; + color: white; + /*Some cool shadow and glow effect*/ + box-shadow: + 0 5px 15px 1px rgba(0, 0, 0, 0.6), + 0 0 200px 1px rgba(255, 255, 255, 0.5); + position: fixed; + height: 100% +} + +#accordian h2 a { + background: #ffd590; + background: linear-gradient(#ffd590, #ffd590); + color: #ffffff; + cursor: pointer; + font-size: 25px; + font-style: bold; + line-height: 34px; +} + +#accordian h2 img { + float:left; + height: 30px; + margin-bottom:10px; + margin-left:45px; + margin-top:5px; + padding: 9px; + width: 30px; +} + +#accordian h3 { + background: #ffd590; + background: linear-gradient(#ffd590, #ffd590); + color: #ffffff; + cursor: pointer; + font-size: 15px; + font-style: bold; + line-height: 34px; + padding: 0 10px; +} + +#accordian h3 a { + color: #ffffff; +} + +#accordian h3 a:hover { + background: #ffd590; + border-left: 5px solid orange; +} + +#accordian h3:hover { + text-shadow: 0 0 1px rgba(255, 255, 255, 0.7); +} + +#accordian li { + list-style-type: none; +} + +#accordian li.active .ul-menu { + display: block; +} + +#accordian .ul-menu .ul-menu li a { + color: white; + display: block; + font-size: 15px; + line-height: 27px; + padding: 0 15px; + text-decoration: none; + /*transition for smooth hover animation*/ + transition: all 0.15s; +} + +#accordian .ul-menu .ul-menu li a:hover { + background: #ffd590; + border-left: 5px solid orange; +} + +/*hide the non active LIs by default*/ +#accordian .ul-menu .ul-menu { + display: none; +} +/*CSS for list*/ +li a { + display: block; + color: #000; + padding: 8px 0 8px 16px; + text-decoration: none; +} + +li a.active { + background-color: #4caf50; + color: white; +} + +li a:hover:not(.active) { + background-color: #555; + color: white; +} + +li.last { + background-color: red; + float: none; + overflow: hidden; +} + +#line { + color: white; +} +/*CSS for ul of menu*/ +.ul-menu { + background-color: #fbc469; + height: 100%; + list-style-type: none; + margin: 0; + overflow: auto;/*enables scrolling if menu too long*/ + padding: 0; + width: 250px; +} + +.ul-menu .ul-menu li a { + color: white; + display: block; + font-size: 11px; + line-height: 27px; + padding: 0 15px; + text-decoration: none; + /*transition for smooth hover animation*/ + transition: all 0.15s; +} + +.ul-menu .ul-menu { + display: none; +} diff --git a/css files/progress-bar.css b/css files/progress-bar.css new file mode 100644 index 0000000..16923fa --- /dev/null +++ b/css files/progress-bar.css @@ -0,0 +1,50 @@ +/* Created by Akanksha + CSS for progress bar +*/ +#bar { + background-color: #fbc469; + height: 100%; + position: absolute; + width: 1%; +} + +body { + background-color: #05d197; + margin: 0; +} + +#line { + color: white; + width: 50%; +} + +#progress { + background-color: #ddd; + height: 30px; + margin-top: 200px; + position: relative; + width: 80%; +} + +.text { + color: #ffffff; + font-style: bold; +} + +/*custom scrollbar for the app*/ +::-webkit-scrollbar { + background-color: #f5f5f5; + width: 12px; +} + +::-webkit-scrollbar-track { + background-color: #f5f5f5; + border-radius: 10px; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); +} + +::-webkit-scrollbar-thumb { + background-color: #bdbdbd; + border-radius: 10px; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); +} diff --git a/css files/safety-tools.css b/css files/safety-tools.css new file mode 100644 index 0000000..bcf4b5f --- /dev/null +++ b/css files/safety-tools.css @@ -0,0 +1,183 @@ +/* Created by Akanksha + Desc: CSS for all pages of safety tools + RADAR + Personal security startegies + Bystander Intervention + Coping with unwanted attention strategies + Commonalities of sexual predators + Safety tools basics + Safety plan worksheet +*/ +body { + background-color: #05d197; + margin: 0; +} + +.block { + background-color: #2db58f; + border: 3px solid #ffffff; + color: #ffffff; + cursor: grab; + font-size: 20px; + height: 300px; + padding: 20px; + width: 500px; +} + +#btn-table { + border-collapse:separate; + border-spacing:50px 50px; + height: 200px; + width: 100%; +} + +.button { /*The big green buttons*/ + background-color: #2db58f; + border-color: #ffffff; + border-width: 3px; + color: #ffffff; + cursor: pointer; + font-size: 20px; + height: 150px; + margin-top: 30px; + text-align: center; + width: 100%; +} + +.button:hover { + background-color: #02845f; +} + +#bw-arrow {/*css for backward arrow*/ + margin-left: 0px; + margin-top: 250px; + position: absolute; +} + +.content { + background-color:#2db58f; + padding: 5px 10px; +} + +.dragscroll {/*for horizontally scrolled content*/ + cursor: grab; + cursor : -o-grab; + cursor : -moz-grab; + cursor : -webkit-grab; + margin-top: 5%; + overflow: auto; + overflow-x:hidden; +} + +#fw-arrow {/*the forward arrow*/ + margin-left: 1020px; + margin-top: 250px; + position: absolute; +} + +.greaterthan5-blocks-content {/*used for pages which have multiple blocks (>5)*/ + border-collapse:separate; + border-spacing:50px 50px; + width: 270%; +} + +.heading {/*used only in safety plan worksheet*/ + background-color: #05d197 ; + color: #ffffff; + cursor: pointer; + margin: 10px; + padding: 30px 20px; + position: relative; +} + +.line { + color: white; + width: 50%; +} + +p { + padding: 5px 0; +} + +.text { + color: #ffffff; +} + +.threeorfour-blocks-content {/*used for pages which have 3 or 4 blocks only*/ + border-collapse:separate; + border-spacing:50px 50px; + width: 150%; +} + +.two-blocks-content {/*used for pages which have 2 blocks only*/ + border-collapse:separate; + border-spacing:50px 50px; + height: 500px; + overflow:scroll; + table-layout:fixed; +} +/*ul CSS*/ +.ul-safetytools { + background-color: #2db58f; + color: #ffffff; + font-size: 20px; + width: 90%; + height: 80%; + overflow:scroll; + overflow-x: hidden; +} + +.ul-safetytools li{ + margin-top: 10px; +} + +.window { + height: 100%; + margin-left: 20%; + padding: 1px 16px; +} +.wrap { + margin: 0; + padding: 0; +} + +::-webkit-input-placeholder { /* WebKit, Blink, Edge */ + color: #d3d3d3; + font-size: 15px; +} + +:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ + color: #d3d3d3; + font-size: 15px; + opacity: 1; +} + +::-moz-placeholder { /* Mozilla Firefox 19+ */ + color: #d3d3d3; + font-size: 15px; + opacity: 1; +} + +:-ms-input-placeholder { /* Internet Explorer 10-11 */ + color: #d3d3d3; + font-size: 15px; +} + +/*custom scrollbar for the app*/ +::-webkit-scrollbar { + background-color: #f5f5f5; + width: 12px; +} + +::-webkit-scrollbar-track { + background-color: #f5f5f5; + border-radius: 10px; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); +} + +::-webkit-scrollbar-thumb { + background-color: #bdbdbd; + border-radius: 10px; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); +} + diff --git a/css files/sweetalert.css b/css files/sweetalert.css new file mode 100644 index 0000000..083d504 --- /dev/null +++ b/css files/sweetalert.css @@ -0,0 +1,932 @@ +body.stop-scrolling { + height: 100%; + overflow: hidden; } + +.sweet-overlay { + background-color: black; + /* IE8 */ + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + /* IE8 */ + background-color: rgba(0, 0, 0, 0.4); + position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; + display: none; + z-index: 10000; } + +.sweet-alert { + background-color: white; + font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; + width: 478px; + padding: 17px; + border-radius: 5px; + text-align: center; + position: fixed; + left: 50%; + top: 50%; + margin-left: -256px; + margin-top: -200px; + overflow: hidden; + display: none; + z-index: 99999; } + @media all and (max-width: 540px) { + .sweet-alert { + width: auto; + margin-left: 0; + margin-right: 0; + left: 15px; + right: 15px; } } + .sweet-alert h2 { + color: #575757; + font-size: 30px; + text-align: center; + font-weight: 600; + text-transform: none; + position: relative; + margin: 25px 0; + padding: 0; + line-height: 40px; + display: block; } + .sweet-alert p { + color: #797979; + font-size: 16px; + text-align: center; + font-weight: 300; + position: relative; + text-align: inherit; + float: none; + margin: 0; + padding: 0; + line-height: normal; } + .sweet-alert fieldset { + border: none; + position: relative; } + .sweet-alert .sa-error-container { + background-color: #f1f1f1; + margin-left: -17px; + margin-right: -17px; + overflow: hidden; + padding: 0 10px; + max-height: 0; + webkit-transition: padding 0.15s, max-height 0.15s; + transition: padding 0.15s, max-height 0.15s; } + .sweet-alert .sa-error-container.show { + padding: 10px 0; + max-height: 100px; + webkit-transition: padding 0.2s, max-height 0.2s; + transition: padding 0.25s, max-height 0.25s; } + .sweet-alert .sa-error-container .icon { + display: inline-block; + width: 24px; + height: 24px; + border-radius: 50%; + background-color: #ea7d7d; + color: white; + line-height: 24px; + text-align: center; + margin-right: 3px; } + .sweet-alert .sa-error-container p { + display: inline-block; } + .sweet-alert .sa-input-error { + position: absolute; + top: 29px; + right: 26px; + width: 20px; + height: 20px; + opacity: 0; + -webkit-transform: scale(0.5); + transform: scale(0.5); + -webkit-transform-origin: 50% 50%; + transform-origin: 50% 50%; + -webkit-transition: all 0.1s; + transition: all 0.1s; } + .sweet-alert .sa-input-error::before, .sweet-alert .sa-input-error::after { + content: ""; + width: 20px; + height: 6px; + background-color: #f06e57; + border-radius: 3px; + position: absolute; + top: 50%; + margin-top: -4px; + left: 50%; + margin-left: -9px; } + .sweet-alert .sa-input-error::before { + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); } + .sweet-alert .sa-input-error::after { + -webkit-transform: rotate(45deg); + transform: rotate(45deg); } + .sweet-alert .sa-input-error.show { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); } + .sweet-alert input { + width: 100%; + box-sizing: border-box; + border-radius: 3px; + border: 1px solid #d7d7d7; + height: 43px; + margin-top: 10px; + margin-bottom: 17px; + font-size: 18px; + box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.06); + padding: 0 12px; + display: none; + -webkit-transition: all 0.3s; + transition: all 0.3s; } + .sweet-alert input:focus { + outline: none; + box-shadow: 0px 0px 3px #c4e6f5; + border: 1px solid #b4dbed; } + .sweet-alert input:focus::-moz-placeholder { + transition: opacity 0.3s 0.03s ease; + opacity: 0.5; } + .sweet-alert input:focus:-ms-input-placeholder { + transition: opacity 0.3s 0.03s ease; + opacity: 0.5; } + .sweet-alert input:focus::-webkit-input-placeholder { + transition: opacity 0.3s 0.03s ease; + opacity: 0.5; } + .sweet-alert input::-moz-placeholder { + color: #bdbdbd; } + .sweet-alert input:-ms-input-placeholder { + color: #bdbdbd; } + .sweet-alert input::-webkit-input-placeholder { + color: #bdbdbd; } + .sweet-alert.show-input input { + display: block; } + .sweet-alert .sa-confirm-button-container { + display: inline-block; + position: relative; } + .sweet-alert .la-ball-fall { + position: absolute; + left: 50%; + top: 50%; + margin-left: -27px; + margin-top: 4px; + opacity: 0; + visibility: hidden; } + .sweet-alert button { + background-color: #05d197; + color: white; + border: none; + box-shadow: none; + font-size: 17px; + font-weight: 500; + -webkit-border-radius: 4px; + border-radius: 5px; + padding: 10px 32px; + margin: 26px 5px 0 5px; + cursor: pointer; } + .sweet-alert button:focus { + outline: none; + box-shadow: 0 0 2px rgba(128, 179, 235, 0.5), inset 0 0 0 1px rgba(0, 0, 0, 0.05); } + .sweet-alert button:hover { + background-color: #7ecff4; } + .sweet-alert button:active { + background-color: #5dc2f1; } + .sweet-alert button.cancel { + background-color: #C1C1C1; } + .sweet-alert button.cancel:hover { + background-color: #b9b9b9; } + .sweet-alert button.cancel:active { + background-color: #a8a8a8; } + .sweet-alert button.cancel:focus { + box-shadow: rgba(197, 205, 211, 0.8) 0px 0px 2px, rgba(0, 0, 0, 0.0470588) 0px 0px 0px 1px inset !important; } + .sweet-alert button[disabled] { + opacity: .6; + cursor: default; } + .sweet-alert button.confirm[disabled] { + color: transparent; } + .sweet-alert button.confirm[disabled] ~ .la-ball-fall { + opacity: 1; + visibility: visible; + transition-delay: 0s; } + .sweet-alert button::-moz-focus-inner { + border: 0; } + .sweet-alert[data-has-cancel-button=false] button { + box-shadow: none !important; } + .sweet-alert[data-has-confirm-button=false][data-has-cancel-button=false] { + padding-bottom: 40px; } + .sweet-alert .sa-icon { + width: 80px; + height: 80px; + border: 4px solid gray; + -webkit-border-radius: 40px; + border-radius: 40px; + border-radius: 50%; + margin: 20px auto; + padding: 0; + position: relative; + box-sizing: content-box; } + .sweet-alert .sa-icon.sa-error { + border-color: #F27474; } + .sweet-alert .sa-icon.sa-error .sa-x-mark { + position: relative; + display: block; } + .sweet-alert .sa-icon.sa-error .sa-line { + position: absolute; + height: 5px; + width: 47px; + background-color: #F27474; + display: block; + top: 37px; + border-radius: 2px; } + .sweet-alert .sa-icon.sa-error .sa-line.sa-left { + -webkit-transform: rotate(45deg); + transform: rotate(45deg); + left: 17px; } + .sweet-alert .sa-icon.sa-error .sa-line.sa-right { + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + right: 16px; } + .sweet-alert .sa-icon.sa-warning { + border-color: #F8BB86; } + .sweet-alert .sa-icon.sa-warning .sa-body { + position: absolute; + width: 5px; + height: 47px; + left: 50%; + top: 10px; + -webkit-border-radius: 2px; + border-radius: 2px; + margin-left: -2px; + background-color: #F8BB86; } + .sweet-alert .sa-icon.sa-warning .sa-dot { + position: absolute; + width: 7px; + height: 7px; + -webkit-border-radius: 50%; + border-radius: 50%; + margin-left: -3px; + left: 50%; + bottom: 10px; + background-color: #F8BB86; } + .sweet-alert .sa-icon.sa-info { + border-color: #C9DAE1; } + .sweet-alert .sa-icon.sa-info::before { + content: ""; + position: absolute; + width: 5px; + height: 29px; + left: 50%; + bottom: 17px; + border-radius: 2px; + margin-left: -2px; + background-color: #C9DAE1; } + .sweet-alert .sa-icon.sa-info::after { + content: ""; + position: absolute; + width: 7px; + height: 7px; + border-radius: 50%; + margin-left: -3px; + top: 19px; + background-color: #C9DAE1; } + .sweet-alert .sa-icon.sa-success { + border-color: #A5DC86; } + .sweet-alert .sa-icon.sa-success::before, .sweet-alert .sa-icon.sa-success::after { + content: ''; + -webkit-border-radius: 40px; + border-radius: 40px; + border-radius: 50%; + position: absolute; + width: 60px; + height: 120px; + background: white; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); } + .sweet-alert .sa-icon.sa-success::before { + -webkit-border-radius: 120px 0 0 120px; + border-radius: 120px 0 0 120px; + top: -7px; + left: -33px; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + -webkit-transform-origin: 60px 60px; + transform-origin: 60px 60px; } + .sweet-alert .sa-icon.sa-success::after { + -webkit-border-radius: 0 120px 120px 0; + border-radius: 0 120px 120px 0; + top: -11px; + left: 30px; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + -webkit-transform-origin: 0px 60px; + transform-origin: 0px 60px; } + .sweet-alert .sa-icon.sa-success .sa-placeholder { + width: 80px; + height: 80px; + border: 4px solid rgba(165, 220, 134, 0.2); + -webkit-border-radius: 40px; + border-radius: 40px; + border-radius: 50%; + box-sizing: content-box; + position: absolute; + left: -4px; + top: -4px; + z-index: 2; } + .sweet-alert .sa-icon.sa-success .sa-fix { + width: 5px; + height: 90px; + background-color: white; + position: absolute; + left: 28px; + top: 8px; + z-index: 1; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); } + .sweet-alert .sa-icon.sa-success .sa-line { + height: 5px; + background-color: #A5DC86; + display: block; + border-radius: 2px; + position: absolute; + z-index: 2; } + .sweet-alert .sa-icon.sa-success .sa-line.sa-tip { + width: 25px; + left: 14px; + top: 46px; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); } + .sweet-alert .sa-icon.sa-success .sa-line.sa-long { + width: 47px; + right: 8px; + top: 38px; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); } + .sweet-alert .sa-icon.sa-custom { + background-size: contain; + border-radius: 0; + border: none; + background-position: center center; + background-repeat: no-repeat; } + +/* + * Animations + */ +@-webkit-keyframes showSweetAlert { + 0% { + transform: scale(0.7); + -webkit-transform: scale(0.7); } + 45% { + transform: scale(1.05); + -webkit-transform: scale(1.05); } + 80% { + transform: scale(0.95); + -webkit-transform: scale(0.95); } + 100% { + transform: scale(1); + -webkit-transform: scale(1); } } + +@keyframes showSweetAlert { + 0% { + transform: scale(0.7); + -webkit-transform: scale(0.7); } + 45% { + transform: scale(1.05); + -webkit-transform: scale(1.05); } + 80% { + transform: scale(0.95); + -webkit-transform: scale(0.95); } + 100% { + transform: scale(1); + -webkit-transform: scale(1); } } + +@-webkit-keyframes hideSweetAlert { + 0% { + transform: scale(1); + -webkit-transform: scale(1); } + 100% { + transform: scale(0.5); + -webkit-transform: scale(0.5); } } + +@keyframes hideSweetAlert { + 0% { + transform: scale(1); + -webkit-transform: scale(1); } + 100% { + transform: scale(0.5); + -webkit-transform: scale(0.5); } } + +@-webkit-keyframes slideFromTop { + 0% { + top: 0%; } + 100% { + top: 50%; } } + +@keyframes slideFromTop { + 0% { + top: 0%; } + 100% { + top: 50%; } } + +@-webkit-keyframes slideToTop { + 0% { + top: 50%; } + 100% { + top: 0%; } } + +@keyframes slideToTop { + 0% { + top: 50%; } + 100% { + top: 0%; } } + +@-webkit-keyframes slideFromBottom { + 0% { + top: 70%; } + 100% { + top: 50%; } } + +@keyframes slideFromBottom { + 0% { + top: 70%; } + 100% { + top: 50%; } } + +@-webkit-keyframes slideToBottom { + 0% { + top: 50%; } + 100% { + top: 70%; } } + +@keyframes slideToBottom { + 0% { + top: 50%; } + 100% { + top: 70%; } } + +.showSweetAlert[data-animation=pop] { + -webkit-animation: showSweetAlert 0.3s; + animation: showSweetAlert 0.3s; } + +.showSweetAlert[data-animation=none] { + -webkit-animation: none; + animation: none; } + +.showSweetAlert[data-animation=slide-from-top] { + -webkit-animation: slideFromTop 0.3s; + animation: slideFromTop 0.3s; } + +.showSweetAlert[data-animation=slide-from-bottom] { + -webkit-animation: slideFromBottom 0.3s; + animation: slideFromBottom 0.3s; } + +.hideSweetAlert[data-animation=pop] { + -webkit-animation: hideSweetAlert 0.2s; + animation: hideSweetAlert 0.2s; } + +.hideSweetAlert[data-animation=none] { + -webkit-animation: none; + animation: none; } + +.hideSweetAlert[data-animation=slide-from-top] { + -webkit-animation: slideToTop 0.4s; + animation: slideToTop 0.4s; } + +.hideSweetAlert[data-animation=slide-from-bottom] { + -webkit-animation: slideToBottom 0.3s; + animation: slideToBottom 0.3s; } + +@-webkit-keyframes animateSuccessTip { + 0% { + width: 0; + left: 1px; + top: 19px; } + 54% { + width: 0; + left: 1px; + top: 19px; } + 70% { + width: 50px; + left: -8px; + top: 37px; } + 84% { + width: 17px; + left: 21px; + top: 48px; } + 100% { + width: 25px; + left: 14px; + top: 45px; } } + +@keyframes animateSuccessTip { + 0% { + width: 0; + left: 1px; + top: 19px; } + 54% { + width: 0; + left: 1px; + top: 19px; } + 70% { + width: 50px; + left: -8px; + top: 37px; } + 84% { + width: 17px; + left: 21px; + top: 48px; } + 100% { + width: 25px; + left: 14px; + top: 45px; } } + +@-webkit-keyframes animateSuccessLong { + 0% { + width: 0; + right: 46px; + top: 54px; } + 65% { + width: 0; + right: 46px; + top: 54px; } + 84% { + width: 55px; + right: 0px; + top: 35px; } + 100% { + width: 47px; + right: 8px; + top: 38px; } } + +@keyframes animateSuccessLong { + 0% { + width: 0; + right: 46px; + top: 54px; } + 65% { + width: 0; + right: 46px; + top: 54px; } + 84% { + width: 55px; + right: 0px; + top: 35px; } + 100% { + width: 47px; + right: 8px; + top: 38px; } } + +@-webkit-keyframes rotatePlaceholder { + 0% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); } + 5% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); } + 12% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); } + 100% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); } } + +@keyframes rotatePlaceholder { + 0% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); } + 5% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); } + 12% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); } + 100% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); } } + +.animateSuccessTip { + -webkit-animation: animateSuccessTip 0.75s; + animation: animateSuccessTip 0.75s; } + +.animateSuccessLong { + -webkit-animation: animateSuccessLong 0.75s; + animation: animateSuccessLong 0.75s; } + +.sa-icon.sa-success.animate::after { + -webkit-animation: rotatePlaceholder 4.25s ease-in; + animation: rotatePlaceholder 4.25s ease-in; } + +@-webkit-keyframes animateErrorIcon { + 0% { + transform: rotateX(100deg); + -webkit-transform: rotateX(100deg); + opacity: 0; } + 100% { + transform: rotateX(0deg); + -webkit-transform: rotateX(0deg); + opacity: 1; } } + +@keyframes animateErrorIcon { + 0% { + transform: rotateX(100deg); + -webkit-transform: rotateX(100deg); + opacity: 0; } + 100% { + transform: rotateX(0deg); + -webkit-transform: rotateX(0deg); + opacity: 1; } } + +.animateErrorIcon { + -webkit-animation: animateErrorIcon 0.5s; + animation: animateErrorIcon 0.5s; } + +@-webkit-keyframes animateXMark { + 0% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; } + 50% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; } + 80% { + transform: scale(1.15); + -webkit-transform: scale(1.15); + margin-top: -6px; } + 100% { + transform: scale(1); + -webkit-transform: scale(1); + margin-top: 0; + opacity: 1; } } + +@keyframes animateXMark { + 0% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; } + 50% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; } + 80% { + transform: scale(1.15); + -webkit-transform: scale(1.15); + margin-top: -6px; } + 100% { + transform: scale(1); + -webkit-transform: scale(1); + margin-top: 0; + opacity: 1; } } + +.animateXMark { + -webkit-animation: animateXMark 0.5s; + animation: animateXMark 0.5s; } + +@-webkit-keyframes pulseWarning { + 0% { + border-color: #F8D486; } + 100% { + border-color: #F8BB86; } } + +@keyframes pulseWarning { + 0% { + border-color: #F8D486; } + 100% { + border-color: #F8BB86; } } + +.pulseWarning { + -webkit-animation: pulseWarning 0.75s infinite alternate; + animation: pulseWarning 0.75s infinite alternate; } + +@-webkit-keyframes pulseWarningIns { + 0% { + background-color: #F8D486; } + 100% { + background-color: #F8BB86; } } + +@keyframes pulseWarningIns { + 0% { + background-color: #F8D486; } + 100% { + background-color: #F8BB86; } } + +.pulseWarningIns { + -webkit-animation: pulseWarningIns 0.75s infinite alternate; + animation: pulseWarningIns 0.75s infinite alternate; } + +@-webkit-keyframes rotate-loading { + 0% { + transform: rotate(0deg); } + 100% { + transform: rotate(360deg); } } + +@keyframes rotate-loading { + 0% { + transform: rotate(0deg); } + 100% { + transform: rotate(360deg); } } + +/* Internet Explorer 9 has some special quirks that are fixed here */ +/* The icons are not animated. */ +/* This file is automatically merged into sweet-alert.min.js through Gulp */ +/* Error icon */ +.sweet-alert .sa-icon.sa-error .sa-line.sa-left { + -ms-transform: rotate(45deg) \9; } + +.sweet-alert .sa-icon.sa-error .sa-line.sa-right { + -ms-transform: rotate(-45deg) \9; } + +/* Success icon */ +.sweet-alert .sa-icon.sa-success { + border-color: transparent\9; } + +.sweet-alert .sa-icon.sa-success .sa-line.sa-tip { + -ms-transform: rotate(45deg) \9; } + +.sweet-alert .sa-icon.sa-success .sa-line.sa-long { + -ms-transform: rotate(-45deg) \9; } + +/*! + * Load Awesome v1.1.0 (http://github.danielcardoso.net/load-awesome/) + * Copyright 2015 Daniel Cardoso <@DanielCardoso> + * Licensed under MIT + */ +.la-ball-fall, +.la-ball-fall > div { + position: relative; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } + +.la-ball-fall { + display: block; + font-size: 0; + color: #fff; } + +.la-ball-fall.la-dark { + color: #333; } + +.la-ball-fall > div { + display: inline-block; + float: none; + background-color: currentColor; + border: 0 solid currentColor; } + +.la-ball-fall { + width: 54px; + height: 18px; } + +.la-ball-fall > div { + width: 10px; + height: 10px; + margin: 4px; + border-radius: 100%; + opacity: 0; + -webkit-animation: ball-fall 1s ease-in-out infinite; + -moz-animation: ball-fall 1s ease-in-out infinite; + -o-animation: ball-fall 1s ease-in-out infinite; + animation: ball-fall 1s ease-in-out infinite; } + +.la-ball-fall > div:nth-child(1) { + -webkit-animation-delay: -200ms; + -moz-animation-delay: -200ms; + -o-animation-delay: -200ms; + animation-delay: -200ms; } + +.la-ball-fall > div:nth-child(2) { + -webkit-animation-delay: -100ms; + -moz-animation-delay: -100ms; + -o-animation-delay: -100ms; + animation-delay: -100ms; } + +.la-ball-fall > div:nth-child(3) { + -webkit-animation-delay: 0ms; + -moz-animation-delay: 0ms; + -o-animation-delay: 0ms; + animation-delay: 0ms; } + +.la-ball-fall.la-sm { + width: 26px; + height: 8px; } + +.la-ball-fall.la-sm > div { + width: 4px; + height: 4px; + margin: 2px; } + +.la-ball-fall.la-2x { + width: 108px; + height: 36px; } + +.la-ball-fall.la-2x > div { + width: 20px; + height: 20px; + margin: 8px; } + +.la-ball-fall.la-3x { + width: 162px; + height: 54px; } + +.la-ball-fall.la-3x > div { + width: 30px; + height: 30px; + margin: 12px; } + +/* + * Animation + */ +@-webkit-keyframes ball-fall { + 0% { + opacity: 0; + -webkit-transform: translateY(-145%); + transform: translateY(-145%); } + 10% { + opacity: .5; } + 20% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); } + 80% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); } + 90% { + opacity: .5; } + 100% { + opacity: 0; + -webkit-transform: translateY(145%); + transform: translateY(145%); } } + +@-moz-keyframes ball-fall { + 0% { + opacity: 0; + -moz-transform: translateY(-145%); + transform: translateY(-145%); } + 10% { + opacity: .5; } + 20% { + opacity: 1; + -moz-transform: translateY(0); + transform: translateY(0); } + 80% { + opacity: 1; + -moz-transform: translateY(0); + transform: translateY(0); } + 90% { + opacity: .5; } + 100% { + opacity: 0; + -moz-transform: translateY(145%); + transform: translateY(145%); } } + +@-o-keyframes ball-fall { + 0% { + opacity: 0; + -o-transform: translateY(-145%); + transform: translateY(-145%); } + 10% { + opacity: .5; } + 20% { + opacity: 1; + -o-transform: translateY(0); + transform: translateY(0); } + 80% { + opacity: 1; + -o-transform: translateY(0); + transform: translateY(0); } + 90% { + opacity: .5; } + 100% { + opacity: 0; + -o-transform: translateY(145%); + transform: translateY(145%); } } + +@keyframes ball-fall { + 0% { + opacity: 0; + -webkit-transform: translateY(-145%); + -moz-transform: translateY(-145%); + -o-transform: translateY(-145%); + transform: translateY(-145%); } + 10% { + opacity: .5; } + 20% { + opacity: 1; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + transform: translateY(0); } + 80% { + opacity: 1; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + transform: translateY(0); } + 90% { + opacity: .5; } + 100% { + opacity: 0; + -webkit-transform: translateY(145%); + -moz-transform: translateY(145%); + -o-transform: translateY(145%); + transform: translateY(145%); } } diff --git a/css files/welcome-style.css b/css files/welcome-style.css new file mode 100644 index 0000000..6f4810e --- /dev/null +++ b/css files/welcome-style.css @@ -0,0 +1,84 @@ +/*Created by Akanksha + Desc: CSS for welcome.php +*/ +body { + background-color: #05d197; + margin: 0; +} + +.button { /*The green buttons css*/ + background-color: #2db58f; + border-width: 3px; + border-color: #ffffff; + color: #ffffff; + cursor: pointer; + font-size: 20px; + height: 150px; + margin-top: 30px; + text-align: center; + width: 100%; +} + +.button:hover { + background-color: #02845f; +} + +.button-org {/*Orange buttons css*/ + background-color: #ffd590; + border-width: 3px; + border-color: #ffffff; + color: #ffffff; + cursor: pointer; + font-size: 20px; + height: 150px; + margin-top: 30px; + text-align: center; + width: 100%; +} + +.button-org:hover { + background-color: #ffffff; + color: #ffd590; +} + +.line { + color: white; + width: 50%; +} + +#buttons-table {/*table containing buttons*/ + border-collapse:separate; + border-spacing:50px 50px; + width: 100%; + height: 200px; +} + +.text { + color: #ffffff; + font-style: bold; +} + +.window { + height: 100%; + margin-left: 25%; + padding: 1px 16px; +} + +/*custom scrollbar for the app*/ +::-webkit-scrollbar { + width: 12px; + background-color: #f5f5f5; +} + +::-webkit-scrollbar-track { + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); + border-radius: 10px; + background-color: #f5f5f5; +} + +::-webkit-scrollbar-thumb { + border-radius: 10px; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); + background-color: #bdbdbd; +} + diff --git a/database/pcsa_web.sql b/database/pcsa_web.sql new file mode 100644 index 0000000..e0bc08c --- /dev/null +++ b/database/pcsa_web.sql @@ -0,0 +1,99 @@ +-- phpMyAdmin SQL Dump +-- version 4.5.1 +-- http://www.phpmyadmin.net +-- +-- Host: 127.0.0.1 +-- Generation Time: Aug 09, 2016 at 02:44 PM +-- Server version: 10.1.10-MariaDB +-- PHP Version: 5.6.19 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `pcsa_web` +-- + +DELIMITER $$ +-- +-- Procedures +-- +CREATE DEFINER=`root`@`localhost` PROCEDURE `addcomrade` (IN `id` INT(1), IN `mail` VARCHAR(100)) NO SQL +INSERT INTO comrade(comradeid,email)VALUES(id,mail)$$ + +CREATE DEFINER=`root`@`localhost` PROCEDURE `dupemail` (IN `mail` VARCHAR(100)) SELECT *from user where email = mail$$ + +CREATE DEFINER=`root`@`localhost` PROCEDURE `getcomradenum` (IN `inemail` VARCHAR(100), IN `incomradeid` INT(1)) select phonenumber from comrade where email = inemail and comradeid = incomradeid$$ + +CREATE DEFINER=`root`@`localhost` PROCEDURE `login` (IN `pass` VARCHAR(100), IN `mail` VARCHAR(100)) SELECT * from user where password = pass AND email = mail$$ + +CREATE DEFINER=`root`@`localhost` PROCEDURE `registration` (IN `mail` VARCHAR(100), IN `uname` VARCHAR(100), IN `pass` VARCHAR(100), IN `country` VARCHAR(100)) INSERT INTO user VALUES(mail,uname,pass,country)$$ + +CREATE DEFINER=`root`@`localhost` PROCEDURE `updatecomrade` (IN `id` INT(1), IN `mail` VARCHAR(100), IN `phno` VARCHAR(100)) NO SQL +UPDATE comrade SET phonenumber = phno where email = mail and comradeid = id$$ + +DELIMITER ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `comrade` +-- + +CREATE TABLE `comrade` ( + `comradeid` int(1) NOT NULL, + `email` varchar(100) NOT NULL, + `phonenumber` varchar(100) DEFAULT NULL, + `comrade_email` varchar(100) CHARACTER SET latin1 DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `user` +-- + +CREATE TABLE `user` ( + `email` varchar(100) NOT NULL, + `username` varchar(100) CHARACTER SET latin1 NOT NULL, + `password` varchar(100) CHARACTER SET latin1 NOT NULL, + `host_country` varchar(100) CHARACTER SET latin1 NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `comrade` +-- +ALTER TABLE `comrade` + ADD PRIMARY KEY (`comradeid`,`email`), + ADD UNIQUE KEY `comrade_email` (`comrade_email`), + ADD KEY `email` (`email`); + +-- +-- Indexes for table `user` +-- +ALTER TABLE `user` + ADD PRIMARY KEY (`email`); + +-- +-- Constraints for dumped tables +-- + +-- +-- Constraints for table `comrade` +-- +ALTER TABLE `comrade` + ADD CONSTRAINT `comrade_ibfk_1` FOREIGN KEY (`email`) REFERENCES `user` (`email`); + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/dbconnect.php b/dbconnect.php new file mode 100644 index 0000000..8442bf6 --- /dev/null +++ b/dbconnect.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/editComrades.php b/editComrades.php new file mode 100644 index 0000000..4cde153 --- /dev/null +++ b/editComrades.php @@ -0,0 +1,130 @@ + + + + + FirstAide + + + + +
+ + + +
+
+
+

Circle of Trust

+
+

My Trustees

+

Add the Comrade Numbers here

+
+ +
+ + + +
+ + 0) + { + echo ""; + } + else if(count(array_unique($formphnos))salert('Duplicate Phone Number','Please enter again!','error');"; + } + else + { + for($i=1;$i<=6;$i++) + { + $id = 'comrade'.$i; + $phno = $_POST[$id]; + + if(empty($phno)) + { + $query = mysqli_query($connection,"CALL updatecomrade($i,'$useremail',NULL)"); + } + else + { + $query = mysqli_query($connection,"CALL updatecomrade($i,'$useremail','$phno')"); + } + $connection -> next_result(); + } + + //Messages to inform state of execution + $nochange = 0; + $empty = 0; + + for($i=1;$i<=6;$i++) + { + $id = 'comrade'.$i; + $newphno = $_POST[$id]; + + if($newphno==$dbphnos[$i]) + $nochange++; + if($newphno==NULL) + $empty++; + } + //Possible messages after execution + if($empty==6) + echo ""; + else if($nochange==6) + echo ""; + else + echo ""; + + } + + } + mysqli_close($connection); + include('loadComradeNumbers.php'); //load phonenumbers again after updation +?> + +
+ + + + + + +
+ +
+
+ + + + diff --git a/getHelpNow.php b/getHelpNow.php new file mode 100644 index 0000000..bb05fbf --- /dev/null +++ b/getHelpNow.php @@ -0,0 +1,107 @@ + + + + + FirstAide + + + + +
+
+
+

Get Help Now

+
+ + + + + + + + +
Change Location: + +

This information is for Syria (current post)

+
+ + + + + + + + + + + +
+ + + +
+ + + + + +
+ + + + + + + + + + +
+
+ + + + + + + + + diff --git a/getHelpNow2.php b/getHelpNow2.php new file mode 100644 index 0000000..3a1a151 --- /dev/null +++ b/getHelpNow2.php @@ -0,0 +1,60 @@ + + + + + FirstAide + + + + +
+
+ +
+

Get Help Now

+
+
+ +
+ + + +
+ +
+ + + + + + + + + +
+ + + +
+ + + +
+
+
+
+ + \ No newline at end of file diff --git a/groupsms.php b/groupsms.php new file mode 100644 index 0000000..ee6adec --- /dev/null +++ b/groupsms.php @@ -0,0 +1,74 @@ + array( + CURLOPT_SSL_VERIFYPEER => false + ))); + + //instantiate a new Twilio Rest Client + $client = new Services_Twilio($AccountSid, $AuthToken, '2010-04-01', $http); + + //Loop over all comrades. $number is a phone number above, and + // $name is the name next to it + try { + foreach ($toNos as $number) { + + $sms = $client->account->messages->sendMessage( + // Change the 'From' number below to be a valid Twilio number + // that you've purchased, or the (deprecated) Sandbox number + "", + // the number we are sending to - Any phone number + $number, + // the sms body + $msg + ); + // Send a valid response back to circleOfTrustMessage.js + $success = 1; + if($empty==6) + $success==0; + else + $success == $filled; + echo $success; + } + } + catch(\Services_Twilio_RestException $e){ + $error = $e->getMessage(); + echo $error; + } + + /*do not close php using ?> here*/ + + \ No newline at end of file diff --git a/images/PClogoWhite.png b/images/PClogoWhite.png new file mode 100644 index 0000000000000000000000000000000000000000..0686c0805ab8c908d23088a83bec628fd44ac29f GIT binary patch literal 77481 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 bEJd7UXpHc+77-xhG=-jyv39Md^W*;ma+#8# literal 0 HcmV?d00001 diff --git a/images/bw-arrow.png b/images/bw-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..2d91e90b7d28835e0aa695232d72c1ca064dc33c GIT binary patch literal 20832 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 Q=O5KLta7m}vGL#W5996E=Kufz literal 0 HcmV?d00001 diff --git a/images/close-button.png b/images/close-button.png new file mode 100644 index 0000000000000000000000000000000000000000..76e7f2632554583cdb72ee9dc8fa601c59c65983 GIT binary patch literal 5299 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 literal 0 HcmV?d00001 diff --git a/images/drag_hand.png b/images/drag_hand.png new file mode 100644 index 0000000000000000000000000000000000000000..8e3f08d4ecefffbfb58f53d5452bca9f49c82988 GIT binary patch literal 25133 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 X%U%4*`zTo919ofHSyftW-u-_77Gg7B literal 0 HcmV?d00001 diff --git a/images/ic_comrade.png b/images/ic_comrade.png new file mode 100644 index 0000000000000000000000000000000000000000..e0879588a8c750aaacd3ea427ad6679898108dd8 GIT binary patch literal 6820 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 P00000NkvXXu0mjfLBzEO literal 0 HcmV?d00001 diff --git a/images/ic_help_me.png b/images/ic_help_me.png new file mode 100644 index 0000000000000000000000000000000000000000..366c060a7cda0f7e81624c7ad46d7974be8eb944 GIT binary patch literal 10851 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

=t|#p?WQaLv~mSA8r|%PdywVS)3W9Mjhh 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 literal 0 HcmV?d00001 diff --git a/images/mail.png b/images/mail.png new file mode 100644 index 0000000000000000000000000000000000000000..e30392bcadb5f35b74960a675ea01eb0d3ea96ea GIT binary patch literal 6897 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 literal 0 HcmV?d00001 diff --git a/images/phone.png b/images/phone.png new file mode 100644 index 0000000000000000000000000000000000000000..ba0716f971843b5f29b46cc1433037dd92cb1777 GIT binary patch literal 262892 zcmeI54{TIdc887STF7Ntx{44@Eovc((i9=IO(T>h(FRcpQN%_mLTR*O5keG2G>W1q z8&&N>no>&BC_*WU5K5yo+NBZN(p3amgOI}?1I8FL7%+}8jsfF<N*^4R7ANf4=8)-aY4@d+w&Em;Ckj%I+^KDk}Qk;zbLdDJq(vuM>(U zmg?}6m;PsUQBg(F;ssAEeRV=n#roEDI?D$F5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwx`u}Yw}an(P#Sb(wG2igq*2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX?}?+85h{f~c4EWq!0@C^bGfB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##ATZVm5DPHYpCIjr00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009Vmmq3_UfX~+b@%rzU!v7!u0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00I!m7Xlj}eqrUMnT!oIq`D?es6c_~N-MSFY6G zxN)QJ?%lfsw{G3)@9gaSsHv%Ge$E?610VnazXVR4I8k=(+O_GQefHV5ufP5}@y$2i z^nd&9w*x~zH*enTIDh{9QoprR8U!Ga69R`09V*jXeYxKB+a>sSh6;ST|4RvU*VNQZ z%}Il)6ao;4MqvN`{iPE6IU3@>B4KXo>+9=H_qIY7DbW!B-H`;?6vLNae!0bY?`-IK|0w{PF>m9z1=xcW>z z5P*OP*tFlJOP5}ho!>i}z$yr+UAFox2ToCaZ;y6Q(BDnLXaw@16ibOKpCbeykYxfA z==(MNz8XYO&12u%+Pc;?Nj`&_ckTpQ1`wq9f!^NUzUJoUDXx5u5P(1y2^=_ZpiEJD zzaGx+PbamC2S^+|c(BZxrC^~_y|q8i!|V~TeqddU z?Vzfl1hmR$iC*d5sS-KbcU|A36++25LfHi?bgpl-`-1-7)6-LDi3Wo9f$Jaufsh3B zI?vdvXRm)n^1Sa{_!=JkKsJT9IYKFueuXD43)v-Zg8&4A5IA+})FOrcg__sXbU?41 z3CXv#-1!@Q+69_(tPau#u7LmqLJ+8~uAXACzfpu%LchUPEi+)2hVG+ID+DzI6mZa^ z>593oe2x%+fJXxI1U@bod?bIq?yot1{P;9$*5Sj4OXV$mCyGKzRSq`&pb*8)GB21T z^!VH<3Ic-!wElO*D4}>HHu{- zZ1Y*ZOpI+>qKIQK!gJ?V2n-TXqP|(Sm56&)*R+q&e$k~W9FvDlgg7TC;~J>!nD#?EWmKuLBcOf;K-oeF4Le)j=~Ro)oCV&@*2F!4x|AdHkUwP zC;<(pw+|<{zRt^TzoqpD&$zlZI#}Ur-GC_)ts6L_<;{!;9AJ(R2ueV2&p-(RqbdWL z9Xnl{EG@AG4Mi=}-7jS_kg8x@Jscqbfl&xZ5WU&vP9W1AH5GVA`-}}PAGRiGq0cKm zgM_qv_+VvaB~gN-Ja2x6z;_5pFw@Da_j5K>*KEK>SGfX_eyG_3Z=(Qx%4?c1w2Suat3}UiHP3X%|Y%P?HW@g znr%PHYTBmLFh)y!XY{JedTx_gG`5H-u%hwL4996 zT;}3?-u@2R`Fj;jIA0@|WOQL_fA|go2xLGYmkPj!@fyCr=bEdx`4naTX&tIS^tSI% z$nOS4{LORMa)bZ`JP?r3EgULvasJ=(1=yw~t}9yH^SUVpB`%SL&|P`c0_k0K!efsqJkJYHsF@LYW4>FZN~ zK$F7x9@j`@FuUkTZRIxzKp+bQY@RI_A9)0;G|b1npM_^ikq`(>Ag*j7sY*t5wrTed zqIm*8B`$m{2Kai(y$*_f0mvp#X=x30fpFk+tDM4@{q}KtG>Se z*}x6tLI^-0djym+_}w6a>+2eY|8?r^|4{aNM9J|InDNfszZfAFAl}AMTNDBso-dDc zRzUS#(oDqEC~f9m2tdFS0cG%9Zi)Be`bYt^X*56#fT!n2F%XDEpslU#IR)lKPS+Du zfyf_l{qW(#3nMj}n;`%JKLoT+_fZArcLWvSsMjeq&>b!HTkWUylmY<=L?U1d_GJQ8 zM-}X#_p7dcMFPGOsnOgF0SNdbpnO|oe>&)S(LBK!yYds}F00NN+C_?YOsDhoz z{aXBgyavrM^ODvA~_ zcw%X8TSDy~320hyx`yacWjyfx7ACCFX8@ea31betpCdj6+ z?d3iQK)@pbB@vt=8@fD+Tv?>;gqW00LnN*or+R@*7Ot7g&NLUZ_B%CMh0v z{RsQexDNt83CIk1NfCRoMF&a&+>uj|)q*}BB4t4!EP+FZ4n27H?%mj;11&Z{xxrrx z+g|R200cY}&}=|c#F2eQw`&XG4$obnI0!%>ECGel4V@yX=! z$3Oe0jZ)Dg=LJ|lur8NPr0y&cP+FfkS~=7b=deIA!<|~JFg;6MqF4w(AQJ*|)$fW^ z0a#rMQzQvZCJ%{gA&@Ns=gys56X*P(DF7**y;W6JLy33xRA9(00G&njdU4`#jE1eSJNP1+wu#DH8&j66omY*cYepTV3)$ zyens5ai(qMdd~!2pRn)`MvDdTTqVWjF#!efKdmUfSoMJ-hMG>FKK(!*W1(pfC=3D( z4GlB2aG)_x4RCLVkrxVsFujC89uu&YLvqq>iF0Pal#QYUn-w>VNsz~X8#Jvz2uKhg z(sW&Xn~X^TSbYjiT3H~7=_Um7n}D_$iglfUjW{$4*jZa!J2}6}&^ibd00Ef+Yb|Ie z&X0B(=~G<74+{V6F7D1)LbPKY>iU^SY21HT-lM|WM~}(3WR{Ni0p`40caG^ zCNp4efgsM0Znm%c%bmmmS zm=fAyWdHk?7Ytg$>z;ran$oALnR)!;Lp?+^APrbc2$ZB-+~A-q5C}GqYVk zuVO88|#ZA$e5Gq2kzOk`!mM>CDRsN7h7SAj2sa>OtJ3|FORl(g;0u3^S zDty%+dpRFI`OCe5Vgc3i(6629v_l(-cFQ zJe&_H4AEZymuz7|(2sdVWiML+s806I2sey~cOQP@k9yOpWKu z72xo^vZL0RlOd?k54}!{7@FlgAfZ7f@VRz;5jb$*K$#5aoJ*bXdU;a-Zfe8@1NC#C1!4 zgKa(?ml^@R>&oT`fr2D(^5n@9Egk&Gr(gvU?jYCbE!~^CH(7IY^OMSd)*a;DAlIm@ zX3a*B*Q_A_^67MvfP`#;grPHt(8PI-DJ4z#Z-cvO{7`liGX$=dB>NK`7B31fId0zk~zp)T3S~4EMF!@%XoT@ z^aTQ;2*~3;Q}%aDzL^Eq9tH7iah+1I|1?cyw);{778fCtC~L9HuH76Vkkq0zD5M5&@{qG#vhE;=SI6B;EjOd1fEu$Ku_Fn`{C-7W3Z>8 zp<#*Zpgj4{cpe2b)YjHkxbitdpr8p@5RR7bzAGg#oJ_`g-rn|_!+%FYT51nQ*@Gr4 zXvo{T0gFG7<1uMw6!gQV^AIosvWv?lWU+5TIGkp&ARaC8t#D6Ap~5c@cWs#Sia$uW zvN=Kk0wSRG`m+@*lozIejRIO*TVHbzMt1u&O%HktWK#Kk8eu%*%I63H2#A2*y06&W zd6>7V?|Y<-YBYT}m~mLbTA~<+&Ayz0R*syFTUCD2*~lLN1PY#jA_i?y&KBRo9Hu-? z*;&HR=iEb)V{nm_)AcZArMpLFM!Qx^<|K*8%*tJVN-ThTvK;f4fR@yjE0Ctf*DAeq zf*9nSy|HDtS1Mp=Fk*23{{1C-gVzMPH^?>CKkZBQQrYL#c@y40 zdh{r(2MsVE2n;2l+VhSa7$2q^?_NkmL3C^UL=YWaMJ00dG9NI=RYgun9XfJ^r_ z9`2m#?Y8t`u1Qh=%Y1H&CWmK2NlKC#i(Ne&Apn7U1T+dL)hfadbD;!m%1*HgZ`)L$ zHAfMQQ+=Zr5b!}jLxZVu%YT%MpaIp} zE-z(;>xY~bZ}^QN(#{hD`7h9bIpI6?pdX$aKU z*H4r!{<4%nr_VR>aDr@gXz2gGQVS1y2Q?ZnbEIy#>oYyC<%r$Np_ZI}NYiCbK>z}& z1e9*5RFO4Hl+&v_4kciAzm^bc3*O&;G+nXQSG`gI*H525{je*WBLpB2kbts#JS3Yu zk?C7E%=MZL*yx%ilVGMs0hhv*GxQ!MDA*;1mQ*gT4vr9jKmY=^dPhU__k7yrLxt4- zuSlM1MG6h>I%?^KRp*wdqX3%)Q1XB^0lJyVC3Bzn<<8)-0GX7`wGbE!1eA<$jfU;* zQ3W)eBCvB(Hhoe6iyRB37MiCxh0u;co7vE8zz$a)M+iV50s%SdiuGo#(6nKt&s9B6 zA(!0u0NqJnyA-S0t72H45!BL#=N(uC+vTyCszdk99M&0wgW*26;GB`p20$Cs+C)*Tx@i+K13oJBQ zBaAn8?bD!^; zo(>;j#hSuvI(zo)bXTdSCf`m~0QR;w6GVdFXvqO(mdw$pgp|P!7)J=?f`FF#&5~)b zQ3BkSDzKS;HzlGF!EKQ@K2sfFYly3>s;UO}8s!_%kDTU2?1(Z@pjt-P6PZ}{lK~$G?XeK009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|2t?pdX7>F)c>w~U;vxt@00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fWVj_5F#(YnCKUcga8B}009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf6e-7BP~?q;mOXNaLoDJ1!XZdE9!4Am%0u|{0AZ~flK~oT52i|HuXz1`;gP6#O3sTF40?0d8MpI(kH@gW2|ag-01chY1L@u zTG3SGgsn4^x1GrM=IhTtnv9ChEwot|)Wzgp(y!eef^6}_`zu(mZ_>S;|Kp+sfjlkojEcE|vutHTJFfanY>D@+@ literal 0 HcmV?d00001 diff --git a/images/secure.png b/images/secure.png new file mode 100644 index 0000000000000000000000000000000000000000..759856771902da3e36c124e7e6e2945786c72eac GIT binary patch literal 4999 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 literal 0 HcmV?d00001 diff --git a/images/settings.png b/images/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..d9ae232f169480b11dceec494b3a4073e927fdcf GIT binary patch literal 7639 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 + + + + FirstAide + + + +

+ +

First Aide

+
+ + + \ No newline at end of file diff --git a/javascripts/PCMOpopup.js b/javascripts/PCMOpopup.js new file mode 100644 index 0000000..80108cf --- /dev/null +++ b/javascripts/PCMOpopup.js @@ -0,0 +1,24 @@ +/*Created by Akanksha + Desc: Popup js for ContactPCMO +*/ +function openPCMO() +{ + var popup = document.getElementById('popup-PCMO'); + var span = document.getElementById("close-PCMO"); + + //open popup on click of button + popup.style.display = "block"; + + // When the user clicks on (x), close the modal + span.onclick = function() { + popup.style.display = "none"; + } + + // When the user clicks anywhere outside of the modal, close it + window.onclick = function(event) { + if (event.target == popup) { + popup.style.display = "none"; + } + } + +} \ No newline at end of file diff --git a/javascripts/SARLpopup.js b/javascripts/SARLpopup.js new file mode 100644 index 0000000..a991c98 --- /dev/null +++ b/javascripts/SARLpopup.js @@ -0,0 +1,24 @@ +/*Created by Akanksha + Desc: Popup js for ContactSARL +*/ +function openSARL() +{ + var popup = document.getElementById('popup-SARL'); + var span = document.getElementById("close-SARL"); + + //open popup on click of button + popup.style.display = "block"; + + // When the user clicks on (x), close the popup + span.onclick = function() { + popup.style.display = "none"; + } + + // When the user clicks anywhere outside of the pupo, close it + window.onclick = function(event) { + if (event.target == popup) { + popup.style.display = "none"; + } + } + +} \ No newline at end of file diff --git a/javascripts/SSMpopup.js b/javascripts/SSMpopup.js new file mode 100644 index 0000000..2da3a44 --- /dev/null +++ b/javascripts/SSMpopup.js @@ -0,0 +1,24 @@ +/*Created by Akanksha + Desc: Popup js for ContactSSM +*/ +function openSSM() +{ + var popup = document.getElementById('popup-SSM'); + var span = document.getElementById("close-SSM"); + + //open popup on click of button + popup.style.display = "block"; + + // When the user clicks on (x), close the popup + span.onclick = function() { + popup.style.display = "none"; + } + + // When the user clicks anywhere outside of the pupo, close it + window.onclick = function(event) { + if (event.target == popup) { + popup.style.display = "none"; + } + } + +} \ No newline at end of file diff --git a/javascripts/changeloc.js b/javascripts/changeloc.js new file mode 100644 index 0000000..773be67 --- /dev/null +++ b/javascripts/changeloc.js @@ -0,0 +1,11 @@ +/*Created by Akanksha + Desc: Sets the messages to location selected in the dropdown + of getHelpNow.php + */ +function changeloc() + { + var location = document.getElementById("location").value; + //setting the selected location on screen + document.getElementById("loc").innerHTML = + "This information is for " +location+"(current post)"; +} \ No newline at end of file diff --git a/javascripts/circleOfTrustMessage.js b/javascripts/circleOfTrustMessage.js new file mode 100644 index 0000000..e45b7b3 --- /dev/null +++ b/javascripts/circleOfTrustMessage.js @@ -0,0 +1,56 @@ +$(document).ready(function() { + + $("#msg1").click(function(event){ + $.post( + "groupsms.php", + { msg: "Come and get me.I need help getting home safely.Call ASAP to get my Location.Message sent through First Aide's Circle of Trust" }, + function(data) { + + if (data>=1) + salert('Success','Message has been sent to '+data+' comrades','success'); + else if(data==0) + salert('Error','No comrades registered'+data,'error'); + else + salert('Error',data,'error'); + closePopup(); + + } + ); + + }); + + $("#msg2").click(function(event){ + $.post( + "groupsms.php", + { msg: "Call and pretend you need me.I need an interruption.Message sent through First Aide's Circle of Trust" }, + function(data) { + if (data>=1) + salert('Success','Message has been sent to '+data+' comrades','success'); + else if(data==0) + salert('Error','No comrades registered'+data,'error'); + else + salert('Error',data,'error'); + closePopup(); + } + ); + + }); + + $("#msg3").click(function(event){ + $.post( + "groupsms.php", + { msg: "I need to talk.Message sent through First Aide's Circle of Trust" }, + function(data) { + if (data>=1) + salert('Success','Message has been sent to '+data+' comrades','success'); + else if(data==0) + salert('Error','No comrades registered'+data,'error'); + else + salert('Error',data,'error'); + closePopup(); + } + ); + + }); + + }); \ No newline at end of file diff --git a/javascripts/closePopup.js b/javascripts/closePopup.js new file mode 100644 index 0000000..d68404e --- /dev/null +++ b/javascripts/closePopup.js @@ -0,0 +1,7 @@ +/*Created by Akanksha + Desc: Used to close a popup when called + */ +function closePopup(){ + var popup = document.getElementById('popup-cnt'); + popup.style.display = "none"; + } \ No newline at end of file diff --git a/javascripts/dragscroll.js b/javascripts/dragscroll.js new file mode 100644 index 0000000..6c55a2e --- /dev/null +++ b/javascripts/dragscroll.js @@ -0,0 +1,86 @@ +/** + * @fileoverview dragscroll - scroll area by dragging + * @version 0.0.6 + * + * @license MIT, see http://github.com/asvd/intence + * @copyright 2015 asvd + */ + + +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define(['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory((root.dragscroll = {})); + } +}(this, function (exports) { + var _window = window; + var _document = document; + var mousemove = 'mousemove'; + var mouseup = 'mouseup'; + var mousedown = 'mousedown'; + var EventListener = 'EventListener'; + var addEventListener = 'add'+EventListener; + var removeEventListener = 'remove'+EventListener; + + var dragged = []; + var reset = function(i, el) { + for (i = 0; i < dragged.length;) { + el = dragged[i++]; + el = el.container || el; + el[removeEventListener](mousedown, el.md, 0); + _window[removeEventListener](mouseup, el.mu, 0); + _window[removeEventListener](mousemove, el.mm, 0); + } + + // cloning into array since HTMLCollection is updated dynamically + dragged = [].slice.call(_document.getElementsByClassName('dragscroll')); + for (i = 0; i < dragged.length;) { + (function(el, lastClientX, lastClientY, pushed, scroller, cont){ + (cont = el.container || el)[addEventListener]( + mousedown, + cont.md = function(e) { + if (!el.hasAttribute('nochilddrag') || + _document.elementFromPoint( + e.pageX, e.pageY + ) == cont + ) { + pushed = 1; + lastClientX = e.clientX; + lastClientY = e.clientY; + + e.preventDefault(); + } + }, 0 + ); + + _window[addEventListener]( + mouseup, cont.mu = function() {pushed = 0;}, 0 + ); + + _window[addEventListener]( + mousemove, + cont.mm = function(e) { + if (pushed) { + (scroller = el.scroller||el).scrollLeft -= + (- lastClientX + (lastClientX=e.clientX)); + scroller.scrollTop -= + (- lastClientY + (lastClientY=e.clientY)); + } + }, 0 + ); + })(dragged[i++]); + } + } + + + if (_document.readyState == 'complete') { + reset(); + } else { + _window[addEventListener]('load', reset, 0); + } + + exports.reset = reset; +})); diff --git a/javascripts/gethelpnowPhNo.js b/javascripts/gethelpnowPhNo.js new file mode 100644 index 0000000..72ae6c7 --- /dev/null +++ b/javascripts/gethelpnowPhNo.js @@ -0,0 +1,53 @@ +/*Created by Akanksha + Desc: Sends correct number to twilio-call or twilio-sms + based on the location and organization selected + */ +function setnum(id) +{ + var phonenum = "0"; + var location = document.getElementById("location").value; + /*set var phonenum to the correct value depending on which button PCMO or SSM or SARL + invoked this function*/ + switch(id) + { + //set the correct phone numbers here (after given from Peace Corps), these are sample + case "PCMO-msg" : + case "PCMO-call": + { + if(location=="Syria") //set var phonenum according to location selected + phonenum = "4444"; + else if(location =="Uganda") + phonenum = "1111"; + else if(location == "Tunisia") + phonenum = "7777"; + break; + } + case "SSM-msg" : + case "SSM-call": + { + if(location=="Syria") + phonenum = "5555"; + else if(location =="Uganda") + phonenum = "2222"; + else if(location == "Tunisia") + phonenum = "8888"; + break; + } + case "SARL-msg" : + case "SARL-call": + { + if(location=="Syria") + phonenum = "6666"; + else if(location =="Uganda") + phonenum = "3333"; + else if(location == "Tunisia") + phonenum = "9999"; + break; + } + + } + if(id.indexOf("msg")>-1)//check if id contains "msg" string + send_sms(phonenum); //send phone number to twilio-sms.js + else + make_call(phonenum);//send phone number to twilio-call.js +} \ No newline at end of file diff --git a/javascripts/jquery-1.12.4.min.js b/javascripts/jquery-1.12.4.min.js new file mode 100644 index 0000000..e836475 --- /dev/null +++ b/javascripts/jquery-1.12.4.min.js @@ -0,0 +1,5 @@ +/*! jQuery v1.12.4 | (c) jQuery Foundation | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="1.12.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}if(f=d.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return A.find(a);this.length=1,this[0]=f}return this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||(e=n.uniqueSort(e)),D.test(a)&&(e=e.reverse())),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=!0,c||j.disable(),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.addEventListener?(d.removeEventListener("DOMContentLoaded",K),a.removeEventListener("load",K)):(d.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(d.addEventListener||"load"===a.event.type||"complete"===d.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll)a.setTimeout(n.ready);else if(d.addEventListener)d.addEventListener("DOMContentLoaded",K),a.addEventListener("load",K);else{d.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&d.documentElement}catch(e){}c&&c.doScroll&&!function f(){if(!n.isReady){try{c.doScroll("left")}catch(b){return a.setTimeout(f,50)}J(),n.ready()}}()}return I.promise(b)},n.ready.promise();var L;for(L in n(l))break;l.ownFirst="0"===L,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c,e;c=d.getElementsByTagName("body")[0],c&&c.style&&(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",l.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(e))}),function(){var a=d.createElement("div");l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}a=null}();var M=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b},N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0; +}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),"object"!=typeof b&&"function"!=typeof b||(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\w:-]+)/,_=/^$|\/(?:java|ecma)script/i,aa=/^\s+/,ba="abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video";function ca(a){var b=ba.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}!function(){var a=d.createElement("div"),b=d.createDocumentFragment(),c=d.createElement("input");a.innerHTML="
a",l.leadingWhitespace=3===a.firstChild.nodeType,l.tbody=!a.getElementsByTagName("tbody").length,l.htmlSerialize=!!a.getElementsByTagName("link").length,l.html5Clone="<:nav>"!==d.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,b.appendChild(c),l.appendChecked=c.checked,a.innerHTML="",l.noCloneChecked=!!a.cloneNode(!0).lastChild.defaultValue,b.appendChild(a),c=d.createElement("input"),c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),a.appendChild(c),l.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!!a.addEventListener,a[n.expando]=1,l.attributes=!a.getAttribute(n.expando)}();var da={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:l.htmlSerialize?[0,"",""]:[1,"X
","
"]};da.optgroup=da.option,da.tbody=da.tfoot=da.colgroup=da.caption=da.thead,da.th=da.td;function ea(a,b){var c,d,e=0,f="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,ea(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function fa(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}var ga=/<|&#?\w+;/,ha=/r;r++)if(g=a[r],g||0===g)if("object"===n.type(g))n.merge(q,g.nodeType?[g]:g);else if(ga.test(g)){i=i||p.appendChild(b.createElement("div")),j=($.exec(g)||["",""])[1].toLowerCase(),m=da[j]||da._default,i.innerHTML=m[1]+n.htmlPrefilter(g)+m[2],f=m[0];while(f--)i=i.lastChild;if(!l.leadingWhitespace&&aa.test(g)&&q.push(b.createTextNode(aa.exec(g)[0])),!l.tbody){g="table"!==j||ha.test(g)?""!==m[1]||ha.test(g)?0:i:i.firstChild,f=g&&g.childNodes.length;while(f--)n.nodeName(k=g.childNodes[f],"tbody")&&!k.childNodes.length&&g.removeChild(k)}n.merge(q,i.childNodes),i.textContent="";while(i.firstChild)i.removeChild(i.firstChild);i=p.lastChild}else q.push(b.createTextNode(g));i&&p.removeChild(i),l.appendChecked||n.grep(ea(q,"input"),ia),r=0;while(g=q[r++])if(d&&n.inArray(g,d)>-1)e&&e.push(g);else if(h=n.contains(g.ownerDocument,g),i=ea(p.appendChild(g),"script"),h&&fa(i),c){f=0;while(g=i[f++])_.test(g.type||"")&&c.push(g)}return i=null,p}!function(){var b,c,e=d.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b]=c in a)||(e.setAttribute(c,"t"),l[b]=e.attributes[c].expando===!1);e=null}();var ka=/^(?:input|select|textarea)$/i,la=/^key/,ma=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,na=/^(?:focusinfocus|focusoutblur)$/,oa=/^([^.]*)(?:\.(.+)|)/;function pa(){return!0}function qa(){return!1}function ra(){try{return d.activeElement}catch(a){}}function sa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)sa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=qa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return"undefined"==typeof n||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(G)||[""],h=b.length;while(h--)f=oa.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=oa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(i=m=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!na.test(q+n.event.triggered)&&(q.indexOf(".")>-1&&(r=q.split("."),q=r.shift(),r.sort()),h=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),l=n.event.special[q]||{},f||!l.trigger||l.trigger.apply(e,c)!==!1)){if(!f&&!l.noBubble&&!n.isWindow(e)){for(j=l.delegateType||q,na.test(j+q)||(i=i.parentNode);i;i=i.parentNode)p.push(i),m=i;m===(e.ownerDocument||d)&&p.push(m.defaultView||m.parentWindow||a)}o=0;while((i=p[o++])&&!b.isPropagationStopped())b.type=o>1?j:l.bindType||q,g=(n._data(i,"events")||{})[b.type]&&n._data(i,"handle"),g&&g.apply(i,c),g=h&&i[h],g&&g.apply&&M(i)&&(b.result=g.apply(i,c),b.result===!1&&b.preventDefault());if(b.type=q,!f&&!b.isDefaultPrevented()&&(!l._default||l._default.apply(p.pop(),c)===!1)&&M(e)&&h&&e[q]&&!n.isWindow(e)){m=e[h],m&&(e[h]=null),n.event.triggered=q;try{e[q]()}catch(s){}n.event.triggered=void 0,m&&(e[h]=m)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]","i"),va=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,wa=/\s*$/g,Aa=ca(d),Ba=Aa.appendChild(d.createElement("div"));function Ca(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function Da(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function Ea(a){var b=ya.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Fa(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Ga(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(Da(b).text=a.text,Ea(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&Z.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}}function Ha(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&xa.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(o&&(k=ja(b,a[0].ownerDocument,!1,a,d),e=k.firstChild,1===k.childNodes.length&&(k=e),e||d)){for(i=n.map(ea(k,"script"),Da),h=i.length;o>m;m++)g=k,m!==p&&(g=n.clone(g,!0,!0),h&&n.merge(i,ea(g,"script"))),c.call(a[m],g,m);if(h)for(j=i[i.length-1].ownerDocument,n.map(i,Ea),m=0;h>m;m++)g=i[m],_.test(g.type||"")&&!n._data(g,"globalEval")&&n.contains(j,g)&&(g.src?n._evalUrl&&n._evalUrl(g.src):n.globalEval((g.text||g.textContent||g.innerHTML||"").replace(za,"")));k=e=null}return a}function Ia(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(ea(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&fa(ea(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(va,"<$1>")},clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!ua.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(Ba.innerHTML=a.outerHTML,Ba.removeChild(f=Ba.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=ea(f),h=ea(a),g=0;null!=(e=h[g]);++g)d[g]&&Ga(e,d[g]);if(b)if(c)for(h=h||ea(a),d=d||ea(f),g=0;null!=(e=h[g]);g++)Fa(e,d[g]);else Fa(a,f);return d=ea(f,"script"),d.length>0&&fa(d,!i&&ea(a,"script")),d=h=e=null,f},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.attributes,m=n.event.special;null!=(d=a[h]);h++)if((b||M(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k||"undefined"==typeof d.removeAttribute?d[i]=void 0:d.removeAttribute(i),c.push(f))}}}),n.fn.extend({domManip:Ha,detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return Y(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||d).createTextNode(a))},null,a,arguments.length)},append:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(ea(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return Y(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(ta,""):void 0;if("string"==typeof a&&!wa.test(a)&&(l.htmlSerialize||!ua.test(a))&&(l.leadingWhitespace||!aa.test(a))&&!da[($.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ea(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ha(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(ea(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],f=n(a),h=f.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(f[d])[b](c),g.apply(e,c.get());return this.pushStack(e)}});var Ja,Ka={HTML:"block",BODY:"block"};function La(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function Ma(a){var b=d,c=Ka[a];return c||(c=La(a,b),"none"!==c&&c||(Ja=(Ja||n("