diff --git a/.gitignore b/.gitignore index 576b770..fcdecfe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -organic-search-analytics/config/ -*.p12 \ No newline at end of file +*.p12 +.DS_STORE \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index fdf65c0..69c54e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,43 @@ +## 2.5.0 - 2017-04-06 +### Reports +- Add page data to the report +- Convert query into a link to Google +- Chart bug fixes +- Stylized display of applied report parameters +- Linked relevant applied report parameters +- Link between relevant reports in the report table +- Added tooltips to column headings +- Correct inaccuracy in average_position calculation +- Fix Date reports with granularity of Week, Month, and Year set + +### Database updates +- Alter search_analytics table for improved data storage and analysis + - avg_position from int(11) to float, default NULL + - avg_position_click from int(11) to float + - default of null for device_type, country, and query columns + - add page column + - change database charset for wider language compatibility + - add settings table + +### Added +- Added page level data in capture from Google and reporting +- Added debug logger +- Added the config and log directories to the repository so it isn’t necessary to add it on setup + +### Changed +- Update Font Awesome to 4.7.0 +- Minor style updates throughout the site +- Installation sql script to reflect new database structure +- Upgrade script to reflect these database and file system changes + +### Fixes/Closes Github Issues +- #13 +- #16 +- #28 +- #31 +- #32 +- #35 + ## 2.4.3 - 2016-07-01 ### Bug Fix - Data Capture would not import any records for new installs (non-upgraded) of this tool. A MySQL error was thrown in the background due to a field not being available in the database. diff --git a/README.md b/README.md index 40044f3..8958844 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,15 @@ # Organic Search Analytics Importer -## Version 2.3.7 Now Available!!! (January 12th, 2016) -**Official Release Version** -> This is a highly recommended update for all users. This update fixes a bug where queries from Google that contain special characters are not being saved to the database. It is suggested that you update to this version immediately. +## Version 2.5.0 Now Available!!! (April 6th, 2017) +### New Features +- Choose which dimensions to capture in the settings +- Capture Page from Google Search Analytics +- Reporting Bug Fixes and Enhancements -> Once updated, there is a **Delete Data** option found on the home page. This page can be used to delete data that was affected by this bug. Once deleted, you can re-capture data for that date. This process ensures your data is as accurate as possible. - -## Version 2.4.0 -**Current Master Branch** -At this time, the current master branch has been updated to 2.4.0 and not commited as an official release. - -This update adds the country field, as requested in Issue #11. - -> **Notice** You will need to run an update script from the home page for this version to run smoothly as it needs to update the database. Go to the homepage of your installation, choose **Upgrade Scripts** and then choose **Run Update for Version 2.x.x to 2.4.0**. Failure to run this script will result in undesired results across the utility. - -> The update script performs a database update to add the *country* column. +> **Notice** You will need to run an update script from the home page for this version to run smoothly as it needs to update the database. Go to the homepage of your installation, choose **Upgrade Scripts** and then choose **Run Update for Version 2.x.x to 2.5.0**. Failure to run this script will result in undesired results across the utility. ## Features -Import organic search analytics from Google Search Console (Google Webmaster Tools) and Bing Search Keywords (Bing Webmaster Tools) into a local database to keep a historical, local, and combined record of your (past the 30 days that Google offers). +Import organic search analytics from Google Search Console (Google Webmaster Tools) and Bing Search Keywords (Bing Webmaster Tools) into a local database to keep a historical, local, and combined record of your (past the 90 days that Google offers). This archive of organic search analytics will allow you to study long term SEO trends and shifts and can help to monitor and gauge performance of a websites over time. diff --git a/organic-search-analytics.sql b/organic-search-analytics.sql index c2a2789..78e207e 100644 --- a/organic-search-analytics.sql +++ b/organic-search-analytics.sql @@ -33,7 +33,7 @@ CREATE TABLE IF NOT EXISTS `report_saved` ( `category` int(11) NOT NULL, `paramaters` varchar(1000) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=0 ; +) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0 ; -- -------------------------------------------------------- @@ -46,7 +46,7 @@ CREATE TABLE IF NOT EXISTS `report_saved_categories` ( `name` varchar(256) NOT NULL, `description` varchar(1000) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=0 ; +) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0 ; -- -------------------------------------------------------- @@ -60,16 +60,17 @@ CREATE TABLE IF NOT EXISTS `search_analytics` ( `date` date NOT NULL, `search_engine` varchar(50) NOT NULL, `search_type` varchar(24) NOT NULL, - `device_type` varchar(24) NOT NULL, - `country` varchar(10) NULL, - `query` varchar(500) NOT NULL, + `device_type` varchar(24) NULL DEFAULT NULL, + `country` varchar(10) NULL DEFAULT NULL, + `query` varchar(500) NULL DEFAULT NULL, + `page` VARCHAR(500) NULL DEFAULT NULL, `impressions` int(11) NOT NULL, `clicks` int(11) NOT NULL, `ctr` float NOT NULL, - `avg_position` int(11) NOT NULL, - `avg_position_click` int(11) NULL, + `avg_position` float NOT NULL, + `avg_position_click` float NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=0 ; +) ENGINE=MyISAM DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0 ; -- -------------------------------------------------------- @@ -83,7 +84,15 @@ CREATE TABLE IF NOT EXISTS `settings` ( `value` varchar(256) NOT NULL, `data` varchar(500) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=0 ; +) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0 ; + +INSERT INTO `settings` + (type, value, data) +VALUES + ('settings', 'google_search_console_dimensions_query', 'On'), + ('settings', 'google_search_console_dimensions_page', 'Off'), + ('settings', 'google_search_console_dimensions_device', 'On'), + ('settings', 'google_search_console_dimensions_country', 'On') ; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; diff --git a/organic-search-analytics/config/.gitignore b/organic-search-analytics/config/.gitignore new file mode 100644 index 0000000..e7a210e --- /dev/null +++ b/organic-search-analytics/config/.gitignore @@ -0,0 +1,3 @@ +* +*/ +!.gitignore \ No newline at end of file diff --git a/organic-search-analytics/css/lib/font-awesome/font-awesome.min.css b/organic-search-analytics/css/lib/font-awesome/font-awesome.min.css index 951674f..0f5b8b8 100644 --- a/organic-search-analytics/css/lib/font-awesome/font-awesome.min.css +++ b/organic-search-analytics/css/lib/font-awesome/font-awesome.min.css @@ -1,4 +1,4 @@ /*! - * Font Awesome 4.4.0 by @davegandy - http://fontawesome.io - @fontawesome + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../../../fonts/fontawesome-webfont.eot?v=4.4.0');src:url('../../../fonts/fontawesome-webfont.eot?#iefix&v=4.4.0') format('embedded-opentype'),url('../../../fonts/fontawesome-webfont.woff2?v=4.4.0') format('woff2'),url('../../../fonts/fontawesome-webfont.woff?v=4.4.0') format('woff'),url('../../../fonts/fontawesome-webfont.ttf?v=4.4.0') format('truetype'),url('../../../fonts/fontawesome-webfont.svg?v=4.4.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"} + */@font-face{font-family:'FontAwesome';src:url('../../../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../../../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../../../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../../../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../../../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../../../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/organic-search-analytics/css/styles.css b/organic-search-analytics/css/styles.css index 2695f2e..c9ae1ec 100644 --- a/organic-search-analytics/css/styles.css +++ b/organic-search-analytics/css/styles.css @@ -49,8 +49,6 @@ header, header a { color: #FFFFFF; } .donate { display: inline-block; } .donate form { margin: 0; } - - .serverResponse { border-color: black; border-style:solid; @@ -93,6 +91,8 @@ header, header a { color: #FFFFFF; } margin: .2%; border: none; } +a.button { text-decoration: none; } +a.button > .fa { font-size: .8em; } input.button { font-size: 16px; padding: 1% 1.5%; @@ -100,6 +100,8 @@ input.button { #report-custom .report-parameter-group .groupLabel { font-weight: bold; margin: 0; } +.fa.reportLinkExt { margin-left: 1%; text-decoration: none; } + .filelist a { margin-bottom: 1%; display: block; @@ -149,9 +151,6 @@ table.sidebysidetable td { padding-right: 5px; } - - - .sort { padding: 0 2px; color: #AEC1D2; @@ -176,11 +175,33 @@ table.sidebysidetable td { } .sort_active { color: #F9FF00; } +.reportTooltip > span:after { + content: '\f29c'; + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration:none; + cursor: pointer; + display: inline-block; +} - - - - +#reportParameters { + border: 1px solid black; + margin: 2% 0; + padding: 1%; +} +#reportParametersHeading { + margin: 0 0 1%; +} +#reportParameters div { + display: inline-block; + width: 30%; + word-wrap: break-word; + margin: 0 2% .5% 0; +} +#reportParameters div span { + font-weight: bold; +} #reportChartContainer { padding-bottom: 70px; } @@ -192,7 +213,6 @@ table.sidebysidetable td { text-decoration: none; } - .col { float:left; } .col40 { width: 40%; } .col45 { width: 45%; } @@ -209,75 +229,74 @@ table.sidebysidetable td { .clear { clear:both; } - footer { margin-top: 50px; padding: 20px 20px 15px; background-color:#DDDDDD; } - /* Alert Box */ .alert { margin-top: .5%; padding: .5%; } .alert a, .alert a:hover, .alert a:visited, .alert a:active { color: inherit; } #siteContent div.alert.warning { - background-color: #F00; - color: #FF0; + background-color: #F00; + color: #FF0; } #siteContent div.alert.success { - background-color: #008813; - color: #FFF; + background-color: #008813; + color: #FFF; } - - /* Settings Page */ .site_settings_heading > div, .site_settings_row > div { - display: inline-block; + display: inline-block; } .site_settings_heading .site_settings_label, .site_settings_row .site_settings_label { - width: 350px; + width: 350px; } .site_settings_heading .site_settings_label { - margin-left: 10px; + margin-left: 10px; } .site_settings_heading { - background-color: #5C7CC3; - color: white; - height: 80px; + background-color: #5C7CC3; + color: white; + padding: 1% .5%; } .site_settings_heading > div span { display: inline-block; - margin-top: 10px; } .site_settings_row .site_settings_google, .site_settings_heading .site_settings_google, .site_settings_row .site_settings_bing, .site_settings_heading .site_settings_bing { - width: 100px; - text-align: center; + width: 100px; + text-align: center; } .site_settings_row:nth-child(odd) { - background-color: #EAEAEA; + background-color: #EAEAEA; } .site_settings_row { - padding: .5% 0; + padding: .5% 0; +} +.site_settings_row > div { + margin-left: 1%; } .inputButton { - border: none; - font-size: 1em; - margin-top: 1%; - padding: .5% .8%; - cursor: pointer; + border: none; + font-size: 1em; + margin-top: 1%; + padding: .5% .8%; + cursor: pointer; } .inputButtonSave { - background-color: green; - color: white; + background-color: green; + color: white; } #upgradeVersion { margin-left: 5px; color: #FF5400; } +.settings-block { margin-left: 2%; } /* Reporting */ @@ -286,12 +305,12 @@ footer { margin-top: 50px; padding: 20px 20px 15px; background-color:#DDDDDD; } /* #page_report .col h2 ~ div { color: red; } */ #page_report .col h2:after { - content: "\f078"; - font-family: FontAwesome; - display: inline-block; - text-align: center; - cursor: pointer; - margin-left: 2%; + content: "\f078"; + font-family: FontAwesome; + display: inline-block; + text-align: center; + cursor: pointer; + margin-left: 2%; } .expandable > h2 { @@ -314,20 +333,10 @@ footer { margin-top: 50px; padding: 20px 20px 15px; background-color:#DDDDDD; } border-color: #333; } - - - - - - - - .taL { text-align: left; } .taR { text-align: right; } .taC { text-align: center; } - - /* Spacing | START */ .m0 { margin: 0; } .mT0 { margin-top: 0; } @@ -406,12 +415,10 @@ footer { margin-top: 50px; padding: 20px 20px 15px; background-color:#DDDDDD; } .mB4p { margin-bottom: 4%; } .mB5p { margin-bottom: 5%; } - .p_5p { padding: 0.5%; } .p1p { padding: 1%; } .p2p { padding: 2%; } - .pL1p { padding-left: 1%; } .pL2p { padding-left: 2%; } .pL3p { padding-left: 3%; } @@ -448,7 +455,6 @@ footer { margin-top: 50px; padding: 20px 20px 15px; background-color:#DDDDDD; } .pB9p { padding-bottom: 9%; } .pB10p { padding-bottom: 10%; } - .pR1px { padding-right: 1px; } .pR2px { padding-right: 2px; } .pR3px { padding-right: 3px; } @@ -466,7 +472,6 @@ footer { margin-top: 50px; padding: 20px 20px 15px; background-color:#DDDDDD; } .pT9px { padding-top: 9px; } .pT10px { padding-top: 10px; } - .pB1px { padding-bottom: 1px; } .pB2px { padding-bottom: 2px; } .pB3px { padding-bottom: 3px; } @@ -479,5 +484,4 @@ footer { margin-top: 50px; padding: 20px 20px 15px; background-color:#DDDDDD; } .pB10px { padding-bottom: 10px; } /* Spacing | END */ - .ui-tooltip.ui-widget.tooltips { font-size: .8em; font-weight: normal; } \ No newline at end of file diff --git a/organic-search-analytics/fonts/FontAwesome.otf b/organic-search-analytics/fonts/FontAwesome.otf index 681bdd4..401ec0f 100644 Binary files a/organic-search-analytics/fonts/FontAwesome.otf and b/organic-search-analytics/fonts/FontAwesome.otf differ diff --git a/organic-search-analytics/fonts/fontawesome-webfont.eot b/organic-search-analytics/fonts/fontawesome-webfont.eot index a30335d..e9f60ca 100644 Binary files a/organic-search-analytics/fonts/fontawesome-webfont.eot and b/organic-search-analytics/fonts/fontawesome-webfont.eot differ diff --git a/organic-search-analytics/fonts/fontawesome-webfont.svg b/organic-search-analytics/fonts/fontawesome-webfont.svg index 6fd19ab..855c845 100644 --- a/organic-search-analytics/fonts/fontawesome-webfont.svg +++ b/organic-search-analytics/fonts/fontawesome-webfont.svg @@ -1,640 +1,2671 @@ - - + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/organic-search-analytics/fonts/fontawesome-webfont.ttf b/organic-search-analytics/fonts/fontawesome-webfont.ttf index d7994e1..35acda2 100644 Binary files a/organic-search-analytics/fonts/fontawesome-webfont.ttf and b/organic-search-analytics/fonts/fontawesome-webfont.ttf differ diff --git a/organic-search-analytics/fonts/fontawesome-webfont.woff b/organic-search-analytics/fonts/fontawesome-webfont.woff index 6fd4ede..400014a 100644 Binary files a/organic-search-analytics/fonts/fontawesome-webfont.woff and b/organic-search-analytics/fonts/fontawesome-webfont.woff differ diff --git a/organic-search-analytics/fonts/fontawesome-webfont.woff2 b/organic-search-analytics/fonts/fontawesome-webfont.woff2 index 5560193..4d13fc6 100644 Binary files a/organic-search-analytics/fonts/fontawesome-webfont.woff2 and b/organic-search-analytics/fonts/fontawesome-webfont.woff2 differ diff --git a/organic-search-analytics/inc/code/core.php b/organic-search-analytics/inc/code/core.php index 729f84e..56221c6 100644 --- a/organic-search-analytics/inc/code/core.php +++ b/organic-search-analytics/inc/code/core.php @@ -2,7 +2,7 @@ /** * PHP class for core functions * - * Copyright 2015 PromInc Productions. All Rights Reserved. + * Copyright 2017 PromInc Productions. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,21 @@ class Core { + + const ENABLED = 1; + const DISABLED = 0; + + const WARNING = "WARNING"; + const ERROR = "ERROR"; + const INFO = "INFO"; + const DEBUG = "DEBUG"; + + const NEWLINE = "\n"; + const TAB = "\t"; + + const DS = "/"; + + /** * Connect to MySQL * @@ -101,6 +116,7 @@ public function getNumDays( $start, $end, $include_end_day = true) { return $num_days; } + /** * Get the current date/time * diff --git a/organic-search-analytics/inc/code/dataCapture.php b/organic-search-analytics/inc/code/dataCapture.php index b79f4b3..0e62c5d 100644 --- a/organic-search-analytics/inc/code/dataCapture.php +++ b/organic-search-analytics/inc/code/dataCapture.php @@ -2,7 +2,7 @@ /** * PHP class for capturing data from API services * - * Copyright 2015 PromInc Productions. All Rights Reserved. + * Copyright 2017 PromInc Productions. All Rights Reserved. * * @author: Brian Prom * @link: http://promincproductions.com/blog/brian/ @@ -12,25 +12,59 @@ class DataCapture { + const GOOGLE_SEARCH_ANALYTICS_MAX_DATE_OFFSET = 4; const GOOGLE_SEARCH_ANALYTICS_MAX_DAYS = 90; + public $core; public $mysql; - + public $dimensions; + + function __construct() { $this->core = new Core(); //Load core $this->mysql = new MySQL(); //Load MySQL } + + /** + * Get the list of dimensions to capture as defined in the settings page + * + * @returns String Comma separated list of dimensions + */ + public function getDimensions() { + if( !$this->dimensions ) { + $siteSettings = $this->mysql->getSettings("settings"); + $dimensions = array(); + foreach( $siteSettings as $key => $value ) { + if( substr( $key, 0, 32 ) == "google_search_console_dimensions" && $value == "On" ) { + $dimensions[] = substr($key, 33 ); + } + } + + uasort($dimensions, function($a, $b) { + static $sizes = array('query' => 0, 'page' => 1, 'device' => 2, 'country' => 3); + return $sizes[strtolower($a)] - $sizes[strtolower($b)]; + }); + + $this->dimensions = array_values($dimensions); + } + return $this->dimensions; + } + + /** * Default settings for Google Search Analytics */ - private $defaultGoogleSearchAnalyticsSettings = array( + private function defaultGoogleSearchAnalyticsSettings() { + return array( 'mode' => 'import', /* What to do with the data. Valid options: import, return */ - 'dimensions' => array('query','device','country'), + 'dimensions' => $this->getDimensions(), 'row_limit' => 5000 /* Number of rows to capture from Google. Valid options: 1-5000 */ - ); + ); + } + /** * Get authorized sites from Google Search Console @@ -166,7 +200,7 @@ public function checkNeededDataGoogleSearchAnalytics($website) { * @returns Integer,array Number of records found or var_dump of returned data from Google depending on mode */ public function downloadGoogleSearchAnalytics( $website, $date, $overrides = array() ) { - $params = array_merge( $this->defaultGoogleSearchAnalyticsSettings, $overrides ); + $params = array_merge( $this->defaultGoogleSearchAnalyticsSettings(), $overrides ); $importCount = 0; @@ -220,6 +254,8 @@ public function downloadGoogleSearchAnalytics( $website, $date, $overrides = arr $searchAnalyticsRequest->setAggregationType( $params['aggregation_type'] ); } + $dimensionMap = array_flip( $this->getDimensions() ); + /* Loop through each of the search types */ foreach( $searchTypes as $searchType ) { /* Set search type in Search Analytics Request */ @@ -233,7 +269,7 @@ public function downloadGoogleSearchAnalytics( $website, $date, $overrides = arr switch( $params['mode'] ) { case 'import': $wmtimport = new WMTimport(); - $importCount += $wmtimport->importGoogleSearchAnalytics( $website, $date, $searchType, $searchAnalyticsResponse ); + $importCount += $wmtimport->importGoogleSearchAnalytics( $website, $date, $searchType, $searchAnalyticsResponse, $dimensionMap ); break; case 'return': var_dump( $searchAnalyticsResponse ); diff --git a/organic-search-analytics/inc/code/debugLogger.php b/organic-search-analytics/inc/code/debugLogger.php new file mode 100644 index 0000000..9440aee --- /dev/null +++ b/organic-search-analytics/inc/code/debugLogger.php @@ -0,0 +1,72 @@ + + * @link: http://promincproductions.com/blog/brian/ + */ + + class DebugLogger + { + + + const LOG_DIR_DEFAULT = "log"; + const LOG_FILE_DEFAULT = "general.log"; + + + /** + * Log message to file + * + * @param message + * @param level + * @param dir + * @param file + */ + public function debugLog($message, $level, $dir = self::LOG_DIR_DEFAULT, $file = self::LOG_FILE_DEFAULT) { + error_log( + $this->makeLogMessage($message,$level=Core::DEBUG), + 3, + $dir.Core::DS.$file + ); + } + + + /** + * Generate log message + * + * @param message + * @param level + * + * @returns String Date Level Message File Line, + */ + public function makeLogMessage($message = "", $level = Core::DEBUG) { + $trace = debug_backtrace(); + return date('c'). + Core::TAB. + $level. + Core::TAB. + $message. + Core::TAB. + "in ".$trace[0]['file']. + " line ".$trace[0]['line']. + Core::NEWLINE + ; + } + + + } +?> \ No newline at end of file diff --git a/organic-search-analytics/inc/code/gapiOauth.php b/organic-search-analytics/inc/code/gapiOauth.php index 1747512..69ab844 100644 --- a/organic-search-analytics/inc/code/gapiOauth.php +++ b/organic-search-analytics/inc/code/gapiOauth.php @@ -2,7 +2,7 @@ /** * PHP class for oAuth 2.0 connection to Google Search Console * - * Copyright 2015 PromInc Productions. All Rights Reserved. + * Copyright 2017 PromInc Productions. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/organic-search-analytics/inc/code/globalIncludes.php b/organic-search-analytics/inc/code/globalIncludes.php index 3450f40..1335430 100644 --- a/organic-search-analytics/inc/code/globalIncludes.php +++ b/organic-search-analytics/inc/code/globalIncludes.php @@ -1,9 +1,10 @@ "warning", "message"=>"Go to the Settings Configuration page and click the Save button."); + } + include_once( $GLOBALS['basedir'].'inc/code/mysql.php' ); //Database Connection include_once( $GLOBALS['basedir'].'inc/code/gapiOauth.php' ); //Google API Oauth include_once( $GLOBALS['basedir'].'inc/code/wmtimport.php' ); //WMT CSV import functions @@ -22,7 +34,6 @@ include_once( $GLOBALS['basedir'].'apis/Bing/Webmasters.php' ); //Bing Search API /* Load classes */ - $core = new Core(); //Load core $mysql = new MySQL(); //Load MySQL $dataCapture = new DataCapture(); //Load Data Capturing tools diff --git a/organic-search-analytics/inc/code/reports.php b/organic-search-analytics/inc/code/reports.php index 2012865..861f6c1 100644 --- a/organic-search-analytics/inc/code/reports.php +++ b/organic-search-analytics/inc/code/reports.php @@ -23,12 +23,15 @@ class Reports { + public $core; + function __construct() { $this->core = new Core(); //Load core } + /** * Import array of Bing Search Keywords to database * @@ -90,7 +93,6 @@ public function saveReport($domain, $name, $category, $params) { /* Send Query */ $saveReport = MySQL::qryDBinsert( MySQL::DB_TABLE_SAVED_REPORTS, $valueString ); - // var_dump( $GLOBALS['db'] ); /* Return query request status */ return $saveReport; @@ -228,9 +230,14 @@ public function getReportQueryAndHeading( $reportParams ) { $whereClause = $return['chartLabel'] = ""; $return['whereClauseItemsTable'] = $return['pageHeadingItems'] = []; + + if( isset( $reportParams['groupBy'] ) ) { + $return['pageHeadingItems'][] = "Report Type: " . ucfirst($reportParams['groupBy']); + } + if( isset( $reportParams['domain'] ) && $reportParams['domain'] > "" ) { $return['whereClauseItemsTable'][] = "domain = '" . $reportParams['domain'] . "'"; - $return['pageHeadingItems'][] = "Domain: " . $reportParams['domain']; + $return['pageHeadingItems'][] = "Domain: " . $reportParams['domain'] . ""; } if( isset( $reportParams['query'] ) && $reportParams['query'] > "" ) { switch( $reportParams['queryMatch'] ) { @@ -242,20 +249,43 @@ public function getReportQueryAndHeading( $reportParams ) { $return['whereClauseItemsTable'][] = "query = '" . $reportParams['query'] . "'"; break; } - $return['pageHeadingItems'][] = "Query: " . $reportParams['query'] . (isset($reportParams['queryMatch'])?" (".$reportParams['queryMatch'].")":""); + $return['pageHeadingItems'][] = "Query: " . $reportParams['query'] . "" . (isset($reportParams['queryMatch'])?" (".$reportParams['queryMatch'].")":""); $return['chartLabel'] = $reportParams['query'] . (isset($reportParams['queryMatch'])?" (".$reportParams['queryMatch'].")":""); } + if( isset( $reportParams['page'] ) && $reportParams['page'] > "" ) { + switch( $reportParams['pageMatch'] ) { + case "broad": + default: + $return['whereClauseItemsTable'][] = "page LIKE '%" . $reportParams['page'] . "%'"; + break; + case "exact": + $return['whereClauseItemsTable'][] = "page = '" . $reportParams['page'] . "'"; + break; + } + + $pageHeading_page = "Page: "; + if( isset($reportParams['pageMatch']) && $reportParams['pageMatch'] == "exact" ) { + $pageHeading_page .= ''; + } + $pageHeading_page .= $reportParams['page']; + if( isset($reportParams['pageMatch']) && $reportParams['pageMatch'] == "exact" ) { + $pageHeading_page .= ''; + } + $pageHeading_page .= (isset($reportParams['pageMatch'])?" (".$reportParams['pageMatch'].")":""); + $return['pageHeadingItems'][] = $pageHeading_page; + $return['chartLabel'] = $reportParams['page'] . (isset($reportParams['pageMatch'])?" (".$reportParams['pageMatch'].")":""); + } if( isset( $reportParams['search_type'] ) && $reportParams['search_type'] > "" ) { if( $reportParams['search_type'] != "ALL" ) { $return['whereClauseItemsTable'][] = "search_type = '" . $reportParams['search_type'] . "'"; } - $return['pageHeadingItems'][] = "Search Type: " . $reportParams['search_type']; + $return['pageHeadingItems'][] = "Search Type: " . $reportParams['search_type']; } if( isset( $reportParams['device_type'] ) && $reportParams['device_type'] > "" ) { if( $reportParams['device_type'] != "ALL" ) { $return['whereClauseItemsTable'][] = "device_type = '" . $reportParams['device_type'] . "'"; } - $return['pageHeadingItems'][] = "Device Type: " . $reportParams['device_type']; + $return['pageHeadingItems'][] = "Device Type: " . $reportParams['device_type']; } /* Country */ @@ -263,17 +293,17 @@ public function getReportQueryAndHeading( $reportParams ) { if( $reportParams['country'] != "ALL" ) { $return['whereClauseItemsTable'][] = "country = '" . $reportParams['country'] . "'"; } - $return['pageHeadingItems'][] = "Country: " . strtoupper( $reportParams['country'] ); + $return['pageHeadingItems'][] = "Country: " . strtoupper( $reportParams['country'] ); } if( isset( $reportParams['date_start'] ) && $reportParams['date_start'] > 0 && $reportParams['date_type'] == 'hard_set' ) { if( isset( $reportParams['date_end'] ) && $reportParams['date_end'] > 0 ) { $return['whereClauseItemsTable'][] = "date >= '" . $reportParams['date_start'] . "' AND date <= '" . $reportParams['date_end'] . "'"; $num_days = $this->core->getNumDays( $reportParams['date_start'], $reportParams['date_end'] ); - $return['pageHeadingItems'][] = "Dates: " . $reportParams['date_start'] . " to " . $reportParams['date_end'] . " (" . $num_days . " day" . ( $num_days > 1 ? "s" : "" ) . ")"; + $return['pageHeadingItems'][] = "Dates: " . $reportParams['date_start'] . " to " . $reportParams['date_end'] . " (" . $num_days . " day" . ( $num_days > 1 ? "s" : "" ) . ")"; } else { $return['whereClauseItemsTable'][] = "date = '" . $reportParams['date_start'] . "'"; - $return['pageHeadingItems'][] = "Date: " . $reportParams['date_start']; + $return['pageHeadingItems'][] = "Date: " . $reportParams['date_start']; } } elseif( isset( $reportParams['date_type'] ) && $reportParams['date_type'] != 'hard_set' ) { $queryMaxDate = "SELECT max(date) as 'max' FROM `".MySQL::DB_TABLE_SEARCH_ANALYTICS."` WHERE 1"; @@ -284,25 +314,43 @@ public function getReportQueryAndHeading( $reportParams ) { $dateStart = date('Y-m-d', strtotime('-'.($dateStartOffset-1).' days', strtotime( $dateEnd ) ) ); $return['whereClauseItemsTable'][] = "date >= '" . $dateStart . "' AND date <= '" . $dateEnd . "'"; - $return['pageHeadingItems'][] = "Dates: Past " . $dateStartOffset . " days (" . $dateStart . " to " . $dateEnd . ")"; + $return['pageHeadingItems'][] = "Dates: Past " . $dateStartOffset . " days (" . $dateStart . " to " . $dateEnd . ")"; } } $return['whereClauseTable'] = " WHERE " . implode( " AND ", $return['whereClauseItemsTable'] ) . " "; - if( isset( $reportParams['sortDir'] ) ) { $return['sortDir'] = $reportParams['sortDir']; } else { $return['sortDir'] = 'asc'; } - if( isset( $reportParams['sortBy'] ) ) { $return['sortBy'] = $reportParams['sortBy']; } else { $return['sortBy'] = 'date'; } - - $groupByDate = 'date'; - if( isset( $reportParams['granularity'] ) && $reportParams['granularity'] != 'day' ) { - $return['groupBy'] = strtoupper( $reportParams['granularity'] ) . '(' . $groupByDate . ')'; - $return['pageHeadingItems'][] = "Granularity: " . $reportParams['granularity']; + if( isset( $reportParams['sortDir'] ) ) { + $return['sortDir'] = $reportParams['sortDir']; } else { - $return['groupBy'] = $groupByDate; + $return['sortDir'] = 'asc'; + } + if( isset( $reportParams['sortBy'] ) ) { + $return['sortBy'] = $reportParams['sortBy']; + } else { + $return['sortBy'] = 'date'; } - if( isset( $reportParams['groupBy'] ) && $reportParams['groupBy'] == "query" ) { - // $return['groupBy'] = $return['sortBy'] = "query"; - $return['groupBy'] = "query"; + if( isset( $reportParams['groupBy'] ) ) { + if( $reportParams['groupBy'] == "date" ) { + if( isset( $reportParams['granularity'] ) && $reportParams['granularity'] != 'day' ) { + $return['granularity'] = $reportParams['granularity']; + $return['groupByAlias'] = 'date'; + if( $reportParams['granularity'] == 'month' ) { + $return['groupBy'] = 'DATE_FORMAT(date, "%Y-%m")'; + } elseif( $reportParams['granularity'] == 'week' ) { + $return['groupBy'] = 'DATE_FORMAT(DATE_ADD(date, INTERVAL(1-DAYOFWEEK(date)) DAY),"%Y-%m-%d")'; + } else { + $return['groupBy'] = strtoupper( $reportParams['granularity'] ) . '(date)'; + } + $return['pageHeadingItems'][] = "Granularity: " . ucfirst( $reportParams['granularity'] ); + } else { + $return['groupBy'] = $return['groupByAlias'] = 'date'; + } + } elseif( $reportParams['groupBy'] == "query" ) { + $return['groupBy'] = $return['groupByAlias'] = "query"; + } elseif( $reportParams['groupBy'] == "page" ) { + $return['groupBy'] = $return['groupByAlias'] = "page"; + } } } return $return; diff --git a/organic-search-analytics/inc/code/wmtimport.php b/organic-search-analytics/inc/code/wmtimport.php index dc914ab..7d712a8 100644 --- a/organic-search-analytics/inc/code/wmtimport.php +++ b/organic-search-analytics/inc/code/wmtimport.php @@ -13,6 +13,16 @@ class WMTimport { + public $debug; + + + function __construct() { + if( config::DEBUG_LOGGER == Core::ENABLED ) { + $this->debug = new DebugLogger(); //Load Debugging Logger + } + } + + /** * Break apart the filename to return the data pieces * @@ -43,7 +53,6 @@ public function getDataFromReportName($fileName) } return $return; - } @@ -57,20 +66,25 @@ public function getDataFromReportName($fileName) * * @returns Int Count of records imported */ - public function importGoogleSearchAnalytics($domain, $date, $searchType, $searchAnalytics) { + public function importGoogleSearchAnalytics($domain, $date, $searchType, $searchAnalytics, $dimensionMap) { $countImport = 0; foreach( $searchAnalytics->rows as $recordKey => $recordData ) { /* Prep data */ $domain = addslashes( $domain ); $searchType = addslashes( $searchType ); - $deviceType = addslashes( strtolower( $recordData['keys'][1] ) ); - $country = addslashes( strtolower( $recordData['keys'][2] ) ); - $query = addslashes( $recordData['keys'][0] ); + $query = ( isset( $dimensionMap['query'] ) ? addslashes( $recordData['keys'][$dimensionMap['query']] ) : NULL ); + $page = ( isset( $dimensionMap['page'] ) ? addslashes( $recordData['keys'][$dimensionMap['page']] ) : NULL ); + $deviceType = ( isset( $dimensionMap['device'] ) ? addslashes( strtolower( $recordData['keys'][$dimensionMap['device']] ) ) : NULL ); + $country = ( isset( $dimensionMap['country'] ) ? addslashes( strtolower( $recordData['keys'][$dimensionMap['country']] ) ) : NULL ); - $import = "INSERT into ".MySQL::DB_TABLE_SEARCH_ANALYTICS."(domain, date, search_engine, search_type, device_type, country, query, impressions, clicks, ctr, avg_position) values('$domain', '$date', 'google', '$searchType', '$deviceType', '$country', '{$query}','{$recordData['impressions']}','{$recordData['clicks']}','{$recordData['ctr']}','{$recordData['position']}')"; + $import = "INSERT into ".MySQL::DB_TABLE_SEARCH_ANALYTICS."(domain, date, search_engine, search_type, device_type, country, query, page, impressions, clicks, ctr, avg_position) values('$domain', '$date', 'google', '$searchType', '$deviceType', '$country', '{$query}', '{$page}', '{$recordData['impressions']}', '{$recordData['clicks']}', '{$recordData['ctr']}', '{$recordData['position']}')"; if( $GLOBALS['db']->query($import) ) { $countImport++; + } else { + if( config::DEBUG_LOGGER == Core::ENABLED ) { + $this->debug->debugLog($GLOBALS['db']->error,Core::ERROR); + } } } return $countImport; @@ -88,7 +102,7 @@ public function importGoogleSearchAnalytics($domain, $date, $searchType, $search public function importBingSearchKeywords($domain, $searchKeywords) { $searchKeywords = json_decode($searchKeywords); $countImport = 0; - + /* Check for prior import in DB */ $lastImported = "SELECT MAX(date) AS 'lastImported' FROM ".MySQL::DB_TABLE_SEARCH_ANALYTICS." WHERE domain = '".$domain."' AND search_engine = 'bing'"; if( $lastImportedResult = $GLOBALS['db']->query($lastImported) ) { @@ -106,6 +120,10 @@ public function importBingSearchKeywords($domain, $searchKeywords) { if( $GLOBALS['db']->query($import) ) { $countImport++; + } else { + if( config::DEBUG_LOGGER == Core::ENABLED ) { + $this->debug->debugLog($GLOBALS['db']->error,Core::ERROR); + } } } } diff --git a/organic-search-analytics/inc/html/_foot.php b/organic-search-analytics/inc/html/_foot.php index 35fc746..0665e58 100644 --- a/organic-search-analytics/inc/html/_foot.php +++ b/organic-search-analytics/inc/html/_foot.php @@ -11,13 +11,13 @@ Developed by Brian Prom
- + ver
-
Group By: > > + >
> @@ -228,15 +232,25 @@
Sort By: - - >> - - >> - > - > - > - > - > + + + + + + + + + + + + + + + + > + > + > + >
diff --git a/organic-search-analytics/js/report.js b/organic-search-analytics/js/report.js index 02cc90c..6c05400 100644 --- a/organic-search-analytics/js/report.js +++ b/organic-search-analytics/js/report.js @@ -37,33 +37,42 @@ function ajaxScript(catId, script, domain, date, callback) { * Hides granularity when date is not the group by method * Displays the appropriate sortBy features */ +var groupBySortSettings = { + groupByDate: { + defaultSortBy: "sortByDate", + disable: ["sortByQuery","sortByPage"], + hideGranularity: false + }, + groupByQuery: { + defaultSortBy: "sortByQuery", + disable: ["sortByDate","sortByQueries","sortByPage"], + hideGranularity: true + }, + groupByPage: { + defaultSortBy: "sortByPage", + disable: ["sortByDate","sortByQuery","sortByPages"], + hideGranularity: true + } +}; jQuery("#report-custom input:radio[name=groupBy]").change(function(e){ - if( e.target.id == "groupByQuery" ) { - jQuery( "#paramGroup_granularity" ).hide(); - - var checked_status = jQuery( "#sortByDate" ).prop("checked"); - - jQuery( "#sortByDate" ).parent("span").hide(); - jQuery( "#sortByDate" ).attr("disabled",true).prop("checked",false); - - jQuery( "#sortByQuery" ).parent("span").show(); - jQuery( "#sortByQuery" ).attr("disabled",false); - if( checked_status ) { - jQuery( "#sortByQuery" ).prop("checked",true); - } - } else { + // Toggle granularity + if( !groupBySortSettings[e.target.id]['hideGranularity'] ) { jQuery( "#paramGroup_granularity" ).show(); + } else { + jQuery( "#paramGroup_granularity" ).hide(); + } - var checked_status = jQuery( "#sortByQuery" ).prop("checked"); - - jQuery( "#sortByQuery" ).parent("span").hide(); - jQuery( "#sortByQuery" ).attr("disabled",true).prop("checked",false); + // Disable non-applicable sort by options + jQuery("#paramGroup_sortBy .sortByOption").show(); + jQuery("input[name=sortBy]").attr("disabled",false); + for( disableOption in groupBySortSettings[e.target.id]['disable'] ) { + jQuery("#"+groupBySortSettings[e.target.id]['disable'][disableOption]).parent("span.sortByOption").hide(); + jQuery("#"+groupBySortSettings[e.target.id]['disable'][disableOption]).attr("disabled",true).prop("checked",false); + } - jQuery( "#sortByDate" ).parent("span").show(); - jQuery( "#sortByDate" ).attr("disabled",false); - if( checked_status ) { - jQuery( "#sortByDate" ).prop("checked",true); - } + // Set default option if an option is not set + if( !jQuery('input[name=sortBy]').is(':checked') || jQuery("#"+jQuery('input[name=sortBy]:checked').attr("id")).attr("disabled") == "disabled" ) { + jQuery( "#"+groupBySortSettings[e.target.id]["defaultSortBy"] ).prop("checked",true); } }); diff --git a/organic-search-analytics/log/.gitignore b/organic-search-analytics/log/.gitignore new file mode 100644 index 0000000..e7a210e --- /dev/null +++ b/organic-search-analytics/log/.gitignore @@ -0,0 +1,3 @@ +* +*/ +!.gitignore \ No newline at end of file diff --git a/organic-search-analytics/report.php b/organic-search-analytics/report.php index 365c7d2..1f7c564 100644 --- a/organic-search-analytics/report.php +++ b/organic-search-analytics/report.php @@ -22,9 +22,11 @@ getReportQueryAndHeading( $reportParams ); $groupBy = $reportDetails['groupBy']; + $groupByAlias = $reportDetails['groupByAlias']; } ?> @@ -37,8 +39,14 @@
-

+
+

Report Parameters

+
", $reportDetails['pageHeadingItems'] ); ?>
+
+
0 ) { /* Put MySQL Results into an array */ - $totals = array( 'rows' => 0, 'queries' => 0, 'impressions' => 0, 'clicks' => 0, 'avg_position' => 0, 'avg_ctr' => 0 ); + $totals = array( 'rows' => 0, 'queries' => 0, 'pages' => 0, 'impressions' => 0, 'clicks' => 0, 'avg_position' => 0, 'avg_ctr' => 0 ); $rows = array(); for( $r=0; $r < count($outputTable); $r++ ) { - $rows[ $outputTable[$r][$groupBy] ] = array( "queries" => $outputTable[$r]["queries"], "impressions" => $outputTable[$r]["impressions"], "clicks" => $outputTable[$r]["clicks"], "avg_position" => $outputTable[$r]["avg_position"] ); + $rows[ $outputTable[$r][$groupBy] ] = array( "queries" => $outputTable[$r]["queries"], "pages" => $outputTable[$r]["pages"], "impressions" => $outputTable[$r]["impressions"], "clicks" => $outputTable[$r]["clicks"], "avg_position" => $outputTable[$r]["avg_position"] ); /* Add to totals */ $totals['queries'] += $outputTable[$r]["queries"]; + $totals['pages'] += $outputTable[$r]["pages"]; $totals['impressions'] += $outputTable[$r]["impressions"]; $totals['clicks'] += $outputTable[$r]["clicks"]; $totals['avg_position'] += $outputTable[$r]["avg_position"]; } + /* Calculate averages */ $totals['avg_position'] = number_format( $totals['avg_position'] / count($outputTable), 2 ); $totals['avg_ctr'] = number_format( ( $totals["clicks"] / $totals["impressions"] ) * 100, 2 )."%"; + /* Format numbers */ + /* + TODO: The totals really should be a separate query for more accurate/useful data. + i.e. On a Date report with Year granularity, you might get 50 queries from year 1 and 47 from year 2. These get added together to be 97. But this doesn't account for any overlap in the two years. There may really only be 52 unique queries as an example. + */ $totals['rows'] = number_format( count($outputTable), 0 ); $totals['queries'] = number_format( $totals['queries'], 0 ); + $totals['pages'] = number_format( $totals['pages'], 0 ); $totals['impressions'] = number_format( $totals['impressions'], 0 ); $totals['clicks'] = number_format( $totals['clicks'], 0 ); /* Build an array for chart data */ - $jqData = array( $groupBy => array(), "impressions" => array(), "clicks" => array(), "ctr" => array(), "avg_position" => array() ); + $jqData = array( $groupByAlias => array(), "impressions" => array(), "clicks" => array(), "ctr" => array(), "avg_position" => array() ); foreach ( $rows as $index => $values ) { - $jqData[$groupBy][] = $index; + if( $groupByAlias == "page" ) { + $indexDomain = substr( $index, 0, strlen( $reportParams['domain'] ) ); + if( strlen( $index ) > strlen( $indexDomain ) && $indexDomain == $reportParams['domain'] ) { + $jqData[$groupByAlias][] = substr( $index, strlen( $reportParams['domain'] ) ); + } + } else { + $jqData[$groupByAlias][] = $index; + } + $jqData['impressions'][] = $values["impressions"]; $jqData['clicks'][] = $values["clicks"]; $jqData['ctr'][] = ( $values["clicks"] / $values["impressions"] ) * 100; $jqData['avg_position'][] = $values["avg_position"]; } - $num = count( $jqData[$groupBy] ); + $num = count( $jqData[$groupByAlias] ); $posString = ""; + $xAxis = ""; $posMax = 0; for( $c=0; $c<$num; $c++ ) { if( $c != 0 ) { $posString .= ","; + $xAxis .= ","; } - $posString .= "['".addslashes($jqData[$groupBy][$c])."',".$jqData['avg_position'][$c]."]"; + $posString .= "['".addslashes($jqData[$groupByAlias][$c])."',".$jqData['avg_position'][$c]."]"; if( $jqData['avg_position'][$c] > $posMax ) { $posMax = $jqData['avg_position'][$c]; } + $xAxis .= "['".addslashes($jqData[$groupByAlias][$c])."','".addslashes($jqData[$groupByAlias][$c])."']"; } ?> @@ -152,7 +201,7 @@ + - + array(), + "query" => array("queries"), + "page" => array("pages") + ); + ?> $values ) { ?> - + + $values ) { ?> +
+ array( "week", "month", "year" ) ); ?> + - + + + + + + + + + + + + + + + + $values ) { ?> + + - - + + + + + + + + + diff --git a/organic-search-analytics/settings-configure.php b/organic-search-analytics/settings-configure.php index 618d3b0..e0208d5 100644 --- a/organic-search-analytics/settings-configure.php +++ b/organic-search-analytics/settings-configure.php @@ -19,6 +19,8 @@ $writeToConfigFile .= $t.$t."const OAUTH_CREDENTIALS_PRIVATE_KEY_FILE_NAME = '".$_POST['OAUTH_CREDENTIALS_PRIVATE_KEY_FILE_NAME']."';".$nl; $writeToConfigFile .= "".$nl; $writeToConfigFile .= $t.$t."const CREDENTIALS_BING_API_KEY = '".$_POST['CREDENTIALS_BING_API_KEY']."';".$nl; + $writeToConfigFile .= "".$nl; + $writeToConfigFile .= $t.$t."const DEBUG_LOGGER = ".( isset( $_POST['DEBUG_LOGGER'] ) ? 1 : 0 ).";".$nl; $writeToConfigFile .= $t."}".$nl; $writeToConfigFile .= "?>"; @@ -54,6 +56,7 @@ $credentials_bing_api_key = config::CREDENTIALS_BING_API_KEY; + $debug_logger = ( defined( 'config::DEBUG_LOGGER' ) ? config::DEBUG_LOGGER : Core::DISABLED ); } else { $db_connection_host = $db_connection_user = $db_connection_password = $db_connection_database = $oauth_credentials_private_key_file_name = $oauth_credentials_email = $credentials_bing_api_key = ""; } @@ -103,9 +106,17 @@

+
+

Debug Logging

+ +

+ + "> +

+
- + diff --git a/organic-search-analytics/settings.php b/organic-search-analytics/settings.php index 83e06c3..a16859a 100644 --- a/organic-search-analytics/settings.php +++ b/organic-search-analytics/settings.php @@ -10,12 +10,13 @@ $siteSettings = array(); $siteSettings['Google'] = $mysql->getSettings("sites_google"); $siteSettings['Bing'] = $mysql->getSettings("sites_bing"); - + $siteSettings['Settings'] = $mysql->getSettings("settings"); + /* Get list of sites */ $wmtSites = array(); $wmtSites['Google'] = $dataCapture->getSitesGoogleSearchConsole(); $wmtSites['Bing'] = $dataCapture->getSitesBingWebmaster(); - + /* Get combined sites */ foreach( $wmtSites as $searchEngine => $sitesData ) { foreach( $sitesData as $key => $data ) { @@ -37,12 +38,55 @@ } } + /* Define settings for the page */ + $settingsSetup = array( + "google" => array( + "description" => "Customize what infomration is captured from Google", + "label" => "Google", + "products" => array( + "search_console" => array( + "description" => "Select which dimensions you'd like to capture.
NOTE: Adding more dimensions could limit the accuracy of the data you obtain. The Google API provides up to 5,000 results per request.
To illustrate this example, if you select Queries only lets say there were 10 queries for that day. If you then add Country and each query was returned in 5 countries each, you now are receiving 50 results (10 queries X 5 countries). Adding Device Type, assuming each query in each country was performed on each Device Type the number of results would grow to 150 results. You can see how as you add additional dimensions the number of results can grow quickly. Depending on frequently your site shows in the SERPs this may or may not impact your ability to capture all of the avaialbe data.
", + "label" => "Search Console", + "section" => array( + "dimensions" => array( + "description" => " section description", + "heading" => "Dimensions", + "heading_options" => "Enable/Disable", + "options" => array( + "query" => array( + "label" => "Queries", + "type" => "checkbox", + "note" => "" + ), + "page" => array( + "label" => "Page (URL)", + "type" => "checkbox", + "note" => "" + ), + "device" => array( + "label" => "Device Type", + "type" => "checkbox", + "note" => "Will return Desktop, Mobile, or Tablet" + ), + "country" => array( + "label" => "Country", + "type" => "checkbox", + "note" => "" + ) + ) + ) + ) + ) + ) + ) + ); + /* Update settings table */ if( isset( $_POST['save_settings'] ) ) { foreach( $sitesList as $site => $data ) { // Set to checked $siteToAdd = addslashes( $site ); - + foreach( $data['availableTo'] as $searchEngine ) { if( in_array( $searchEngine, $data['enabled'] ) && isset( $_POST['site_settings'][$site][$searchEngine] ) ) { //do nothing @@ -63,6 +107,35 @@ } } } + + /* Loop through settings and update database where necessary */ + foreach( $settingsSetup as $searchEngine => $settingsGroup ) { + foreach( $settingsGroup['products'] as $productName => $productGroup ) { + foreach( $productGroup['section'] as $sectionName => $sectionGroup ) { + foreach( $sectionGroup['options'] as $optionName => $optionGroup ) { + $value = $searchEngine."_".$productName."_".$sectionName."_".$optionName; + switch( $optionGroup['type'] ) { + case "checkbox": + if( isset( $_POST['settings'][$searchEngine][$productName][$sectionName][$optionName] ) ) { $data = "On"; } else { $data = "Off"; } + break; + default: + $data = $_POST['settings'][$searchEngine][$productName][$sectionName][$optionName]; + } + + // Update the database + if( !isset( $siteSettings['Settings'][$value] ) ) { + $response = $mysql->qryDBinsert( $mysql::DB_TABLE_SETTINGS, "NULL, 'settings', '$value', '$data'" ); + } elseif ( isset( $siteSettings['Settings'][$value] ) && $siteSettings['Settings'][$value] != $data ) { + $response = $mysql->qryDBupdate( $mysql::DB_TABLE_SETTINGS, array( 'type' => 'settings', 'value' => $value ), array( 'data' => $data ) ); + } + + // Update settings loaded ot page + $siteSettings['Settings'][$value] = $data; + } + } + } + } + $alert = array("type"=>"success", "message"=>"Settings Succesfully Saved"); } } @@ -85,12 +158,20 @@

Site Setup

-

Select the sites and Search Engine to capture data from.

+
+

Select the sites and Search Engine to capture data from.

+

Not seeing the sites you expect?

Google Search Console

-

Ensure that you have enabled the Google Search Console API and added your Google API Service Account email address as a user to each of your sites in Google Search Console.
Instruction on how to configure Google Search Analytics for API Access

+
+

Ensure that you have enabled the Google Search Console API and added your Google API Service Account email address as a user to each of your sites in Google Search Console.
Instruction on how to configure Google Search Analytics for API Access

+
+ +

Bing Webmaster Tools

-

Ensure that you have configured your site with Bing Wembaster Tools and that the API key set in the configuration matches that of the
API key found in Bing Webmaster Tools.

+
+

Ensure that you have configured your site with Bing Wembaster Tools and that the API key set in the configuration matches that of the
API key found in Bing Webmaster Tools.

+
- - + + $settingsGroup ) {?> +

+ 0 ) { ?>
+ $productGroup ) { ?> +
+

Options

+ 0 ) { ?>
+ $sectionGroup ) { ?> +
+
+
+
+ $optionGroup ) { ?> +
+
+
+ /> +
+
+ +
+
+ + +
+ + + +
\ No newline at end of file diff --git a/organic-search-analytics/upgrade.php b/organic-search-analytics/upgrade.php index d6d1c04..1d6e648 100644 --- a/organic-search-analytics/upgrade.php +++ b/organic-search-analytics/upgrade.php @@ -66,6 +66,77 @@ $alert = array("type"=>"success", "message"=>"Upgrade performed succesfully."); break; + case "2_x_x_to_2_5_0": + /* Include resources */ + include_once( 'inc/code/core.php' ); //Core functions + include_once( 'inc/code/mysql.php' ); //Database Connection + $core = new Core(); //Load core + $mysql = new MySQL(); //Load MySQL + $GLOBALS['db'] = $core->mysql_connect_db(); // Connect to DB + + $errors = array(); + + /* Table: search_analytics */ + $query = "ALTER TABLE `search_analytics`". + " ADD `page` VARCHAR(500) NULL DEFAULT NULL AFTER `query`,". + " CHANGE COLUMN `device_type` `device_type` VARCHAR(24) NULL DEFAULT NULL,". + " CHANGE COLUMN `country` `country` VARCHAR(10) NULL DEFAULT NULL,". + " CHANGE COLUMN `query` `query` VARCHAR(500) NULL DEFAULT NULL,". + " CHANGE COLUMN `avg_position` `avg_position` FLOAT NULL DEFAULT NULL,". + " CHANGE COLUMN `avg_position_click` `avg_position_click` FLOAT NULL DEFAULT NULL,". + " CONVERT TO CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`" + ; + $result = $mysql->query( $query ); + if( !$result ) { + $errors[] = $mysql->error; + } + + /* Table: search_analytics */ + /* Action: Prepopulate settings */ + $query = "INSERT INTO `settings`". + " (type, value, data)". + "VALUES". + " ('settings', 'google_search_console_dimensions_query', 'On'),". + " ('settings', 'google_search_console_dimensions_page', 'Off'),". + " ('settings', 'google_search_console_dimensions_device', 'On'),". + " ('settings', 'google_search_console_dimensions_country', 'On')" + ; + $result = $mysql->query( $query ); + if( !$result ) { + $errors[] = $mysql->error; + } + + /* Table: report_saved */ + $query = "ALTER TABLE `report_saved` CONVERT TO CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`"; + $result = $mysql->query( $query ); + if( !$result ) { + $errors[] = $mysql->error; + } + + /* Table: report_saved_categories */ + $query = "ALTER TABLE `report_saved_categories` CONVERT TO CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`"; + $result = $mysql->query( $query ); + if( !$result ) { + $errors[] = $mysql->error; + } + + /* Table: settings */ + $query = "ALTER TABLE `settings` ENGINE=`INNODB`, CONVERT TO CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`"; + $result = $mysql->query( $query ); + if( !$result ) { + $errors[] = $mysql->error; + } + + if( !count( $errors ) ) { + $alert = array("type"=>"success", "message"=>"Upgrade performed succesfully."); + } else { + $errorString = "There were errors in the upgrade process.

"; + $errorString .= implode("
", $errors ); + $alert = array("type"=>"error", "message"=>$errorString); + } + + $alert = array("type"=>"success", "message"=>"Upgrade performed succesfully.
Go to the Settings Configuration page and click the Save button."); + break; } } ?> @@ -76,11 +147,40 @@

Certain versions require special consideration when upgrading. This page will take care of technical changes that need to be made.

NOTE: If upgrading through multiple versions, it's advised to run all of the updates in order.

    +
  • +

    Version 2.x.x to 2.5.0

    +
      +
    • Several database changes:
    • +
        +
      • Adds column page to the search_analytics table.
      • +
      • Updates column country to default to NULL.
      • +
      • Updates column query to allow NULL and default to NULL.
      • +
      • Updates column device_type to allow NULL and default to NULL.
      • +
      • Updates column avarage_position setting default to NULL and change type from int(11) to float.
      • +
      • Updates column avarage_position_click changing type from int(11) to float.
      • +
      • Change the default character set to utf8 for all tables
      • +
      • Change the engine from MyISAM to InnoDB on the settings table.
      • +
      +
    • Added debug logging functionality (only added to Data Capture processes at this time)
    • +
        +
      • NOTE: Manual Upgrade Step is Required!
      • +
      • Go to the Settings Configuration page and click the Save button. This updates your config file to add the Debug Logger configuration. You do NOT need to enable it (and it is wise not to unless you need to do debugging).
      • +
      +
    • Run Update for Version 2.x.x to 2.5.0
    • +
    +
  • +
  • +

    Version 2.x.x to 2.4.0

    + +
  • Version 2.1.0 and below to 2.2.0

  • @@ -88,14 +188,7 @@
    • Adds the CREDENTIALS_BING_API_KEY constant to the config/config.php file to allow for setting the Bing Webmaster Tools API connection.
    • Updates the Click Through Rate data type in the search_analytics table to correct data inaccuracies.
    • -
    • Run Update for Version 1.x to 2.0.0
    • -
    -
  • -
  • -

    Version 2.x.x to 2.4.0

    -
diff --git a/organic-search-analytics/version.txt b/organic-search-analytics/version.txt index 35cee72..437459c 100644 --- a/organic-search-analytics/version.txt +++ b/organic-search-analytics/version.txt @@ -1 +1 @@ -2.4.3 +2.5.0
- + + + + + + + + + Pages + + + + Impressions + Clicks + Avg Position + CTR +
+ '; + } + $indexDomain = substr( $index, 0, strlen( $reportParams['domain'] ) ); + if( strlen( $index ) > strlen( $indexDomain ) && $indexDomain == $reportParams['domain'] ) { + echo substr( $index, strlen( $reportParams['domain'] ) ); + } else { + echo ( strlen( $index ) > 0 ? $index : '( not set )' ); + } + + if( $url ) { + echo ''; + echo ''; + } + ?> + + + + + + + + + + + + + + + + + + + + + + + + +