diff --git a/profiles/wcm_base/CHANGELOG.txt b/profiles/wcm_base/CHANGELOG.txt index 61e8e0378e5fdd93362523ad74f4db47bf08d3e9..40b5ceb4724e022d1f4a6145217e363df7ec3281 100644 --- a/profiles/wcm_base/CHANGELOG.txt +++ b/profiles/wcm_base/CHANGELOG.txt @@ -1,3 +1,11 @@ +WCM Base 7.x-1.x, 2017-03-24 +---------------------------- +- WCM Base: + - Added News Client module. + - Added Panopoly Search patch to update Search API contrib modules. +- WCM Omega, OCIO Omega: Added max-width to floated images. +- OCIO News: Allowed byline field to replace new author, or hide it completely. + WCM Base 7.x-1.x, 2017-03-21 ---------------------------- - WCM Base: Added WCM Metatags module. diff --git a/profiles/wcm_base/build-wcm_base-dev.make b/profiles/wcm_base/build-wcm_base-dev.make index 67dcdd555628a905fca704a7b6878075962cc58a..493134b09395b2866506f5bdd328788e6f5e8331 100644 --- a/profiles/wcm_base/build-wcm_base-dev.make +++ b/profiles/wcm_base/build-wcm_base-dev.make @@ -45,6 +45,7 @@ projects[wcm_user_leadership][options][working-copy] = TRUE projects[wcm_user_profile][options][working-copy] = TRUE projects[smtp_html_mail][options][working-copy] = TRUE projects[wcm_news_client_display][options][working-copy] = TRUE +projects[news_client][options][working-copy] = TRUE ;themes projects[ocio_omega_base][options][working-copy] = TRUE diff --git a/profiles/wcm_base/modules/contrib/oauth2_client/LICENSE.txt b/profiles/wcm_base/modules/contrib/oauth2_client/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..d159169d1050894d3ea3b98e1c965c4058208fe1 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/oauth2_client/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/profiles/wcm_base/modules/contrib/oauth2_client/README.org b/profiles/wcm_base/modules/contrib/oauth2_client/README.org new file mode 100644 index 0000000000000000000000000000000000000000..c394b8a94c7d7859f1b16a8d8772ce823992e8b1 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/oauth2_client/README.org @@ -0,0 +1,195 @@ + +This module is a complement to the module [[https://drupal.org/project/oauth2_server][oauth2_server]]. + +*Note:* The modules oauth2_server and oauth2_client have conflicts +with the module [[https://drupal.org/project/oauth2][oauth2]], so they should not be installed at the same +time. + +* How to use it + + Define oauth2 clients in your code like this: + #+BEGIN_EXAMPLE + /** + * Implements hook_oauth2_clients(). + */ + function MYMODULE_oauth2_clients() { + $server_url = 'https://oauth2_server.example.org'; + $client_url = 'https://oauth2_client.example.org'; + + // user-password flow + $oauth2_clients['test1'] = array( + 'token_endpoint' => $server_url . '/oauth2/token', + 'auth_flow' => 'user-password', + 'client_id' => 'test1', + 'client_secret' => 'test1', + 'username' => 'user1', + 'password' => 'user1', + ); + + // client-credentials flow + $oauth2_clients['test2'] = array( + 'token_endpoint' => $server_url . '/oauth2/token', + 'auth_flow' => 'client-credentials', + 'client_id' => 'test2', + 'client_secret' => 'test2', + ); + + // server-side flow + $oauth2_clients['test3'] = array( + 'token_endpoint' => $server_url . '/oauth2/token', + 'auth_flow' => 'server-side', + 'client_id' => 'test1', + 'client_secret' => 'test1', + 'authorization_endpoint' => $server_url . '/oauth2/authorize', + 'redirect_uri' => $client_url . '/oauth2/authorized', + ); + + return $oauth2_clients; + } + #+END_EXAMPLE + + Then use them like this: + #+BEGIN_EXAMPLE + try { + $oauth2_client = oauth2_client_load('test1'); + $access_token = $oauth2_client->getAccessToken(); + } + catch (Exception $e) { + drupal_set_message($e->getMessage(), 'error'); + } + #+END_EXAMPLE + + The only thing that oauth2_client does is to get an access_token + from the oauth2_server, so that it can be used for accessing web + services. + + +* More about using it + + Another form of usage is like this: + #+BEGIN_EXAMPLE + $oauth2_config = array( + 'token_endpoint' => $server_url . '/oauth2/token', + 'auth_flow' => 'user-password', + 'client_id' => 'test1', + 'client_secret' => '12345', + 'username' => $username, + 'password' => $password, + ); + try { + $oauth2_client = new OAuth2\Client($oauth2_config, $client_id); + $access_token = $oauth2_client->getAccessToken(); + } + catch (Exception $e) { + drupal_set_message($e->getMessage(), 'error'); + } + #+END_EXAMPLE + + +* Custom usage + + Sometimes (or rather often) oauth2 servers have special requirements + that are different from the OAuth2 standard and different from other + oauth2 implementations. This client cannot possibly cover all these + special requirements. In such a case, a possible solution can be to + extend the class *OAuth2\Client* like this: + #+BEGIN_EXAMPLE + <?php + namespace OAuth2; + + class MyClient extends Client { + protected function getToken($data) { + // Implement the custom logic that is needed by the oauth2 server. + } + } + #+END_EXAMPLE + + And then use it like this: + #+BEGIN_EXAMPLE + try { + $oauth2_client = new OAuth2\MyClient($oauth2_config); + $access_token = $oauth2_client->getAccessToken(); + } + catch (Exception $e) { + drupal_set_message($e->getMessage(), 'error'); + } + #+END_EXAMPLE + + +* How it works + + An access token and its related data are stored on the session + ($_SESSION['oauth2_client']['token'][$client_id]), so that it can be + reused while it is not expired yet. The data that are stored for + each token are: access_token, expires_in, token_type, scope, + refresh_token and expiration_time. They are the values that come + from the oauth2 server, except the last one, which is calculated as + (REQUEST_TIME + expires_in). + + When the token has expired (expiration_time > time() + 10), a new + token is requested from the oauth2 server, using the refresh_token. + If the refresh token fails for some reason (maybe refresh_token + expired or any other reason), then the whole process of + authorization is performed from the beginning. + + For the client-credentials and user-password authorization flows + this does not involve a user interaction with the oauth2 server. + + However, for the server-side flow the user has to authorize again + the application. This is done in these steps, first the user is + redirected to the oauth2 server to authorize the application again, + from there it is redirected back to the application with an + authorization code, then the application uses the authorization code + to request a new access token. + + In order to remember the part of the client application that + initiated the authorization request, a session variable is used: + $_SESSION['oauth2_client']['redirect'][$state]. Then, drupal_goto() + is used to jump again to that path of the application. + + +* Integrating with other oauth2 clients + + Other oauth2 clients for Drupal can integrate with oauth2_client. + This means that they can use the same client that is registered on + the oauth2_server for the oauth2_client. + + The oauth2_server sends the authorization reply to the redirect_uri + that is registered for the client. If this client has been + registered for being used by the module oauth2_client, then its + redirect_uri is like this: + https://server.example.org/oauth2/authorized . A reply sent to this + redirect_uri will be routed to the callback function supplied by + oauth2_client. So, in general, the other oauth2 clients cannot use + the same client_id and client_secret that are registered in the + server. They will have to register their own client_id, + client_secret and redirect_uri. + + However this is not very convenient. That's why oauth2_client allows + the other oauth2 clients to use the same client_id and + client_secret, but the reply has to pass through oauth2_client, + since redirect_uri sends it there. + + It works like this: Suppose that another oauth2 client starts the + authentication workflow. On the parameters of the request it sets + redirect_uri to the one belonging to oauth2_client (since this is + the one that is reckognized and accepted by the server). However at + the same time it notifies oauth2_client that the reply of this + request should be forwarded to it. It does it by calling the + function: oauth2_client_set_redirect($state, $redirect). + + The parameter $state is the random parameter that is used on the + authentication url in order to mittigate CSRF attacks. In this case + it is used as a key for identifying the authentication request. The + parameter $redirect is an associative array that contains the keys: + - uri: the uri of the oauth2 client that is requesting a + redirect + - params: associative array of other parameters that should be + appended to the uri, along with the $_REQUEST comming from the + server + + Once another oauth2 client that has been successfully authenticated + and has received an access_token, it can share it with the + oauth2_client, so that oauth2_client does not have to repeat the + authentication process again. It can be done by calling the + function: oauth2_client_set_token($client_id, $token). diff --git a/profiles/wcm_base/modules/contrib/oauth2_client/README.txt b/profiles/wcm_base/modules/contrib/oauth2_client/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..cd4e675462e430628779f80b1fb363d6dbc16d64 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/oauth2_client/README.txt @@ -0,0 +1,192 @@ + +This module is a a complement to the module oauth2_server. + +*Note:* The modules oauth2_server and oauth2_client have conflicts +with the module oauth2, so they should not be installed at the same +time. + +* How to use it + + Define oauth2 clients in your code like this: + #+BEGIN_EXAMPLE + /** + * Implements hook_oauth2_clients(). + */ + function MYMODULE_oauth2_clients() { + $server_url = 'https://oauth2_server.example.org'; + $client_url = 'https://oauth2_client.example.org'; + + // user-password flow + $oauth2_clients['test1'] = array( + 'token_endpoint' => $server_url . '/oauth2/token', + 'auth_flow' => 'user-password', + 'client_id' => 'test1', + 'client_secret' => 'test1', + 'username' => 'user1', + 'password' => 'user1', + ); + + // client-credentials flow + $oauth2_clients['test2'] = array( + 'token_endpoint' => $server_url . '/oauth2/token', + 'auth_flow' => 'client-credentials', + 'client_id' => 'test2', + 'client_secret' => 'test2', + ); + + // server-side flow + $oauth2_clients['test3'] = array( + 'token_endpoint' => $server_url . '/oauth2/token', + 'auth_flow' => 'server-side', + 'client_id' => 'test1', + 'client_secret' => 'test1', + 'authorization_endpoint' => $server_url . '/oauth2/authorize', + 'redirect_uri' => $client_url . '/oauth2/authorized', + ); + + return $oauth2_clients; + } + #+END_EXAMPLE + + Then use them like this: + #+BEGIN_EXAMPLE + try { + $oauth2_client = oauth2_client_load('test1'); + $access_token = $oauth2_client->getAccessToken(); + } + catch (Exception $e) { + drupal_set_message($e->getMessage(), 'error'); + } + #+END_EXAMPLE + + The only thing that oauth2_client does is to get an access_token + from the oauth2_server, so that it can be used for accessing web + services. + + +* More about using it + + Another form of usage is like this: + #+BEGIN_EXAMPLE + $oauth2_config = array( + 'token_endpoint' => $server_url . '/oauth2/token', + 'auth_flow' => 'user-password', + 'client_id' => 'test1', + 'client_secret' => '12345', + 'username' => $username, + 'password' => $password, + ); + try { + $oauth2_client = new OAuth2\Client($oauth2_config, $client_id); + $access_token = $oauth2_client->getAccessToken(); + } + catch (Exception $e) { + drupal_set_message($e->getMessage(), 'error'); + } + #+END_EXAMPLE + +* Custom usage + + Sometimes (or rather often) oauth2 servers have special requirements + that are different from the OAuth2 standard and different from other + oauth2 implementations. This client cannot possibly cover all these + special requirements. In such a case, a possible solution can be to + extend the class *OAuth2\Client* like this: + #+BEGIN_EXAMPLE + <?php + namespace OAuth2; + + class MyClient extends Client { + protected function getToken($data) { + // Implement the custom logic that is needed by the oauth2 server. + } + } + #+END_EXAMPLE + + And then use it like this: + #+BEGIN_EXAMPLE + try { + $oauth2_client = new OAuth2\MyClient($oauth2_config); + $access_token = $oauth2_client->getAccessToken(); + } + catch (Exception $e) { + drupal_set_message($e->getMessage(), 'error'); + } + #+END_EXAMPLE + +* How it works + + An access token and its related data are stored on the session + ($_SESSION['oauth2_client']['token'][$client_id]), so that it can be + reused while it is not expired yet. The data that are stored for + each token are: access_token, expires_in, token_type, scope, + refresh_token and expiration_time. They are the values that come + from the oauth2 server, except the last one, which is calculated as + (REQUEST_TIME + expires_in). + + When the token has expired (expiration_time > time() + 10), a new + token is requested from the oauth2 server, using the refresh_token. + If the refresh token fails for some reason (maybe refresh_token + expired or any other reason), then the whole process of + authorization is performed from the beginning. + + For the client-credentials and user-password authorization flows + this does not involve a user interaction with the oauth2 server. + + However, for the server-side flow the user has to authorize again + the application. This is done in these steps, first the user is + redirected to the oauth2 server to authorize the application again, + from there it is redirected back to the application with an + authorization code, then the application uses the authorization code + to request a new access token. + + In order to remember the part of the client application that + initiated the authorization request, a session variable is used: + $_SESSION['oauth2_client']['redirect'][$state]['uri']. Then, + drupal_goto() is used to jump again to that path of the application. + +* Integrating with other oauth2 clients + + Other oauth2 clients for Drupal can integrate with oauth2_client. + This means that they can use the same client that is registered on + the oauth2_server for the oauth2_client. + + The oauth2_server sends the authorization reply to the redirect_uri + that is registered for the client. If this client has been + registered for being used by the module oauth2_client, then its + redirect_uri is like this: + https://server.example.org/oauth2/authorized . A reply sent to this + redirect_uri will be routed to the callback function supplied by + oauth2_client. So, in general, the other oauth2 clients cannot use + the same client_id and client_secret that are registered in the + server. They will have to register their own client_id, + client_secret and redirect_uri. + + However this is not very convenient. That's why oauth2_client allows + the other oauth2 clients to use the same client_id and + client_secret, but the reply has to pass through oauth2_client, + since redirect_uri sends it there. + + It works like this: Suppose that another oauth2 client starts the + authentication workflow. On the parameters of the request it sets + redirect_uri to the one belonging to oauth2_client (since this is + the one that is reckognized and accepted by the server). However at + the same time it notifies oauth2_client that the reply of this + request should be forwarded to it. It does it by calling the + function: oauth2_client_set_redirect($state, $redirect). + + The parameter $state is the random parameter that is used on the + authentication url in order to mittigate CSRF attacks. In this case + it is used as a key for identifying the authentication request. The + parameter $redirect is an associative array that contains the keys: + - uri: the uri of the oauth2 client that is requesting a + redirect + - params: associative array of other parameters that should be + appended to the uri, along with the $_REQUEST comming from the + server + + Once another oauth2 client that has been successfully authenticated + and has received an access_token, it can share it with the + oauth2_client, so that oauth2_client does not have to repeat the + authentication process again. It can be done by calling the + function: oauth2_client_set_token($client_id, $token). diff --git a/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.api.php b/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.api.php new file mode 100644 index 0000000000000000000000000000000000000000..f8b2c98c5c13168707336b1350fae986d265210f --- /dev/null +++ b/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.api.php @@ -0,0 +1,155 @@ +<?php +/** + * @file + * The programing interface provided by the module oauth2_client. + */ + +/** + * Define oauth2 clients. + * + * @return Array + * Associative array of oauth2 clients. + */ +function hook_oauth2_clients() { + global $base_url; + $server_url = 'https://oauth2_server.example.org'; + + $oauth2_clients = array(); + + // Using user-password flow. + $oauth2_clients['test1'] = array( + 'token_endpoint' => $server_url . '/oauth2/token', + 'auth_flow' => 'user-password', + 'client_id' => 'client1', + 'client_secret' => 'secret1', + 'username' => 'user1', + 'password' => 'pass1', + ); + + // Using client-credentials flow. + $oauth2_clients['test2'] = array( + 'token_endpoint' => $server_url . '/oauth2/token', + 'auth_flow' => 'client-credentials', + 'client_id' => 'client2', + 'client_secret' => 'secret2', + ); + + // Using server-side flow. + $oauth2_clients['test3'] = array( + 'token_endpoint' => $server_url . '/oauth2/token', + 'auth_flow' => 'server-side', + 'client_id' => 'client3', + 'client_secret' => 'secret3', + 'authorization_endpoint' => $server_url . '/oauth2/authorize', + 'redirect_uri' => $base_url . '/oauth2/authorized', + ); + + return $oauth2_clients; +} + +/** + * Load an oauth2 client. + * + * @param string $name + * Name of the client. + * + * @return OAuth2\Client + * Returns an OAuth2\Client object + * + * Example: + * $test1 = oauth2_client_load('test1'); + * $access_token = $test1->getAccessToken(); + */ +function oauth2_client_load($name); + +/** + * Return the redirect_uri of oauth2_client. + */ +function oauth2_client_get_redirect_uri() { + return url('oauth2/authorized', array('absolute' => TRUE)); +} + +/** + * Set a redirect request. + * + * This can be used by other oauth2 clients to integrate with + * oauth2_client, i.e. to use the same client that is registered + * on the server for the oauth2_client. + * + * The oauth2_server sends the authorization reply to the + * redirect_uri that is registered for the client, which is + * the one corresponding to oauth2_client. If another oauth2 + * client would like to get this authorization reply, it has + * to set a redirect request with this function, and then + * oauth2_client will forward the reply to it. + * + * @param string $state + * The random parameter that is used on the authentication url + * in order to mittigate CSRF attacks. In this case it is used + * as a key for identifying the authentication request. + * + * @param array $redirect + * Associative array that contains the keys: + * - 'uri': the uri of the oauth2 client that is requesting a redirect + * - 'params': associative array of other parameters that should be + * appended to the uri, along with the $_REQUEST + * + * Example: + * $state = md5(uniqid(rand(), TRUE)); + * $hybridauth_config['state'] = $state; + * $hybridauth_config['redirect_uri'] = oauth2_client_get_redirect_uri(); + * oauth2_client_set_redirect($state, array( + * 'uri' => 'hybridauth/endpoint', + * 'params' => array( + * 'hauth.done' => 'DrupalOAuth2', + * ) + * )); + */ +function oauth2_client_set_redirect($state, $redirect) { + OAuth2\Client::setRedirect($state, $redirect); +} + +/** + * Share an access token with oauth2_client. + * + * Another oauth2 client that has been successfully authenticated + * and has received an access_token, can share it with oauth2_client, + * so that oauth2_client does not have to repeat the authentication + * process again. + * + * Example: + * $client_id = $hybridauth->api->client_id; + * $token = array( + * 'access_token' => $hybridauth->api->access_token, + * 'refresh_token' => $hybridauth->api->refresh_token, + * 'expires_in' => $hybridauth->api->access_token_expires_in, + * 'expiration_time' => $hybridauth->api->access_token_expires_at, + * 'scope' => $hybridauth->scope, + * ); + * $token_endpoint = $oauth2->api->token_endpoint; + * $client_id = $oauth2->api->client_id; + * $auth_flow = 'server-side'; + * $id = md5($token_endpoint . $client_id . $auth_flow); + * oauth2_client_set_token($id, $token); + */ +function oauth2_client_set_token($client_id, $token) { + $_SESSION['oauth2_client']['token'][$client_id] = $token; +} + +/** + * Returns the access token of the oauth2_client for the given $client_id. + */ +function oauth2_client_get_token($client_id) { + if (isset($_SESSION['oauth2_client']['token'][$client_id])) { + return $_SESSION['oauth2_client']['token'][$client_id]; + } + else { + return array( + 'access_token' => NULL, + 'refresh_token' => NULL, + 'expires_in' => NULL, + 'expiration_time' => NULL, + 'scope' => NULL, + ); + } +} diff --git a/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.inc b/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.inc new file mode 100644 index 0000000000000000000000000000000000000000..afc2972817ad16deb328f0baa525194b94396b01 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.inc @@ -0,0 +1,403 @@ +<?php +namespace OAuth2; + +/** + * @file + * class OAuth2\Client + */ + +/** + * The class OAuth2\Client is used to get authorization from + * an oauth2 server. Its only goal is to get an access_token + * from the oauth2 server, so the only public function + * (besides the constructor) is getAccessToken(). + * + * It can use authorization flows: server-side, client-credentials + * and user-password. The details for each case are passed + * to the constructor. All the three cases need a client_id, + * a client_secret, and a token_endpoint. There can be an optional + * scope as well. + */ +class Client { + /** + * Unique identifier of an OAuth2\Client object. + */ + protected $id = NULL; + + /** + * Associative array of the parameters that are needed + * by the different types of authorization flows. + * - auth_flow :: server-side | client-credentials | user-password + * - client_id :: Client ID, as registered on the oauth2 server + * - client_secret :: Client secret, as registered on the oauth2 server + * - token_endpoint :: something like: + * https://oauth2_server.example.org/oauth2/token + * - authorization_endpoint :: somethig like: + * https://oauth2_server.example.org/oauth2/authorize + * - redirect_uri :: something like: + * url('oauth2/authorized', array('absolute' => TRUE)) or + * https://oauth2_client.example.org/oauth2/authorized + * - scope :: requested scopes, separated by a space + * - username :: username of the resource owner + * - password :: password of the resource owner + * - skip-ssl-verification :: Skip verification of the SSL connection (needed for testing). + */ + protected $params = array( + 'auth_flow' => NULL, + 'client_id' => NULL, + 'client_secret' => NULL, + 'token_endpoint' => NULL, + 'authorization_endpoint' => NULL, + 'redirect_uri' => NULL, + 'scope' => NULL, + 'username' => NULL, + 'password' => NULL, + 'skip-ssl-verification' => FALSE, + ); + + /** + * Associated array that keeps data about the access token. + */ + protected $token = array( + 'access_token' => NULL, + 'expires_in' => NULL, + 'token_type' => NULL, + 'scope' => NULL, + 'refresh_token' => NULL, + 'expiration_time' => NULL, + ); + + /** Return the token array. */ + function token() { return $this->token; } + + /** + * Construct an OAuth2\Client object. + * + * @param array $params + * Associative array of the parameters that are needed + * by the different types of authorization flows. + * + * @param string $id + * ID of the client. If not given, it will be generated + * from token_endpoint, client_id and auth_flow. + */ + public function __construct($params = NULL, $id = NULL) { + if ($params) $this->params = $params + $this->params; + + if (!$id) { + $id = md5($this->params['token_endpoint'] + . $this->params['client_id'] + . $this->params['auth_flow']); + } + $this->id = $id; + + // Get the token data from the session, if it is stored there. + if (isset($_SESSION['oauth2_client']['token'][$this->id])) { + $this->token = $_SESSION['oauth2_client']['token'][$this->id] + $this->token; + } + } + + /** + * Clear the token data from the session. + */ + public function clearToken() { + if (isset($_SESSION['oauth2_client']['token'][$this->id])) { + unset($_SESSION['oauth2_client']['token'][$this->id]); + } + $this->token = array( + 'access_token' => NULL, + 'expires_in' => NULL, + 'token_type' => NULL, + 'scope' => NULL, + 'refresh_token' => NULL, + 'expiration_time' => NULL, + ); + } + + /** + * Get and return an access token. + * + * If there is an existing token (stored in session), return that one. But if + * the existing token is expired, get a new one from the authorization server. + * + * If the refresh_token has also expired and the auth_flow is 'server-side', a + * redirection to the oauth2 server will be made, in order to re-authenticate. + * However the redirection will be skipped if the parameter $redirect is + * FALSE, and NULL will be returned as access_token. + */ + public function getAccessToken($redirect = TRUE) { + // Check wheather the existing token has expired. + // We take the expiration time to be shorter by 10 sec + // in order to account for any delays during the request. + // Usually a token is valid for 1 hour, so making + // the expiration time shorter by 10 sec is insignificant. + // However it should be kept in mind during the tests, + // where the expiration time is much shorter. + $expiration_time = $this->token['expiration_time']; + if ($expiration_time > (time() + 10)) { + // The existing token can still be used. + return $this->token['access_token']; + } + + try { + // Try to use refresh_token. + $token = $this->getTokenRefreshToken(); + } + catch (\Exception $e) { + // Get a token. + switch ($this->params['auth_flow']) { + case 'client-credentials': + $token = $this->getToken(array( + 'grant_type' => 'client_credentials', + 'scope' => $this->params['scope'], + )); + break; + + case 'user-password': + $token = $this->getToken(array( + 'grant_type' => 'password', + 'username' => $this->params['username'], + 'password' => $this->params['password'], + 'scope' => $this->params['scope'], + )); + break; + + case 'server-side': + if ($redirect) { + $token = $this->getTokenServerSide(); + } + else { + $this->clearToken(); + return NULL; + } + break; + + default: + throw new \Exception(t('Unknown authorization flow "!auth_flow". Suported values for auth_flow are: client-credentials, user-password, server-side.', + array('!auth_flow' => $this->params['auth_flow']))); + break; + } + } + $token['expiration_time'] = REQUEST_TIME + $token['expires_in']; + + // Store the token (on session as well). + $this->token = $token; + $_SESSION['oauth2_client']['token'][$this->id] = $token; + + // Redirect to the original path (if this is a redirection + // from the server-side flow). + self::redirect(); + + // Return the token. + return $token['access_token']; + } + + /** + * Get a new access_token using the refresh_token. + * + * This is used for the server-side and user-password + * flows (not for client-credentials, there is no + * refresh_token in it). + */ + protected function getTokenRefreshToken() { + if (!$this->token['refresh_token']) { + throw new \Exception(t('There is no refresh_token.')); + } + return $this->getToken(array( + 'grant_type' => 'refresh_token', + 'refresh_token' => $this->token['refresh_token'], + )); + } + + /** + * Get an access_token using the server-side (authorization code) flow. + * + * This is done in two steps: + * - First, a redirection is done to the authentication + * endpoint, in order to request an authorization code. + * - Second, using this code, an access_token is requested. + * + * There are lots of redirects in this case and this part is the most + * tricky and difficult to understand of the oauth2_client, so let + * me try to explain how it is done. + * + * Suppose that in the controller of the path 'test/xyz' + * we try to get an access_token: + * $client = oauth2_client_load('server-side-test'); + * $access_token = $client->getAccessToken(); + * or: + * $client = new OAuth2\Client(array( + * 'token_endpoint' => 'https://oauth2_server/oauth2/token', + * 'client_id' => 'client1', + * 'client_secret' => 'secret1', + * 'auth_flow' => 'server-side', + * 'authorization_endpoint' => 'https://oauth2_server/oauth2/authorize', + * 'redirect_uri' => 'https://oauth2_client/oauth2/authorized', + * )); + * $access_token = $client->getAccessToken(); + * + * From getAccessToken() we come to this function, getTokenServerSide(), + * and since there is no $_GET['code'], we redirect to the authentication + * url, but first we save the current path in the session: + * $_SESSION['oauth2_client']['redirect'][$state]['uri'] = 'test/xyz'; + * + * Once the authentication and authorization is done on the server, we are + * redirected by the server to the redirect uri: 'oauth2/authorized'. In + * the controller of this path we redirect to the saved path 'test/xyz' + * (since $_SESSION['oauth2_client']['redirect'][$state] exists), passing + * along the query parameters sent by the server (which include 'code', + * 'state', and maybe other parameters as well.) + * + * Now the code: $access_token = $client->getAccessToken(); is + * called again and we come back for a second time to the function + * getTokenServerSide(). However this time we do have a + * $_GET['code'], so we get a token from the server and return it. + * + * Inside the function getAccessToken() we save the returned token in + * session and then, since $_SESSION['oauth2_client']['redirect'][$state] + * exists, we delete it and make another redirect to 'test/xyz'. This third + * redirect is in order to have in browser the original url, because from + * the last redirect we have something like this: + * 'test/xyz?code=8557&state=3d7dh3&....' + * + * We come again for a third time to the code + * $access_token = $client->getAccessToken(); + * But this time we have a valid token already saved in session, + * so the $client can find and return it without having to redirect etc. + */ + protected function getTokenServerSide() { + if (!isset($_GET['code'])) { + $url = $this->getAuthenticationUrl(); + header('Location: ' . $url, TRUE, 302); + drupal_exit($url); + } + else { + // Check the query parameter 'state'. + if ( !isset($_GET['state']) + || !isset($_SESSION['oauth2_client']['redirect'][$_GET['state']]) ) + { + throw new \Exception(t("Wrong query parameter 'state'.")); + } + + // Get and return a token. + return $this->getToken(array( + 'grant_type' => 'authorization_code', + 'code' => $_GET['code'], + 'redirect_uri' => $this->params['redirect_uri'], + )); + } + } + + /** + * Return the authentication url (used in case of the server-side flow). + */ + protected function getAuthenticationUrl() { + $state = md5(uniqid(rand(), TRUE)); + $query_params = array( + 'response_type' => 'code', + 'client_id' => $this->params['client_id'], + 'redirect_uri' => $this->params['redirect_uri'], + 'state' => $state + ); + if ($this->params['scope']) { + $query_params['scope'] = $this->params['scope']; + } + $endpoint = $this->params['authorization_endpoint']; + self::setRedirect($state); + return $endpoint . '?' . http_build_query($query_params); + } + + /** + * Save the information needed for redirection after getting the token. + */ + public static function setRedirect($state, $redirect =NULL) { + if ($redirect == NULL) { + $redirect = array( + 'uri' => $_GET['q'], + 'params' => drupal_get_query_parameters(), + 'client' => 'oauth2_client', + ); + } + if (!isset($redirect['client'])) { + $redirect['client'] = 'external'; + } + $_SESSION['oauth2_client']['redirect'][$state] = $redirect; + } + + /** + * Redirect to the original path. + * + * Redirects are registered with OAuth2\Client::setRedirect() + * The redirect contains the url to go to and the parameters + * to be sent to it. + */ + public static function redirect($clean =TRUE) { + if (!isset($_REQUEST['state'])) return; + $state = $_REQUEST['state']; + + if (!isset($_SESSION['oauth2_client']['redirect'][$state])) return; + $redirect = $_SESSION['oauth2_client']['redirect'][$state]; + + // We don't expect a 'destination' query argument comming from the oauth2 server. + // This would confuse and misguide the function drupal_goto() that is called below. + if (isset($_GET['destination'])) unset($_GET['destination']); + + if ($redirect['client'] != 'oauth2_client') { + unset($_SESSION['oauth2_client']['redirect'][$state]); + drupal_goto($redirect['uri'], + array('query' => $redirect['params'] + $_REQUEST)); + } + else { + if ($clean) { + unset($_SESSION['oauth2_client']['redirect'][$state]); + unset($_REQUEST['code']); + unset($_REQUEST['state']); + } + drupal_goto($redirect['uri'], + array('query' => $redirect['params'] + $_REQUEST)); + } + } + + /** + * Get and return an access token for the grant_type given in $params. + */ + protected function getToken($data) { + if (array_key_exists('scope', $data) and $data['scope'] === NULL) { + unset($data['scope']); + } + + $client_id = $this->params['client_id']; + $client_secret = $this->params['client_secret']; + $token_endpoint = $this->params['token_endpoint']; + + $options = array( + 'method' => 'POST', + 'data' => drupal_http_build_query($data), + 'headers' => array( + 'Content-Type' => 'application/x-www-form-urlencoded', + 'Authorization' => 'Basic ' . base64_encode("$client_id:$client_secret"), + ), + ); + if ($this->params['skip-ssl-verification']) { + $options['context'] = stream_context_create(array( + 'ssl' => array( + 'verify_peer' => FALSE, + 'verify_peer_name' => FALSE, + ) + )); + } + $result = drupal_http_request($token_endpoint, $options); + + if ($result->code != 200) { + throw new \Exception( + t("Failed to get an access token of grant_type @grant_type.\nError: @result_error", + array( + '@grant_type' => $data['grant_type'], + '@result_error' => $result->error, + )) + ); + } + + return (Array) json_decode($result->data); + } +} diff --git a/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.info b/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.info new file mode 100644 index 0000000000000000000000000000000000000000..4a35d8f31f02aec03911f32eb8f1249ea2a44193 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.info @@ -0,0 +1,13 @@ +name = OAuth2 Client +description = Provides OAuth2 client functionality. +package = "OAuth2" +core = 7.x + +files[] = oauth2_client.inc + +; Information added by Drupal.org packaging script on 2016-08-24 +version = "7.x-1.6" +core = "7.x" +project = "oauth2_client" +datestamp = "1472072657" + diff --git a/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.install b/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.install new file mode 100644 index 0000000000000000000000000000000000000000..9d9c866b831586070ddb4af5897795eace286446 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.install @@ -0,0 +1,6 @@ +<?php +/** + * @file + * Install funcions. + */ + diff --git a/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.module b/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.module new file mode 100644 index 0000000000000000000000000000000000000000..4612dfebec415f8adcdecabadc0ba932db0ae26f --- /dev/null +++ b/profiles/wcm_base/modules/contrib/oauth2_client/oauth2_client.module @@ -0,0 +1,171 @@ +<?php +/** + * @file + * Provides OAuth2 client functionality. + */ + +/** + * Get the class OAuth2\Client. + */ +include_once drupal_get_path('module', 'oauth2_client') . '/oauth2_client.inc'; + +/** + * Gets all defined oauth2_clients. + */ +function oauth2_client_get_all() { + $data = array(); + foreach (module_implements('oauth2_clients') as $module) { + $result = call_user_func($module . '_oauth2_clients'); + if (isset($result) && is_array($result)) { + foreach ($result as $name => $item) { + $item += array('module' => $module); + $data[$name] = $item; + } + } + } + drupal_alter('oauth2_clients', $data); + return $data; +} + +/** + * Load an oauth2 client. + * + * @param string $name + * Name of the client. + * + * @return OAuth2\Client + * Returns an OAuth2\Client object + */ +function oauth2_client_load($name) { + $oauth2_clients = oauth2_client_get_all(); + + if (!isset($oauth2_clients[$name])) { + throw new Exception("No client with name '$name' is defined."); + } + $oauth2_client = new OAuth2\Client($oauth2_clients[$name], $name); + return $oauth2_client; +} + +/** + * Implements hook_menu(). + */ +function oauth2_client_menu() { + $items = array(); + $items['oauth2/authorized'] = array( + 'page callback' => 'oauth2_client_authorized', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + return $items; +} + +/** + * Callback for path oauth2/authorized. + * + * An authorized request in server-side flow + * will be redirected here (having variables + * 'code' and 'state'). + */ +function oauth2_client_authorized() { + // If there is any error in the server response, display it. + if (isset($_GET['error'])) { + $error = $_GET['error']; + $error_description = $_GET['error_description']; + drupal_set_message("Error: $error: $error_description", 'error'); + } + + // Redirect to the client that started the authentication. + OAuth2\Client::redirect($clean = FALSE); +} + +/** + * Return the redirect_uri of oauth2_client. + */ +function oauth2_client_get_redirect_uri() { + return url('oauth2/authorized', array('absolute' => TRUE)); +} + +/** + * Set a redirect request. + * + * This can be used by other oauth2 clients to integrate with + * oauth2_client, i.e. to use the same client that is registered + * on the server for the oauth2_client. + * + * The oauth2_server sends the authorization reply to the + * redirect_uri that is registered for the client, which is + * the one corresponding to oauth2_client. If another oauth2 + * client would like to get this authorization reply, it has + * to set a redirect request with this function, and then + * oauth2_client will forward the reply to it. + * + * @param string $state + * The random parameter that is used on the authentication url + * in order to mittigate CSRF attacks. In this case it is used + * as a key for identifying the authentication request. + * + * @param array $redirect + * Associative array that contains the keys: + * - 'uri': the uri of the oauth2 client that is requesting a redirect + * - 'params': associative array of other parameters that should be + * appended to the uri, along with the $_REQUEST + * + * Example: + * $state = md5(uniqid(rand(), TRUE)); + * $hybridauth_config['state'] = $state; + * $hybridauth_config['redirect_uri'] = oauth2_client_get_redirect_uri(); + * oauth2_client_set_redirect($state, array( + * 'uri' => 'hybridauth/endpoint', + * 'params' => array( + * 'hauth.done' => 'DrupalOAuth2', + * ) + * )); + */ +function oauth2_client_set_redirect($state, $redirect) { + OAuth2\Client::setRedirect($state, $redirect); +} + +/** + * Share an access token with oauth2_client. + * + * Another oauth2 client that has been successfully authenticated + * and has received an access_token, can share it with oauth2_client, + * so that oauth2_client does not have to repeat the authentication + * process again. + * + * Example: + * $client_id = $hybridauth->api->client_id; + * $token = array( + * 'access_token' => $hybridauth->api->access_token, + * 'refresh_token' => $hybridauth->api->refresh_token, + * 'expires_in' => $hybridauth->api->access_token_expires_in, + * 'expiration_time' => $hybridauth->api->access_token_expires_at, + * 'scope' => $hybridauth->scope, + * ); + * $token_endpoint = $oauth2->api->token_endpoint; + * $client_id = $oauth2->api->client_id; + * $auth_flow = 'server-side'; + * $id = md5($token_endpoint . $client_id . $auth_flow); + * oauth2_client_set_token($id, $token); + */ +function oauth2_client_set_token($id, $token) { + $_SESSION['oauth2_client']['token'][$id] = $token; +} + +/** + * Returns the access token of the oauth2_client with the given $id. + */ +function oauth2_client_get_token($id) { + if (isset($_SESSION['oauth2_client']['token'][$id])) { + return $_SESSION['oauth2_client']['token'][$id]; + } + else { + return array( + 'access_token' => NULL, + 'refresh_token' => NULL, + 'expires_in' => NULL, + 'expiration_time' => NULL, + 'scope' => NULL, + ); + } +} diff --git a/profiles/wcm_base/modules/contrib/oauth2_client/tests/oauth2_client.test b/profiles/wcm_base/modules/contrib/oauth2_client/tests/oauth2_client.test new file mode 100644 index 0000000000000000000000000000000000000000..643096c6f7088dc801e5d13651c4a3ee7639eb11 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/oauth2_client/tests/oauth2_client.test @@ -0,0 +1,129 @@ +<?php + +/** + * @file + * OAuth2 Client tests. + */ + +/** + * Test OAuth2 Client. + */ +class OAuth2ClientTestCase extends DrupalWebTestCase { + protected $profile = 'testing'; + + public static function getInfo() { + return array( + 'name' => 'OAuth2 Client', + 'description' => 'Tests basic OAuth2 Client functionality.', + 'group' => 'OAuth2', + ); + } + + public function setUp() { + parent::setUp(array('oauth2_client_test', 'libraries')); + } + + public function testGetAccessToken() { + $this->clientCredentialsFlow(); + $this->userPasswordFlow(); + $this->serverSideFlow(); + $this->clientIntegration(); + $this->errorCases(); + } + + /** + * Get and return a token from the given test client. + */ + protected function getToken($client) { + $result = $this->drupalGet('oauth2/test/' . $client); + $this->assertPattern('/^access_token: /', $result); + $token = str_replace('access_token: ', '', $result); + $token = trim($token); + $this->assertNotEqual($token, '', 'Token is not empty.'); + return $token; + } + + /** + * Test the client-credentials flow. + */ + public function clientCredentialsFlow() { + $token1 = $this->getToken('client-credentials'); + $token2 = $this->getToken('client-credentials'); + $this->assertEqual($token1, $token2, 'The same cached token is used, while it has not expired yet.'); + + sleep(10); // wait for the token to expire + $token3 = $this->getToken('client-credentials'); + $this->assertNotEqual($token1, $token3, 'Getting a new token, client-credential flow has no refresh token.'); + } + + /** + * Test the user-password flow. + */ + public function userPasswordFlow() { + $token1 = $this->getToken('user-password'); + $token2 = $this->getToken('user-password'); + $this->assertEqual($token1, $token2, 'The same cached token is used, while it has not expired yet.'); + + sleep(10); // wait for the token to expire + $token3 = $this->getToken('user-password'); + $this->assertNotEqual($token1, $token3, 'Getting a new token from refresh_token.'); + + sleep(30); // wait for the refresh_token to expire + $token4 = $this->getToken('user-password'); + } + + /** + * Test the server-side flow. + * + * For this test we are using 'client2' which has + * automatic authorization enabled. + */ + public function serverSideFlow() { + $user = (object) array('name' => 'user1', 'pass_raw' => 'pass1'); + $this->drupalLogin($user); + $token1 = $this->getToken('server-side-auto'); + $token2 = $this->getToken('server-side-auto'); + $this->assertEqual($token1, $token2, 'The same cached token is used, while it has not expired yet.'); + + sleep(10); // wait for the token to expire + $token3 = $this->getToken('server-side-auto'); + $this->assertNotEqual($token1, $token3, 'Getting a new token from refresh_token.'); + + sleep(30); // wait for the refresh_token to expire + $token4 = $this->getToken('server-side-auto'); + } + + /** + * Test client integration. + */ + public function clientIntegration() { + $result = $this->drupalGet('oauth2/test-client-integration'); + $this->assertText('access_token: '); + $this->assertText('extra_param: This will be appended to the request on redirect.'); + } + + /** + * Test error cases. + */ + public function errorCases() { + $error_cases = array( + 'wrong-client-id', + 'wrong-client-secret', + 'wrong-token-endpoint', + 'wrong-username', + 'wrong-password', + 'wrong-scope', + ); + foreach ($error_cases as $error_case) { + $this->drupalGet('oauth2/test/' . $error_case); + $this->assertText('Failed to get an access token'); + } + + // wrong-auth-flow + $this->drupalGet('oauth2/test/wrong-auth-flow'); + $this->assertText('Unknown authorization flow'); + + // wrong-authorization-endpoint + // wrong-redirect-uri + } +} diff --git a/profiles/wcm_base/modules/contrib/oauth2_client/tests/oauth2_client_test.info b/profiles/wcm_base/modules/contrib/oauth2_client/tests/oauth2_client_test.info new file mode 100644 index 0000000000000000000000000000000000000000..bea32ee9d8ec0afd89814adcaf3f12ca18b35de8 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/oauth2_client/tests/oauth2_client_test.info @@ -0,0 +1,14 @@ +name = OAuth2 Client Test +description = Testing OAuth2 client functionality. +package = "OAuth2" +core = 7.x + +dependencies[] = oauth2_client +dependencies[] = oauth2_server + +; Information added by Drupal.org packaging script on 2016-08-24 +version = "7.x-1.6" +core = "7.x" +project = "oauth2_client" +datestamp = "1472072657" + diff --git a/profiles/wcm_base/modules/contrib/oauth2_client/tests/oauth2_client_test.install b/profiles/wcm_base/modules/contrib/oauth2_client/tests/oauth2_client_test.install new file mode 100644 index 0000000000000000000000000000000000000000..611e16e7d6d03ab31651f52b0fee651f013cbd76 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/oauth2_client/tests/oauth2_client_test.install @@ -0,0 +1,160 @@ +<?php +/** + * @file + * Enable and disable hook functions. + */ + +/** + * Implements hook_enable(). + */ +function oauth2_client_test_enable() { + oauth2_client_test_disable(); + + _oauth2_client_test_create(); + _oauth2_client_test_grant_permissions(); +} + +/** + * Implements hook_disable(). + */ +function oauth2_client_test_disable() { + _oauth2_client_test_delete(); + //_oauth2_client_test_revoke_permissions(); +} + +/** + * Create a test server, along with test clients and scopes. + */ +function _oauth2_client_test_create() { + // Create the server and client. + $server = entity_create('oauth2_server', array()); + $server->name = 'test_oauth2_server'; + $server->label = 'Test'; + $server->settings = array( + 'default_scope' => 'scope1', + 'enforce_state' => TRUE, + 'allow_implicit' => TRUE, + 'require_exact_redirect_uri' => FALSE, + 'grant_types' => array( + 'authorization_code' => 'authorization_code', + 'client_credentials' => 'client_credentials', + 'refresh_token' => 'refresh_token', + 'password' => 'password', + ), + 'always_issue_new_refresh_token' => TRUE, + // For testing purposes, set short expire times. + 'access_lifetime' => 20, + 'refresh_token_lifetime' => 30, + ); + $server->save(); + + // Add a client. + $client = entity_create('oauth2_server_client', array()); + $client->server = $server->name; + $client->label = 'Client 1'; + $client->client_key = 'client1'; + $client->client_secret = 'secret1'; + $client->redirect_uri = url('oauth2/authorized', array('absolute' => TRUE)); + $client->automatic_authorization = FALSE; + $client->save(); + + // The second client has automatic_authorization TRUE. + $client = entity_create('oauth2_server_client', array()); + $client->server = $server->name; + $client->label = 'Client 2'; + $client->client_key = 'client2'; + $client->client_secret = 'secret2'; + $client->redirect_uri = url('oauth2/authorized', array('absolute' => TRUE)); + $client->automatic_authorization = TRUE; + $client->save(); + + // Creates some scopes. + $scopes = array( + 'scope1' => 'Scope 1', + 'scope2' => 'Scope 2', + ); + foreach ($scopes as $scope_name => $scope_label) { + $scope = entity_create('oauth2_server_scope', array()); + $scope->server = $server->name; + $scope->name = $scope_name; + $scope->description = $scope_label; + $scope->save(); + } + + // Create a test user. + user_save('', array( + 'name' => 'user1', + 'pass' => 'pass1', + 'status' => 1, + )); +} + +/** + * Delete test servers, clients and scopes. + */ +function _oauth2_client_test_delete() { + $server_name = 'test_oauth2_server'; + + // Delete the test clients. + $clients = array('client1', 'client2'); + foreach ($clients as $client_key) { + $query = new EntityFieldQuery(); + $clients = $query->entityCondition('entity_type', 'oauth2_server_client') + ->propertyCondition('client_key', $client_key) + ->execute(); + if (isset($clients['oauth2_server_client'])) { + $ids = array_keys($clients['oauth2_server_client']); + foreach ($ids as $id) { + entity_delete('oauth2_server_client', $id); + } + } + } + + // Delete the test scopes. + $scopes = array('scope1', 'scope2'); + foreach ($scopes as $scope_name) { + $query = new EntityFieldQuery(); + $scopes = $query->entityCondition('entity_type', 'oauth2_server_scope') + ->propertyCondition('name', $scope_name) + ->execute(); + if (isset($scopes['oauth2_server_scope'])) { + $ids = array_keys($scopes['oauth2_server_scope']); + foreach ($ids as $id) { + entity_delete('oauth2_server_scope', $id); + } + } + } + + // Delete the test oauth2 server. + $query = new EntityFieldQuery(); + $servers = $query->entityCondition('entity_type', 'oauth2_server') + ->propertyCondition('name', $server_name) + ->execute(); + if (isset($servers['oauth2_server'])) { + $ids = array_keys($servers['oauth2_server']); + foreach ($ids as $id) { + entity_delete('oauth2_server', $id); + } + } + + // Delete the test user. + if ($user = user_load_by_name('user1')) { + user_delete($user->uid); + } +} + +function _oauth2_client_test_grant_permissions() { + // Make sure that users have the permission to use the oauth2 server. + foreach (array('anonymous user', 'authenticated user') as $role_name) { + $role = user_role_load_by_name($role_name); + user_role_grant_permissions($role->rid, array('use oauth2 server')); + } +} + +function _oauth2_client_test_revoke_permissions() { + // Remove the permission for using the oauth2 server. + foreach (array('anonymous user', 'authenticated user') as $role_name) { + $role = user_role_load_by_name($role_name); + user_role_revoke_permissions($role->rid, array('use oauth2 server')); + } +} \ No newline at end of file diff --git a/profiles/wcm_base/modules/contrib/oauth2_client/tests/oauth2_client_test.module b/profiles/wcm_base/modules/contrib/oauth2_client/tests/oauth2_client_test.module new file mode 100644 index 0000000000000000000000000000000000000000..088fd929f2c0e623f4ce9013e6175cd01628f4e2 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/oauth2_client/tests/oauth2_client_test.module @@ -0,0 +1,253 @@ +<?php +/** + * @file + * Testing OAuth2 client functionality. + */ + +/** + * Implements hook_boot(). + * + * Outputs debug information to the file: /tmp/btr.log + */ +function oauth2_client_test_boot() { + function _oauth2_client_test_log($var, $comment ='') { + $file = '/tmp/btr.log'; + $content = "\n==> $comment: " . print_r($var, true); + file_put_contents($file, $content, FILE_APPEND); + } + + _oauth2_client_test_log('= = = = = = = = = = = = = = = = = = = = = = ='); + _oauth2_client_test_log($_GET, '$_GET'); + _oauth2_client_test_log($_POST, '$_POST'); + if (isset($_SESSION['oauth2_client'])) { + _oauth2_client_test_log($_SESSION['oauth2_client'], '$_SESSION[oauth2_client]'); + } +} + +/** + * Implements hook_oauth2_clients(). + */ +function oauth2_client_test_oauth2_clients() { + $oauth2_clients = array(); + + $common = array( + 'token_endpoint' => url('oauth2/token', array('absolute' => TRUE)), + 'client_id' => 'client1', + 'client_secret' => 'secret1', + ); + + // For testing client-credentials flow. + $oauth2_clients['client-credentials'] = array( + 'auth_flow' => 'client-credentials', + ) + $common; + + // For testing user-password flow. + $oauth2_clients['user-password'] = array( + 'auth_flow' => 'user-password', + 'username' => 'user1', + 'password' => 'pass1', + ) + $common; + + // For testing server-side flow. + $oauth2_clients['server-side'] = array( + 'auth_flow' => 'server-side', + 'authorization_endpoint' => url('oauth2/authorize', array('absolute' => TRUE)), + 'redirect_uri' => url('oauth2/authorized', array('absolute' => TRUE)), + 'scope' => 'scope1 scope2', + ) + $common; + + // For testing server-side flow with automatic authorization client.. + $oauth2_clients['server-side-auto'] = array( + 'token_endpoint' => url('oauth2/token', array('absolute' => TRUE)), + 'client_id' => 'client2', + 'client_secret' => 'secret2', + 'auth_flow' => 'server-side', + 'authorization_endpoint' => url('oauth2/authorize', array('absolute' => TRUE)), + 'redirect_uri' => url('oauth2/authorized', array('absolute' => TRUE)), + 'scope' => 'scope1 scope2', + ); + + // Test error handling. + + $oauth2_clients['wrong-client-id'] = array( + 'token_endpoint' => url('oauth2/token', array('absolute' => TRUE)), + 'client_id' => 'client_1', + 'client_secret' => 'secret1', + 'auth_flow' => 'client-credentials', + ); + + $oauth2_clients['wrong-client-secret'] = array( + 'token_endpoint' => url('oauth2/token', array('absolute' => TRUE)), + 'client_id' => 'client1', + 'client_secret' => 'secret_1', + 'auth_flow' => 'client-credentials', + ); + + $oauth2_clients['wrong-token-endpoint'] = array( + 'token_endpoint' => url('oauth2/token_1', array('absolute' => TRUE)), + 'client_id' => 'client1', + 'client_secret' => 'secret1', + 'auth_flow' => 'client-credentials', + ); + + $oauth2_clients['wrong-auth-flow'] = array( + 'auth_flow' => 'client-credentials-1', + ) + $common; + + $oauth2_clients['wrong-username'] = array( + 'auth_flow' => 'user-password', + 'username' => 'user_1', + 'password' => 'pass1', + ) + $common; + + $oauth2_clients['wrong-password'] = array( + 'auth_flow' => 'user-password', + 'username' => 'user1', + 'password' => 'pass_1', + ) + $common; + + $oauth2_clients['wrong-scope'] = array( + 'token_endpoint' => url('oauth2/token', array('absolute' => TRUE)), + 'client_id' => 'client1', + 'client_secret' => 'secret1', + 'auth_flow' => 'client-credentials', + 'scope' => 'scope1 scope2 scope3', + ) + $common; + + $oauth2_clients['wrong-authorization-endpoint'] = array( + 'auth_flow' => 'server-side', + 'authorization_endpoint' => url('oauth2/authorize_1', array('absolute' => TRUE)), + 'redirect_uri' => url('oauth2/authorized', array('absolute' => TRUE)), + ) + $common; + + $oauth2_clients['wrong-redirect-uri'] = array( + 'auth_flow' => 'server-side', + 'authorization_endpoint' => url('oauth2/authorize', array('absolute' => TRUE)), + 'redirect_uri' => url('oauth2/authorized_1', array('absolute' => TRUE)), + ) + $common; + + return $oauth2_clients; +} + +/** + * Implements hook_menu(). + */ +function oauth2_client_test_menu() { + $items = array(); + $items['oauth2/test'] = array( + 'page callback' => 'oauth2_client_test_callback', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + $items['oauth2/test-client-integration'] = array( + 'page callback' => 'oauth2_client_test_client_integration', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + $items['oauth2/test-authorized'] = array( + 'page callback' => 'oauth2_client_test_authorized', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + return $items; +} + +/** + * Trying test clients. + * + * Call them by opening in browser: + * - $base_url/oauth2/test/client-credentials + * - $base_url/oauth2/test/user-password + * - $base_url/oauth2/test/server-side + * - $base_url/oauth2/test/server-side-auto + * - $base_url/oauth2/test/wrong-client-id + * - $base_url/oauth2/test/wrong-client-secret + * - $base_url/oauth2/test/wrong-token-endpoint + * - $base_url/oauth2/test/wrong-auth-flow + * - $base_url/oauth2/test/wrong-username + * - $base_url/oauth2/test/wrong-password + * - $base_url/oauth2/test/wrong-scope + * - $base_url/oauth2/test/wrong-authorization-endpoint + * - $base_url/oauth2/test/wrong-redirect-uri + */ +function oauth2_client_test_callback($client_name) { + try { + // Get an access token and output it. + $oauth2_client = oauth2_client_load($client_name); + $access_token = $oauth2_client->getAccessToken(); + print "access_token: $access_token"; + } + catch (Exception $e) { + print $e->getMessage(); + } +} + +/** + * Use the client 'client2' for getting an authorization code. + * This is done with the help of the module oauth2_client, + * because 'client2' is registered for it (its return_uri belongs + * to oauth2_client). + * Before jumping to $authentication_uri, register an internal + * redirect with oauth2_client. + * + * Try it by opening in browser: + * - $base_url/oauth2/test-client-integration + */ +function oauth2_client_test_client_integration() { + $state = drupal_get_token('test_client'); + oauth2_client_set_redirect($state, array( + 'uri' => 'oauth2/test-authorized', + 'params' => array( + 'extra_param' => 'This will be appended to the request on redirect.', + ) + )); + + $query_params = array( + 'response_type' => 'code', + 'client_id' => 'client2', + 'redirect_uri' => oauth2_client_get_redirect_uri(), + 'state' => $state, + ); + $endpoint = url('oauth2/authorize', array('absolute' => TRUE)); + $authentication_uri = $endpoint . '?' . http_build_query($query_params); + drupal_goto($authentication_uri); +} + +/** + * The oauth2 server will redirect to the registered redirect_uri, + * which is handled by the oauth2_client, but then oauth2_client + * will redirect to the path 'oauth2/test/authorized', which comes + * here. This is because we registered a redirect on the oauth2_client + * before jumping to $authentication_uri. While redirecting, oauth2_client + * will also append to the request the 'extra_param'. + */ +function oauth2_client_test_authorized() { + if (!drupal_valid_token($_GET['state'], 'test_client')) { + print "The parameter 'state' is wrong.\n"; + return; + } + $extra_param = $_GET['extra_param']; + print "extra_param: $extra_param <br/>\n"; + + $options = array( + 'method' => 'POST', + 'data' => http_build_query(array( + 'grant_type' => 'authorization_code', + 'code' => $_GET['code'], + 'redirect_uri' => oauth2_client_get_redirect_uri(), + )), + 'headers' => array( + 'Content-Type' => 'application/x-www-form-urlencoded', + 'Authorization' => 'Basic ' . base64_encode('client2:secret2'), + ), + 'context' => stream_context_create(array( + 'ssl' => array( + 'verify_peer' => FALSE, + 'verify_peer_name' => FALSE, + ))); + ); + $token_endpoint = url('oauth2/token', array('absolute' => TRUE)); + $result = drupal_http_request($token_endpoint, $options); + $token = json_decode($result->data); + print 'access_token: ' . $token->access_token; +} diff --git a/profiles/wcm_base/modules/contrib/oauth2_client/tests/run_tests.sh b/profiles/wcm_base/modules/contrib/oauth2_client/tests/run_tests.sh new file mode 100755 index 0000000000000000000000000000000000000000..59045a29b4dd805e96ed9b9a3d3ec6652a10e02c --- /dev/null +++ b/profiles/wcm_base/modules/contrib/oauth2_client/tests/run_tests.sh @@ -0,0 +1,35 @@ +#!/bin/bash +### Create the links of the required modules and libraries +### on the profile 'testing', then run the tests. + +cd $(dirname $0) + +### get the paths +drupal_dir=$(drush php-eval 'print realpath(".")') +testing_dir=$drupal_dir/profiles/testing + +### list of the required modules (dependencies) +module_list=" + oauth2_client + oauth2_server + libraries + ctools + entity + entityreference + xautoload +" +### link the modules to the profile 'testing' +for module in $module_list +do + module_path=$(drush php-eval "print drupal_get_path('module', '$module')") + ln -sf $drupal_dir/$module_path $testing_dir/modules/ +done + +### link the required library oauth2-server-php +oauth2_server_php=$(drush php-eval 'print libraries_get_path("oauth2-server-php")') +mkdir -p $testing_dir/libraries/ +ln -sf $drupal_dir/$oauth2_server_php $testing_dir/libraries/ + +### run the tests +drush test-clean +drush test-run OAuth2ClientTestCase diff --git a/profiles/wcm_base/modules/contrib/search_api/CHANGELOG.txt b/profiles/wcm_base/modules/contrib/search_api/CHANGELOG.txt index 94ccad26a58100e7dbdcd458a45a171f7418d2f8..0084fe0dddcc00f04692dd04312c68658ea8d9a4 100644 --- a/profiles/wcm_base/modules/contrib/search_api/CHANGELOG.txt +++ b/profiles/wcm_base/modules/contrib/search_api/CHANGELOG.txt @@ -1,5 +1,80 @@ -Search API 1.x, dev (xxxx-xx-xx): ---------------------------------- +Search API 1.21 (2017-02-23): +----------------------------- +- #2780341 by Berdir: Fixed passing of custom ranges to date facets. +- #2765317 by JorgenSandstrom, NWOM, drunken monkey: Added a "Last" aggregation + type. +- #2842856 by drunken monkey: Fixed language filters for "Multiple types" + indexes. +- #2844990 by drunken monkey: Made the "Role filter" data alteration available + for multi-type indexes. +- #2837745 by drunken monkey, klausi: Fixed NULL tags on old serialized queries. +- #2833482 by drunken monkey: Fixed undefined constant when uninstalling facets + module. +- #2840261 by alan-ps: Fixed usage of outdated hash functions. +- #1670420 by kyletaylored, dorficus, drunken monkey: Fixed potential fatal + error in facet adapter's getSearchKeys() method. +- #2838075 by dsnopek: Fixed possible race condition in + hook_system_info_alter(). +- #2836687 by sarthak drupal: Fixed one doc comment typo. +- #2632880 by drunken monkey, donquixote: Added possibility to change indexed + bundles on disabled indexes. +- #2828380 by jansete: Fixed taxonomy term access tag in Views filter. +- #2827717 by Fabien.Godineau, drunken monkey: Fixed disabling of search views + when reverting an index. +- #2822836 by prince_zyxware: Fixed some Drupal coding standards violations. +- #2822145 by drunken monkey: Fixed problem with phrase search in Views + fulltext filter. +- #2778261 by drunken monkey, BAHbKA: Fixed "Index items immediately" + functionality for unindexed items. +- #2358065 by Jelle_S, graper, drunken monkey: Added the option for + highlighting of partial matches to the processor. +- #2779159 by mark_fullmer, drunken monkey: Added a Stemmer processor. +- #2649412 by relaxnow, GoZ: Added support for minimum granularity to date + facets. +- #2769021 by Plazik, drunken monkey: Added the generated Search API query to + the Views preview. +- #2769877 by mfernea: Fixed database exception when filtering for anonymous + user. + +Search API 1.20 (2016-07-21): +----------------------------- +- #2731103 by drunken monkey: Fixed the default value for the taxonomy term + filter "multiple" setting. +- #1818572 by morningtime, drunken monkey, lodey, guillaumev: Added pretty + paths support to the Views facets block. +- #2753441 by Johnny vd Laar: Fixed translated field names in + language-independent cache. + +Search API 1.19 (2016-07-05): +----------------------------- +- #2724687 by StefanPr, drunken monkey: Fixed failed sanitization of NULL field + values. +- #2744189 by nikolabintev, drunken monkey: Fixed highlighting for single-word + fields. +- #2744995 by John Cook, drunken monkey: Fixed search views without pager. +- #2742053 by tunic: Fixed change notification on node access records change. +- #2733447 by jsacksick: Fixed translatability of our Views taxonomy term + filter. +- #2720465 by drunken monkey: Fixed bundle filter's handling of entity types + with no bundles on multi-type indexes. +- #2710893 by alan-ps, drunken monkey: Fixed creation of comment indexes when + no nodes exist. +- #2707039 by alan-ps: Fixed indexes of flag entities with "bundles" setting. +- #2700879 by drunken monkey: Fixed breadcrumbs on index tabs. +- #1889940 by cspurk, Yaron Tal: Fixed "HTML filter" processor to recognize all + valid HTML tags. +- #2700011 by drunken monkey: Fixed compatibility issues of facets from + different indexes. +- #2665970 by andrei.colesnic, drunken monkey: Added "Limit list to selected + items" exposed option support for Views taxonomy term filters. +- #2703675 by drunken monkey, heykarthikwithu: Fixed accidental assumption that + all facets are taxonomy terms. +- #2419853 by drunken monkey: Fixed HTML filter leaves escaped entities in + field values sometimes. + +Search API 1.18 (2016-04-20): +----------------------------- +- Various security fixes – see https://www.drupal.org/node/2710063. - #2693425 by jojyja: Fixed a typo in search_api.info. Search API 1.17 (2016-03-14): diff --git a/profiles/wcm_base/modules/contrib/search_api/README.txt b/profiles/wcm_base/modules/contrib/search_api/README.txt index 2e2f581fd732913a3420974c94b2b0a60fac1e0b..3943ceec5b81095d58d6c927dd7eadaed37b2d1c 100644 --- a/profiles/wcm_base/modules/contrib/search_api/README.txt +++ b/profiles/wcm_base/modules/contrib/search_api/README.txt @@ -385,6 +385,10 @@ Included components Enables the admin to specify a stopwords file, the words contained in which will be filtered out of the text data indexed. This can be used to exclude too common words from indexing, for servers not supporting this natively. + * Stem words + Uses the PorterStemmer method to reduce words to stems. A search for + "garden" will return results for "gardening" and "garden," as will a search + for "gardening." - Additional modules diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/plugins/facetapi/adapter.inc b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/plugins/facetapi/adapter.inc index a10db9c0758f0f97d288cd40c255bed142554a07..a5b5cdc0ffa3d5ecd40bff6e466d9f1a0edca192 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/plugins/facetapi/adapter.inc +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/plugins/facetapi/adapter.inc @@ -61,6 +61,10 @@ class SearchApiFacetapiAdapter extends FacetapiAdapter { public function initActiveFilters($query) { $search_id = $query->getOption('search id'); $index_id = $this->info['instance']; + // Only act on queries from the right index. + if ($index_id != $query->getIndex()->machine_name) { + return; + } $facets = facetapi_get_enabled_facets($this->info['name']); $this->fields = array(); @@ -83,13 +87,16 @@ class SearchApiFacetapiAdapter extends FacetapiAdapter { if (array_search($search_id, $facet_search_ids) === FALSE) { if (!$default_true) { - continue; // We are only to show facets for explicitly named search ids. + // We are only to show facets for explicitly named search ids. + continue; } } elseif ($default_true) { - continue; // The 'facet_search_ids' in the settings are to be excluded. + // The 'facet_search_ids' in the settings are to be excluded. + continue; } - $active[$facet['name']] = $search_id; + $facet_key = $facet['name'] . '@' . $this->getSearcher(); + $active[$facet_key] = $search_id; $this->fields[$facet['name']] = array( 'field' => $facet['field'], 'limit' => $options['hard_limit'], @@ -185,6 +192,12 @@ class SearchApiFacetapiAdapter extends FacetapiAdapter { */ public function getSearchKeys() { $search = $this->getCurrentSearch(); + + // If the search is empty then there's no reason to continue. + if (!$search) { + return NULL; + } + $keys = $search[0]->getOriginalKeys(); if (is_array($keys)) { // This will happen nearly never when displaying the search keys to the @@ -274,10 +287,24 @@ class SearchApiFacetapiAdapter extends FacetapiAdapter { // Date facets don't support the "OR" operator (for now). $form['global']['operator']['#access'] = FALSE; + + $default_value = FACETAPI_DATE_YEAR; + if (isset($options['date_granularity_min'])) { + $default_value = $options['date_granularity_min']; + } + $form['global']['date_granularity_min'] = array( + '#type' => 'select', + '#title' => t('Minimum granularity'), + '#description' => t('Determine the minimum drill-down level to start at'), + '#prefix' => '<div class="facetapi-global-setting">', + '#suffix' => '</div>', + '#options' => $granularity_options, + '#default_value' => $default_value, + ); } // Add an "Exclude" option for terms. - if(!empty($facet['query types']) && in_array('term', $facet['query types'])) { + if (!empty($facet['query types']) && in_array('term', $facet['query types'])) { $form['global']['operator']['#weight'] = -2; unset($form['global']['operator']['#suffix']); $form['global']['exclude'] = array( diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/plugins/facetapi/query_type_date.inc b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/plugins/facetapi/query_type_date.inc index 4042fdfd8f57f2f057aff4084961fc88783051eb..6aeb83624402c9fb6056de342f203005d8e2052e 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/plugins/facetapi/query_type_date.inc +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/plugins/facetapi/query_type_date.inc @@ -76,7 +76,7 @@ class SearchApiFacetapiDate extends SearchApiFacetapiTerm implements FacetapiQue */ protected function createRangeFilter($value) { // Ignore any filters passed directly from the server (range or missing). - if (!$value || $value == '!' || (!ctype_digit($value[0]) && preg_match('/^[\[(][^ ]+ [^ ]+[])]$/', $value))) { + if (!$value || $value == '!' || (!ctype_digit($value[0]) && preg_match('/^[\[(][^ ]+ TO [^ ]+[\])]$/', $value))) { return $value ? $value : NULL; } @@ -210,10 +210,11 @@ class SearchApiFacetapiDate extends SearchApiFacetapiTerm implements FacetapiQue public function build() { $facet = $this->adapter->getFacet($this->facet); $search_ids = drupal_static('search_api_facetapi_active_facets', array()); - if (empty($search_ids[$facet['name']]) || !search_api_current_search($search_ids[$facet['name']])) { + $facet_key = $facet['name'] . '@' . $this->adapter->getSearcher(); + if (empty($search_ids[$facet_key]) || !search_api_current_search($search_ids[$facet_key])) { return array(); } - $search_id = $search_ids[$facet['name']]; + $search_id = $search_ids[$facet_key]; $build = array(); $search = search_api_current_search($search_id); $results = $search[1]; @@ -244,9 +245,19 @@ class SearchApiFacetapiDate extends SearchApiFacetapiTerm implements FacetapiQue } } - // Get the finest level of detail we're allowed to drill down to. $settings = $facet->getSettings()->settings; - $max_granularity = isset($settings['date_granularity']) ? $settings['date_granularity'] : FACETAPI_DATE_MINUTE; + + // Get the finest level of detail we're allowed to drill down to. + $max_granularity = FACETAPI_DATE_MINUTE; + if (isset($settings['date_granularity'])) { + $max_granularity = $settings['date_granularity']; + } + + // Get the coarsest level of detail we're allowed to start at. + $min_granularity = FACETAPI_DATE_YEAR; + if (isset($settings['date_granularity_min'])) { + $min_granularity = $settings['date_granularity_min']; + } // Gets active facets, starts building hierarchy. $parent = $granularity = NULL; @@ -300,11 +311,14 @@ class SearchApiFacetapiDate extends SearchApiFacetapiTerm implements FacetapiQue FACETAPI_DATE_MINUTE => 2, FACETAPI_DATE_SECOND => 1, ); - // Gets gap numbers for both the gap and minimum gap, checks if the gap - // is within the limit set by the $granularity parameter. + // Gets gap numbers for both the gap, minimum and maximum gap, checks if + // the gap is within the limit set by the $granularity parameters. if ($gap_numbers[$granularity] < $gap_numbers[$max_granularity]) { $granularity = $max_granularity; } + if ($gap_numbers[$granularity] > $gap_numbers[$min_granularity]) { + $granularity = $min_granularity; + } } else { $granularity = $max_granularity; diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/plugins/facetapi/query_type_term.inc b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/plugins/facetapi/query_type_term.inc index d17721f440914123c1cd54a4e1408ed9cfc0cbfb..64d797a72f81aa945a069c0e673f6531e522018a 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/plugins/facetapi/query_type_term.inc +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/plugins/facetapi/query_type_term.inc @@ -57,21 +57,27 @@ class SearchApiFacetapiTerm extends FacetapiQueryType implements FacetapiQueryTy // When the operator is OR, remove parent terms from the active ones if // children are active. If we don't do this, sending a term and its // parent will produce the same results as just sending the parent. - if ($settings['flatten'] == '0') { + if (is_callable($this->facet['hierarchy callback']) && !$settings['flatten']) { // Check the filters in reverse order, to avoid checking parents that // will afterwards be removed anyways. - foreach (array_reverse(array_keys($active)) as $filter) { + $values = array_keys($active); + $parents = call_user_func($this->facet['hierarchy callback'], $values); + foreach (array_reverse($values) as $filter) { // Skip this filter if it was already removed, or if it is the // "missing value" filter ("!"). if (!isset($active[$filter]) || !is_numeric($filter)) { continue; } - $parents = taxonomy_get_parents_all($filter); - // The return value of taxonomy_get_parents_all() includes the term - // itself at index 0. Remove that to only get the term's ancestors. - unset($parents[0]); - foreach ($parents as $parent) { - unset($active[$parent->tid]); + // Go through the entire hierarchy of the value and remove all its + // ancestors. + while (!empty($parents[$filter])) { + $ancestor = array_shift($parents[$filter]); + if (isset($active[$ancestor])) { + unset($active[$ancestor]); + if (!empty($parents[$ancestor])) { + $parents[$filter] = array_merge($parents[$filter], $parents[$ancestor]); + } + } } } } @@ -165,10 +171,11 @@ class SearchApiFacetapiTerm extends FacetapiQueryType implements FacetapiQueryTy // initActiveFilters) so that we can retrieve it here and get the correct // current search for this facet. $search_ids = drupal_static('search_api_facetapi_active_facets', array()); - if (empty($search_ids[$facet['name']]) || !search_api_current_search($search_ids[$facet['name']])) { + $facet_key = $facet['name'] . '@' . $this->adapter->getSearcher(); + if (empty($search_ids[$facet_key]) || !search_api_current_search($search_ids[$facet_key])) { return array(); } - $search_id = $search_ids[$facet['name']]; + $search_id = $search_ids[$facet_key]; list(, $results) = search_api_current_search($search_id); $build = array(); diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/search_api_facetapi.info b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/search_api_facetapi.info index 4aea9aa78f0123a5b80c06b2c205b7dbb39ca850..022eefc0ee0bfe75d82d1558485856290db27af1 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/search_api_facetapi.info +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/search_api_facetapi.info @@ -9,9 +9,9 @@ files[] = plugins/facetapi/adapter.inc files[] = plugins/facetapi/query_type_term.inc files[] = plugins/facetapi/query_type_date.inc -; Information added by Drupal.org packaging script on 2016-04-20 -version = "7.x-1.18" +; Information added by Drupal.org packaging script on 2017-02-23 +version = "7.x-1.21" core = "7.x" project = "search_api" -datestamp = "1461155351" +datestamp = "1487844493" diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/search_api_facetapi.install b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/search_api_facetapi.install index 5743e08000bc0c7045a27b06d814d2389858bcac..77c0802605c1f1b482fd62e85e3470151a7b49ea 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/search_api_facetapi.install +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_facetapi/search_api_facetapi.install @@ -22,12 +22,14 @@ function search_api_facetapi_install() { */ function search_api_facetapi_uninstall() { variable_del('search_api_facets_search_ids'); - variable_del('date_format_search_api_facetapi_' . FACETAPI_DATE_YEAR); - variable_del('date_format_search_api_facetapi_' . FACETAPI_DATE_MONTH); - variable_del('date_format_search_api_facetapi_' . FACETAPI_DATE_DAY); - variable_del('date_format_search_api_facetapi_' . FACETAPI_DATE_HOUR); - variable_del('date_format_search_api_facetapi_' . FACETAPI_DATE_MINUTE); - variable_del('date_format_search_api_facetapi_' . FACETAPI_DATE_SECOND); + // We have to use the literal values here, as the Facet API module could have + // already been disabled at this point. + variable_del('date_format_search_api_facetapi_YEAR'); + variable_del('date_format_search_api_facetapi_MONTH'); + variable_del('date_format_search_api_facetapi_DAY'); + variable_del('date_format_search_api_facetapi_HOUR'); + variable_del('date_format_search_api_facetapi_MINUTE'); + variable_del('date_format_search_api_facetapi_SECOND'); } /** diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/display_facet_block.inc b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/display_facet_block.inc index 35ad14f54131409111a31ac819c9d40f3951fe0c..00e80c2936b64b255157a816f813414eb72a75c4 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/display_facet_block.inc +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/display_facet_block.inc @@ -151,7 +151,7 @@ class SearchApiViewsFacetsBlockDisplay extends views_plugin_display_block { } } - public function query(){ + public function query() { parent::query(); $facet_field = $this->get_option('facet_field'); @@ -247,6 +247,31 @@ class SearchApiViewsFacetsBlockDisplay extends views_plugin_display_block { ), ); + // Override the $variables['#path'] if facetapi_pretty_paths is enabled. + if (module_exists('facetapi_pretty_paths')) { + // Get the appropriate facet adapter. + $adapter = facetapi_adapter_load('search_api@' . $index->machine_name); + + // Get the URL processor and check if it uses pretty paths. + $urlProcessor = $adapter->getUrlProcessor(); + if ($urlProcessor instanceof FacetapiUrlProcessorPrettyPaths) { + // Retrieve the pretty path alias from the URL processor. + $facet = facetapi_facet_load($facet_field, 'search_api@' . $index->machine_name); + $values = array(trim($term['filter'], '"')); + + // Get the pretty path for the facet and remove the current search's + // base path from it. + $base_path_current = $urlProcessor->getBasePath(); + $pretty_path = $urlProcessor->getFacetPath($facet, $values, FALSE); + $pretty_path = str_replace($base_path_current, '', $pretty_path); + + // Set the new, pretty path for the facet and remove the "f" query + // parameter. + $variables['path'] = $variables['path'] . $pretty_path; + unset($variables['options']['query']['f']); + } + } + // Themes the link, adds row to facets. $facets[] = array( 'class' => array('leaf'), @@ -266,7 +291,7 @@ class SearchApiViewsFacetsBlockDisplay extends views_plugin_display_block { ); } - public function execute(){ + public function execute() { $info['content'] = $this->render(); $info['content']['more'] = $this->render_more_link(); $info['subject'] = filter_xss_admin($this->view->get_title()); diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_entity.inc b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_entity.inc index ffae8ad44ef26610ec27d82c96415bbea015dbbf..ce5c753dd93d068167e0bcd07f0663df8c1a96ba 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_entity.inc +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_entity.inc @@ -67,17 +67,6 @@ abstract class SearchApiViewsHandlerFilterEntity extends SearchApiViewsHandlerFi return $operators; } - /** - * {@inheritdoc} - */ - public function option_definition() { - $options = parent::option_definition(); - - $options['expose']['multiple']['default'] = TRUE; - - return $options; - } - /** * {@inheritdoc} */ diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_fulltext.inc b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_fulltext.inc index de61c9bf77e6643aee0b786e9c2a30a1ed9ef9dc..320adc363c0104921b647e1cfb389c3da1da6410 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_fulltext.inc +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_fulltext.inc @@ -119,7 +119,17 @@ class SearchApiViewsHandlerFilterFulltext extends SearchApiViewsHandlerFilterTex } $words = preg_split('/\s+/', $input); + $quoted = FALSE; foreach ($words as $i => $word) { + // Protect quoted strings. + if ($quoted && $word[strlen($word) - 1] === '"') { + $quoted = FALSE; + continue; + } + if ($quoted || $word[0] === '"') { + $quoted = TRUE; + continue; + } if (drupal_strlen($word) < $this->options['min_length']) { unset($words[$i]); } diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_taxonomy_term.inc b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_taxonomy_term.inc index efa685afce95332cd9dc1d8a07c94371449e1065..f3317cfa154edc5eba0cbbf3e71a15f7208a12e0 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_taxonomy_term.inc +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_taxonomy_term.inc @@ -27,6 +27,7 @@ class SearchApiViewsHandlerFilterTaxonomyTerm extends SearchApiViewsHandlerFilte $options['type'] = array('default' => !empty($this->definition['vocabulary']) ? 'textfield' : 'select'); $options['hierarchy'] = array('default' => 0); + $options['expose']['contains']['reduce'] = array('default' => FALSE); $options['error_message'] = array('default' => TRUE, 'bool' => TRUE); return $options; @@ -72,13 +73,13 @@ class SearchApiViewsHandlerFilterTaxonomyTerm extends SearchApiViewsHandlerFilte } else { if ($vocabulary && !empty($this->options['hierarchy'])) { - $tree = taxonomy_get_tree($vocabulary->vid); + $tree = taxonomy_get_tree($vocabulary->vid, 0, NULL, TRUE); $options = array(); if ($tree) { foreach ($tree as $term) { $choice = new stdClass(); - $choice->option = array($term->tid => str_repeat('-', $term->depth) . $term->name); + $choice->option = array($term->tid => str_repeat('-', $term->depth) . check_plain(entity_label('taxonomy_term', $term))); $options[] = $choice; } } @@ -92,13 +93,20 @@ class SearchApiViewsHandlerFilterTaxonomyTerm extends SearchApiViewsHandlerFilte $query->orderby('tv.name'); $query->orderby('td.weight'); $query->orderby('td.name'); - $query->addTag('term_access'); + $query->addTag('taxonomy_term_access'); if ($vocabulary) { $query->condition('tv.machine_name', $vocabulary->machine_name); } $result = $query->execute(); + $tids = array(); + foreach ($result as $term) { - $options[$term->tid] = $term->name; + $tids[] = $term->tid; + } + $terms = taxonomy_term_load_multiple($tids); + + foreach ($terms as $term) { + $options[$term->tid] = check_plain(entity_label('taxonomy_term', $term)); } } @@ -229,6 +237,14 @@ class SearchApiViewsHandlerFilterTaxonomyTerm extends SearchApiViewsHandlerFilte parent::exposed_validate($form, $form_state); } + /** + * {@inheritdoc} + */ + public function expose_options() { + parent::expose_options(); + $this->options['expose']['reduce'] = FALSE; + } + /** * {@inheritdoc} */ @@ -256,7 +272,7 @@ class SearchApiViewsHandlerFilterTaxonomyTerm extends SearchApiViewsHandlerFilte if (!empty($this->definition['vocabulary'])) { $query->condition('tv.machine_name', $this->definition['vocabulary']); } - $query->addTag('term_access'); + $query->addTag('taxonomy_term_access'); $result = $query->execute(); foreach ($result as $term) { unset($missing[strtolower($term->name)]); @@ -282,15 +298,23 @@ class SearchApiViewsHandlerFilterTaxonomyTerm extends SearchApiViewsHandlerFilte */ public function expose_form(&$form, &$form_state) { parent::expose_form($form, $form_state); - if ($this->options['type'] != 'select') { - unset($form['expose']['reduce']); + + if ($this->options['type'] == 'select') { + $form['expose']['reduce'] = array( + '#type' => 'checkbox', + '#title' => t('Limit list to selected items'), + '#description' => t('If checked, the only items presented to the user will be the ones selected here.'), + '#default_value' => $this->options['expose']['reduce'], + ); + } + else { + $form['error_message'] = array( + '#type' => 'checkbox', + '#title' => t('Display error message'), + '#description' => t('Display an error message if one of the entered terms could not be found.'), + '#default_value' => $this->options['error_message'], + ); } - $form['error_message'] = array( - '#type' => 'checkbox', - '#title' => t('Display error message'), - '#description' => t('Display an error message if one of the entered terms could not be found.'), - '#default_value' => !empty($this->options['error_message']), - ); } /** diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_user.inc b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_user.inc index a2ef3ea23bfd574f5a861f11edd8fd0270c658d6..6255274f28d8c93302de6b112899e1487abb44b3 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_user.inc +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/handler_filter_user.inc @@ -29,8 +29,10 @@ class SearchApiViewsHandlerFilterUser extends SearchApiViewsHandlerFilterEntity protected function ids_to_strings(array $ids) { $names = array(); $args[':uids'] = array_filter($ids); - $result = db_query("SELECT uid, name FROM {users} u WHERE uid IN (:uids)", $args); - $result = $result->fetchAllKeyed(); + if ($args[':uids']) { + $result = db_query('SELECT uid, name FROM {users} u WHERE uid IN (:uids)', $args); + $result = $result->fetchAllKeyed(); + } foreach ($ids as $uid) { if (!$uid) { $names[] = variable_get('anonymous', t('Anonymous')); diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/plugin_cache.inc b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/plugin_cache.inc index 5e0dff34851037f96409e0d92df419ba9869691b..c6bd41d45934c31e3d2aedd6021120240ffe427d 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/plugin_cache.inc +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/plugin_cache.inc @@ -103,7 +103,7 @@ class SearchApiViewsCache extends views_plugin_cache_time { $key_data['exposed_info'] = $_GET['exposed_info']; } } - $key = md5(serialize($key_data)); + $key = drupal_hash_base64(serialize($key_data)); return $key; } diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/query.inc b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/query.inc index 8ac6f2c66e4916464af23f90774c8df07f5efd80..4394c5f336c2edb83807831c5dd8e7541f3e10cc 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/query.inc +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/includes/query.inc @@ -310,6 +310,9 @@ class SearchApiViewsQuery extends views_plugin_query { if (!empty($this->view->override_path) && strpos(current_path(), $this->view->override_path) !== 0) { $this->query->setOption('search_api_base_path', $this->view->override_path); } + + // Save query information for Views UI. + $view->build_info['query'] = (string) $this->query; } /** @@ -344,13 +347,15 @@ class SearchApiViewsQuery extends views_plugin_query { // FALSE. $skip_result_count = $this->query->getOption('skip result count', TRUE); if ($skip_result_count) { - $skip_result_count = !$this->pager->use_count_query() && empty($view->get_total_rows); + $skip_result_count = !$this->pager || (!$this->pager->use_count_query() && empty($view->get_total_rows)); $this->query->setOption('skip result count', $skip_result_count); } try { // Trigger pager pre_execute(). - $this->pager->pre_execute($this->query); + if ($this->pager) { + $this->pager->pre_execute($this->query); + } // Views passes sometimes NULL and sometimes the integer 0 for "All" in a // pager. If set to 0 items, a string "0" is passed. Therefore, we unset @@ -385,7 +390,9 @@ class SearchApiViewsQuery extends views_plugin_query { $view->execute_time = microtime(TRUE) - $start; // Trigger pager post_execute(). - $this->pager->post_execute($view->result); + if ($this->pager) { + $this->pager->post_execute($view->result); + } } catch (Exception $e) { $this->errors[] = $e->getMessage(); diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/search_api_views.info b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/search_api_views.info index ba759236e087ea78b251b61e67626ee6e2a5e91b..2ba7ccaa2f1689e50f7ff87433358cb3d34fe69f 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/search_api_views.info +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/search_api_views.info @@ -27,9 +27,9 @@ files[] = includes/handler_sort.inc files[] = includes/plugin_cache.inc files[] = includes/query.inc -; Information added by Drupal.org packaging script on 2016-04-20 -version = "7.x-1.18" +; Information added by Drupal.org packaging script on 2017-02-23 +version = "7.x-1.21" core = "7.x" project = "search_api" -datestamp = "1461155351" +datestamp = "1487844493" diff --git a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/search_api_views.module b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/search_api_views.module index 8a131c2a65b9eedf132fb35c428e14b5014c8b78..62fcb944acdf7d6200010cd78b7d723b2f7d917a 100644 --- a/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/search_api_views.module +++ b/profiles/wcm_base/modules/contrib/search_api/contrib/search_api_views/search_api_views.module @@ -45,7 +45,10 @@ function search_api_views_search_api_index_update(SearchApiIndex $index) { * Implements hook_search_api_index_delete(). */ function search_api_views_search_api_index_delete(SearchApiIndex $index) { - _search_api_views_index_unavailable($index); + // Only do this if this is a "real" deletion, no revert. + if (!$index->hasStatus(ENTITY_IN_CODE)) { + _search_api_views_index_unavailable($index); + } } /** diff --git a/profiles/wcm_base/modules/contrib/search_api/includes/callback.inc b/profiles/wcm_base/modules/contrib/search_api/includes/callback.inc index ea161fbd38bdb94054ac8f8166b43160da41c475..617aee37a5ccdfcb269b72b4959c3d2f7ea1f7b4 100644 --- a/profiles/wcm_base/modules/contrib/search_api/includes/callback.inc +++ b/profiles/wcm_base/modules/contrib/search_api/includes/callback.inc @@ -182,4 +182,19 @@ abstract class SearchApiAbstractAlterCallback implements SearchApiAlterCallbackI return array(); } + /** + * Determines whether the given index contains multiple types of entities. + * + * @param SearchApiIndex|null $index + * (optional) The index to examine. Defaults to the index set for this + * plugin. + * + * @return bool + * TRUE if the index is a multi-entity index, FALSE otherwise. + */ + protected function isMultiEntityIndex(SearchApiIndex $index = NULL) { + $index = $index ? $index : $this->index; + return $index->datasource() instanceof SearchApiCombinedEntityDataSourceController; + } + } diff --git a/profiles/wcm_base/modules/contrib/search_api/includes/callback_add_aggregation.inc b/profiles/wcm_base/modules/contrib/search_api/includes/callback_add_aggregation.inc index 9535be3c56f62184f324a1bb72e0f93e4f9e5082..069c4107375cc034f69fe331ea744534bfdef508 100644 --- a/profiles/wcm_base/modules/contrib/search_api/includes/callback_add_aggregation.inc +++ b/profiles/wcm_base/modules/contrib/search_api/includes/callback_add_aggregation.inc @@ -209,6 +209,8 @@ class SearchApiAlterAddAggregation extends SearchApiAbstractAlterCallback { return $a; } return drupal_substr($b, 0, 1); + case 'last': + return isset($b) ? $b : $a; case 'list': if (!isset($a)) { $a = array(); @@ -288,6 +290,7 @@ class SearchApiAlterAddAggregation extends SearchApiAbstractAlterCallback { 'min' => t('Minimum'), 'first' => t('First'), 'first_char' => t('First letter'), + 'last' => t('Last'), 'list' => t('List'), ); case 'type': @@ -299,6 +302,7 @@ class SearchApiAlterAddAggregation extends SearchApiAbstractAlterCallback { 'min' => 'integer', 'first' => 'string', 'first_char' => 'string', + 'last' => 'string', 'list' => 'list<string>', ); case 'description': @@ -310,6 +314,7 @@ class SearchApiAlterAddAggregation extends SearchApiAbstractAlterCallback { 'min' => t('The Minimum aggregation computes the numerically smallest contained field value.'), 'first' => t('The First aggregation will simply keep the first encountered field value. This is helpful foremost when you know that a list field will only have a single value.'), 'first_char' => t('The "First letter" aggregation uses just the first letter of the first encountered field value as the aggregated value. This can, for example, be used to build a Glossary view.'), + 'last' => t('The Last aggregation will simply keep the last encountered field value.'), 'list' => t('The List aggregation collects all field values into a multi-valued field containing all values.'), ); } diff --git a/profiles/wcm_base/modules/contrib/search_api/includes/callback_bundle_filter.inc b/profiles/wcm_base/modules/contrib/search_api/includes/callback_bundle_filter.inc index 50a9dc9fb7b7fa990f919e521aa42f501229bee8..cde8fe27d1ce01d89b0eebcfbdb5c45d9e699ed2 100644 --- a/profiles/wcm_base/modules/contrib/search_api/includes/callback_bundle_filter.inc +++ b/profiles/wcm_base/modules/contrib/search_api/includes/callback_bundle_filter.inc @@ -34,7 +34,8 @@ class SearchApiAlterBundleFilter extends SearchApiAbstractAlterCallback { return; } - if ($this->isMultiEntityIndex()) { + $multi_entity = $this->isMultiEntityIndex(); + if ($multi_entity) { $bundle_prop = 'item_bundle'; } else { @@ -46,6 +47,10 @@ class SearchApiAlterBundleFilter extends SearchApiAbstractAlterCallback { $default = (bool) $this->options['default']; foreach ($items as $id => $item) { + // Ignore types that have no bundles. + if ($multi_entity && !self::hasBundles(entity_get_info($item->item_type))) { + continue; + } if (isset($bundles[$item->$bundle_prop]) == $default) { unset($items[$id]); } @@ -127,19 +132,4 @@ class SearchApiAlterBundleFilter extends SearchApiAbstractAlterCallback { return !empty($entity_info['entity keys']['bundle']) && !empty($entity_info['bundles']); } - /** - * Determines whether the given index contains multiple types of entities. - * - * @param SearchApiIndex|null $index - * (optional) The index to examine. Defaults to the index set for this - * plugin. - * - * @return bool - * TRUE if the index is a multi-entity index, FALSE otherwise. - */ - protected function isMultiEntityIndex(SearchApiIndex $index = NULL) { - $index = $index ? $index : $this->index; - return $index->datasource() instanceof SearchApiCombinedEntityDataSourceController; - } - } diff --git a/profiles/wcm_base/modules/contrib/search_api/includes/callback_role_filter.inc b/profiles/wcm_base/modules/contrib/search_api/includes/callback_role_filter.inc index ba126d1f86eff50d61ce643e693bce6158ef8092..68b8d72205d1ed4f25514d2c33ae081fc738137e 100644 --- a/profiles/wcm_base/modules/contrib/search_api/includes/callback_role_filter.inc +++ b/profiles/wcm_base/modules/contrib/search_api/includes/callback_role_filter.inc @@ -16,6 +16,9 @@ class SearchApiAlterRoleFilter extends SearchApiAbstractAlterCallback { * This plugin only supports indexes containing users. */ public function supportsIndex(SearchApiIndex $index) { + if ($this->isMultiEntityIndex($index)) { + return in_array('user', $index->options['datasource']['types']); + } return $index->getEntityType() == 'user'; } @@ -23,10 +26,20 @@ class SearchApiAlterRoleFilter extends SearchApiAbstractAlterCallback { * Implements SearchApiAlterCallbackInterface::alterItems(). */ public function alterItems(array &$items) { - $roles = $this->options['roles']; + $selected_roles = $this->options['roles']; $default = (bool) $this->options['default']; - foreach ($items as $id => $account) { - $role_match = (count(array_diff_key($account->roles, $roles)) !== count($account->roles)); + $multi_types = $this->isMultiEntityIndex($this->index); + foreach ($items as $id => $item) { + if ($multi_types) { + if ($item->item_type !== 'user') { + continue; + } + $item_roles = $item->user->roles; + } + else { + $item_roles = $item->roles; + } + $role_match = (count(array_diff_key($item_roles, $selected_roles)) !== count($item_roles)); if ($role_match === $default) { unset($items[$id]); } diff --git a/profiles/wcm_base/modules/contrib/search_api/includes/datasource.inc b/profiles/wcm_base/modules/contrib/search_api/includes/datasource.inc index eec9a79cc60a86b1e24f39437153336ee267c625..9661092c4ef7d6c35a04c26250aff3187ebec604 100644 --- a/profiles/wcm_base/modules/contrib/search_api/includes/datasource.inc +++ b/profiles/wcm_base/modules/contrib/search_api/includes/datasource.inc @@ -626,8 +626,7 @@ abstract class SearchApiAbstractDataSourceController implements SearchApiDataSou return NULL; } - $ret = array(); - + $indexes_by_id = array(); foreach ($indexes as $index) { $this->checkIndex($index); $update = db_update($this->table) @@ -639,12 +638,26 @@ abstract class SearchApiAbstractDataSourceController implements SearchApiDataSou if ($item_ids !== FALSE) { $update->condition($this->itemIdColumn, $item_ids, 'IN'); } - if ($update->execute()) { - $ret[] = $index; - } + $update->execute(); + $indexes_by_id[$index->id] = $index; } - return $ret; + // Determine and return the indexes with any changed items. If $item_ids is + // FALSE, all items are marked as changed and, thus, all indexes will be + // affected (unless they don't have any items, but no real point in treating + // that special case). + if ($item_ids !== FALSE) { + $indexes_with_items = db_select($this->table, 't') + ->fields('t', array($this->indexIdColumn)) + ->distinct() + ->condition($this->indexIdColumn, array_keys($indexes_by_id), 'IN') + ->condition($this->itemIdColumn, $item_ids, 'IN') + ->execute() + ->fetchCol(); + return array_intersect_key($indexes_by_id, array_flip($indexes_with_items)); + } + + return NULL; } /** @@ -715,7 +728,7 @@ abstract class SearchApiAbstractDataSourceController implements SearchApiDataSou } $this->checkIndex($index); $select = db_select($this->table, 't'); - $select->addField('t', 'item_id'); + $select->addField('t', $this->itemIdColumn); $select->condition($this->indexIdColumn, $index->id); $select->condition($this->changedColumn, 0, '>'); $select->orderBy($this->changedColumn, 'ASC'); diff --git a/profiles/wcm_base/modules/contrib/search_api/includes/datasource_entity.inc b/profiles/wcm_base/modules/contrib/search_api/includes/datasource_entity.inc index 034bb525c730eb9f02efece47fe10ffbe1387cab..bbca0aa454f68fb213936fd71cee7ea7ceded1b2 100644 --- a/profiles/wcm_base/modules/contrib/search_api/includes/datasource_entity.inc +++ b/profiles/wcm_base/modules/contrib/search_api/includes/datasource_entity.inc @@ -166,6 +166,10 @@ class SearchApiEntityDataSourceController extends SearchApiAbstractDataSourceCon $bundle_column = 'vid'; $bundles = db_query('SELECT vid FROM {taxonomy_vocabulary} WHERE machine_name IN (:bundles)', array(':bundles' => $bundles))->fetchCol(); } + elseif ($this->entityType == 'flagging') { + $bundle_column = 'fid'; + $bundles = db_query('SELECT fid FROM {flag} WHERE name IN (:bundles)', array(':bundles' => $bundles))->fetchCol(); + } elseif ($this->entityType == 'comment') { // Comments are significantly more complicated, since they don't // store their bundle explicitly in their database table. Instead, @@ -182,14 +186,17 @@ class SearchApiEntityDataSourceController extends SearchApiAbstractDataSourceCon $bundles = db_query('SELECT nid FROM {node} WHERE type IN (:bundles)', array(':bundles' => $node_types))->fetchCol(); } else { - return; + continue; } } else { $this->startTrackingFallback(array($index->machine_name => $index)); + continue; } } - $query->condition($bundle_column, $bundles); + if ($bundles) { + $query->condition($bundle_column, $bundles); + } } // INSERT ... SELECT ... @@ -271,10 +278,10 @@ class SearchApiEntityDataSourceController extends SearchApiAbstractDataSourceCon $form['bundles'] = array( '#type' => 'checkboxes', '#title' => t('Bundles'), - '#description' => t('Restrict the entity bundles that will be included in this index. Leave blank to include all bundles. This setting cannot be changed for existing indexes.'), + '#description' => t('Restrict the entity bundles that will be included in this index. Leave blank to include all bundles. This setting cannot be changed for enabled indexes.'), '#options' => array_map('check_plain', $options), '#attributes' => array('class' => array('search-api-checkboxes-list')), - '#disabled' => !empty($form_state['index']), + '#disabled' => !empty($form_state['index']) && $form_state['index']->enabled, ); if (!empty($form_state['index']->options['datasource'])) { $form['bundles']['#default_value'] = drupal_map_assoc($form_state['index']->options['datasource']['bundles']); diff --git a/profiles/wcm_base/modules/contrib/search_api/includes/datasource_external.inc b/profiles/wcm_base/modules/contrib/search_api/includes/datasource_external.inc index 1128f173f8fd191cf8e083e4a647c0ed2577f965..c3a9f1fcfaf1df72fb4782fc7abcf88d76fecfd4 100644 --- a/profiles/wcm_base/modules/contrib/search_api/includes/datasource_external.inc +++ b/profiles/wcm_base/modules/contrib/search_api/includes/datasource_external.inc @@ -49,7 +49,7 @@ class SearchApiExternalDataSourceController extends SearchApiAbstractDataSourceC * loadable, specify a function here. * * @param array $ids - * The IDs of the items to laod. + * The IDs of the items to load. * * @return array * The loaded items, keyed by ID. diff --git a/profiles/wcm_base/modules/contrib/search_api/includes/datasource_multiple.inc b/profiles/wcm_base/modules/contrib/search_api/includes/datasource_multiple.inc index 7e5d4de2dc08682c560e78087a845831a88747f4..ea164963062f8315e950478d48475356d3dc8785 100644 --- a/profiles/wcm_base/modules/contrib/search_api/includes/datasource_multiple.inc +++ b/profiles/wcm_base/modules/contrib/search_api/includes/datasource_multiple.inc @@ -44,6 +44,9 @@ class SearchApiCombinedEntityDataSourceController extends SearchApiAbstractDataS $item->item_type = $type; $item->item_entity_id = $entity_id; $item->item_bundle = NULL; + // Add the item language so the "search_api_language" field will work + // correctly. + $item->language = isset($entity->language) ? $entity->language : NULL; try { list(, , $bundle) = entity_extract_ids($type, $entity); $item->item_bundle = $bundle ? "$type:$bundle" : NULL; diff --git a/profiles/wcm_base/modules/contrib/search_api/includes/index_entity.inc b/profiles/wcm_base/modules/contrib/search_api/includes/index_entity.inc index 7a4234a5f3432d0942907da6721e65ca963a5c5f..95848f12129ef9e49d19a8010b41a0be29d74d4b 100644 --- a/profiles/wcm_base/modules/contrib/search_api/includes/index_entity.inc +++ b/profiles/wcm_base/modules/contrib/search_api/includes/index_entity.inc @@ -764,12 +764,14 @@ class SearchApiIndex extends Entity { * "additional fields" key. */ public function getFields($only_indexed = TRUE, $get_additional = FALSE) { + global $language; + $only_indexed = $only_indexed ? 1 : 0; $get_additional = $get_additional ? 1 : 0; // First, try the static cache and the persistent cache bin. if (empty($this->fields[$only_indexed][$get_additional])) { - $cid = $this->getCacheId() . "-$only_indexed-$get_additional"; + $cid = $this->getCacheId() . "-$only_indexed-$get_additional-{$language->language}"; $cache = cache_get($cid); if ($cache) { $this->fields[$only_indexed][$get_additional] = $cache->data; diff --git a/profiles/wcm_base/modules/contrib/search_api/includes/processor_highlight.inc b/profiles/wcm_base/modules/contrib/search_api/includes/processor_highlight.inc index 62aa158160cd2763e540d682d5eda8693c1cbed5..5b41949153806bd209b1898bc92e533daf13614c 100644 --- a/profiles/wcm_base/modules/contrib/search_api/includes/processor_highlight.inc +++ b/profiles/wcm_base/modules/contrib/search_api/includes/processor_highlight.inc @@ -51,6 +51,7 @@ class SearchApiHighlight extends SearchApiAbstractProcessor { 'excerpt' => TRUE, 'excerpt_length' => 256, 'highlight' => 'always', + 'highlight_partial' => FALSE, 'exclude_fields' => array(), ); @@ -114,6 +115,13 @@ class SearchApiHighlight extends SearchApiAbstractProcessor { '#default_value' => $this->options['highlight'], ); + $form['highlight_partial'] = array( + '#type' => 'checkbox', + '#title' => t('Highlight partial matches'), + '#description' => t('When enabled, matches in parts of words will be highlighted as well.'), + '#default_value' => $this->options['highlight_partial'], + ); + return $form; } @@ -322,9 +330,9 @@ class SearchApiHighlight extends SearchApiAbstractProcessor { $ranges = array(); $included = array(); $length = 0; - $workkeys = $keys; - while ($length < $this->options['excerpt_length'] && count($workkeys)) { - foreach ($workkeys as $k => $key) { + $work_keys = $keys; + while ($length < $this->options['excerpt_length'] && $work_keys) { + foreach ($work_keys as $k => $key) { if ($length >= $this->options['excerpt_length']) { break; } @@ -336,8 +344,14 @@ class SearchApiHighlight extends SearchApiAbstractProcessor { // Locate a keyword (position $p, always >0 because $text starts with a // space). $p = 0; - if (preg_match('/' . self::$boundary . preg_quote($key, '/') . self::$boundary . '/iu', $text, $match, PREG_OFFSET_CAPTURE, $included[$key])) { - $p = $match[0][1]; + if (empty($this->options['highlight_partial'])) { + $regex = '/' . self::$boundary . preg_quote($key, '/') . self::$boundary . '/iu'; + if (preg_match($regex, $text, $match, PREG_OFFSET_CAPTURE, $included[$key])) { + $p = $match[0][1]; + } + } + else { + $p = stripos($text, $key, $included[$key]); } // Now locate a space in front (position $q) and behind it (position $s), // leaving about 60 characters extra before and after for context. @@ -352,18 +366,13 @@ class SearchApiHighlight extends SearchApiAbstractProcessor { $ranges[$q] = $p + $s; $length += $p + $s - $q; $included[$key] = $p + 1; - } - else { - unset($workkeys[$k]); + continue; } } - else { - unset($workkeys[$k]); - } - } - else { - unset($workkeys[$k]); } + // Unless we got a match above, we don't need to look for this key any + // more. + unset($work_keys[$k]); } } @@ -437,10 +446,14 @@ class SearchApiHighlight extends SearchApiAbstractProcessor { } return implode('', $texts); } - $replace = $this->options['prefix'] . '\0' . $this->options['suffix']; $keys = implode('|', array_map('preg_quote', $keys, array_fill(0, count($keys), '/'))); - $text = preg_replace('/' . self::$boundary . '(' . $keys . ')' . self::$boundary . '/iu', $replace, ' ' . $text . ' '); + // If "Highlight partial matches" is disabled, we only want to highlight + // matches that are complete words. Otherwise, we want all of them. + $boundary = empty($this->options['highlight_partial']) ? self::$boundary : ''; + $regex = '/' . $boundary . '(?:' . $keys . ')' . $boundary . '/iu'; + $replace = $this->options['prefix'] . '\0' . $this->options['suffix']; + $text = preg_replace($regex, $replace, ' ' . $text . ' '); return substr($text, 1, -1); } @@ -450,12 +463,12 @@ class SearchApiHighlight extends SearchApiAbstractProcessor { * @param array $array * The array to flatten. * @param string $glue - * The separator to insert between individual array items. + * (optional) The separator to insert between individual array items. * * @return string * The glued string. */ - protected function flattenArrayValues(array $array, $glue = "\n\n") { + protected function flattenArrayValues(array $array, $glue = " \n\n ") { $ret = array(); foreach ($array as $item) { if (is_array($item)) { diff --git a/profiles/wcm_base/modules/contrib/search_api/includes/processor_html_filter.inc b/profiles/wcm_base/modules/contrib/search_api/includes/processor_html_filter.inc index 180c9c18b448f4fd05a9d30efea3d87214d4a3db..0cc4800d7ac9b64771dc6dc99d6397b7d09d3b8b 100644 --- a/profiles/wcm_base/modules/contrib/search_api/includes/processor_html_filter.inc +++ b/profiles/wcm_base/modules/contrib/search_api/includes/processor_html_filter.inc @@ -101,7 +101,7 @@ class SearchApiHtmlFilter extends SearchApiAbstractProcessor { $value = $this->parseText($text); } else { - $value = strip_tags($text); + $value = html_entity_decode(strip_tags($text)); // Remove any multiple or leading/trailing spaces we might have introduced. $value = preg_replace('/\s\s+/', ' ', trim($value)); } @@ -120,7 +120,7 @@ class SearchApiHtmlFilter extends SearchApiAbstractProcessor { ); } $text = substr($text, $pos + 1); - if (!preg_match('#^(/?)([-:_a-zA-Z]+)#', $text, $m)) { + if (!preg_match('#^(/?)([:_a-zA-Z][-:_a-zA-Z0-9.]*)#', $text, $m)) { continue; } $text = substr($text, strpos($text, '>') + 1); diff --git a/profiles/wcm_base/modules/contrib/search_api/includes/processor_stemmer.inc b/profiles/wcm_base/modules/contrib/search_api/includes/processor_stemmer.inc new file mode 100644 index 0000000000000000000000000000000000000000..a6c05489eb724b45081330b003625cb1516d43d4 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/search_api/includes/processor_stemmer.inc @@ -0,0 +1,732 @@ +<?php + +/** + * @file + * Contains SearchApiPorterStemmer and SearchApiPorter2. + */ + +/** + * Stems words to their roots. + */ +class SearchApiPorterStemmer extends SearchApiAbstractProcessor { + + /** + * Static cache for already generated stems. + * + * @var array + */ + protected $stems = array(); + + /** + * {@inheritdoc} + */ + public function configurationForm() { + $form = parent::configurationForm(); + + $args = array( + '!algorithm' => url('https://github.com/markfullmer/porter2'), + '!exclusions' => url('https://github.com/markfullmer/porter2#user-content-custom-exclusions'), + ); + $form += array( + 'help' => array( + '#markup' => '<p>' . t('Optionally, provide an exclusion list to override the stemmer algorithm. Read about the <a href="@algorithm">algorithm</a> and <a href="@exclusions">exclusions</a>.', $args) . '</p>', + ), + 'exceptions' => array( + '#type' => 'textarea', + '#title' => t('Exceptions'), + '#description' => t('Enter exceptions in the form of WORD=STEM, where "WORD" is the term entered and "STEM" is the resulting stem. List each exception on a separate line.'), + '#default_value' => "texan=texa", + ), + ); + + if (!empty($this->options['exceptions'])) { + $form['exceptions']['#default_value'] = $this->options['exceptions']; + } + return $form; + } + + /** + * {@inheritdoc} + */ + protected function process(&$value) { + // Load custom exceptions. + $exceptions = $this->getExceptions(); + + $words = preg_split('/[^\p{L}\p{N}]+/u', $value, -1 , PREG_SPLIT_DELIM_CAPTURE); + $stemmed = array(); + foreach ($words as $i => $word) { + if ($i % 2 == 0 && strlen($word)) { + if (!isset($this->stems[$word])) { + $stem = new SearchApiPorter2($word, $exceptions); + $this->stems[$word] = $stem->stem(); + } + $stemmed[] = $this->stems[$word]; + } + else { + $stemmed[] = $word; + } + } + $value = implode('', $stemmed); + } + + /** + * Retrieves the processor's configured exceptions. + * + * @return string[] + * An associative array of exceptions, with words as keys and stems as their + * replacements. + */ + protected function getExceptions() { + if (!empty($this->options['exceptions'])) { + $exceptions = parse_ini_string($this->options['exceptions'], TRUE); + return is_array($exceptions) ? $exceptions : array(); + } + return array(); + } + +} + +/** + * Implements the Porter2 stemming algorithm. + * + * @see https://github.com/markfullmer/porter2 + */ +class SearchApiPorter2 { + + /** + * The word being stemmed. + * + * @var string + */ + protected $word; + + /** + * The R1 of the word. + * + * @var int + * + * @see http://snowball.tartarus.org/texts/r1r2.html. + */ + protected $r1; + + /** + * The R2 of the word. + * + * @var int + * + * @see http://snowball.tartarus.org/texts/r1r2.html. + */ + protected $r2; + + /** + * List of exceptions to be used. + * + * @var string[] + */ + protected $exceptions = array(); + + /** + * Constructs a SearchApiPorter2 object. + * + * @param string $word + * The word to stem. + * @param string[] $custom_exceptions + * (optional) A custom list of exceptions. + */ + public function __construct($word, $custom_exceptions = array()) { + $this->word = $word; + $this->exceptions = $custom_exceptions + array( + 'skis' => 'ski', + 'skies' => 'sky', + 'dying' => 'die', + 'lying' => 'lie', + 'tying' => 'tie', + 'idly' => 'idl', + 'gently' => 'gentl', + 'ugly' => 'ugli', + 'early' => 'earli', + 'only' => 'onli', + 'singly' => 'singl', + 'sky' => 'sky', + 'news' => 'news', + 'howe' => 'howe', + 'atlas' => 'atlas', + 'cosmos' => 'cosmos', + 'bias' => 'bias', + 'andes' => 'andes', + ); + + // Set initial y, or y after a vowel, to Y. + $inc = 0; + while ($inc <= $this->length()) { + if (substr($this->word, $inc, 1) === 'y' && ($inc == 0 || $this->isVowel($inc - 1))) { + $this->word = substr_replace($this->word, 'Y', $inc, 1); + + } + $inc++; + } + // Establish the regions R1 and R2. See function R(). + $this->r1 = $this->R(1); + $this->r2 = $this->R(2); + } + + /** + * Computes the stem of the word. + * + * @return string + * The word's stem. + */ + public function stem() { + // Ignore exceptions & words that are two letters or less. + if ($this->exceptions() || $this->length() <= 2) { + return strtolower($this->word); + } + else { + $this->step0(); + $this->step1a(); + $this->step1b(); + $this->step1c(); + $this->step2(); + $this->step3(); + $this->step4(); + $this->step5(); + } + return strtolower($this->word); + } + + /** + * Determines whether the word is contained in our list of exceptions. + * + * If so, the $word property is changed to the stem listed in the exceptions. + * + * @return bool + * TRUE if the word was an exception, FALSE otherwise. + */ + protected function exceptions() { + if (isset($this->exceptions[$this->word])) { + $this->word = $this->exceptions[$this->word]; + return TRUE; + } + return FALSE; + } + + /** + * Searches for the longest among the "s" suffixes and removes it. + * + * Implements step 0 of the Porter2 algorithm. + */ + protected function step0() { + $found = FALSE; + $checks = array("'s'", "'s", "'"); + foreach ($checks as $check) { + if (!$found && $this->hasEnding($check)) { + $this->removeEnding($check); + $found = TRUE; + } + } + } + + /** + * Handles various suffixes, of which the longest is replaced. + * + * Implements step 1a of the Porter2 algorithm. + */ + protected function step1a() { + $found = FALSE; + if ($this->hasEnding('sses')) { + $this->removeEnding('sses'); + $this->addEnding('ss'); + $found = TRUE; + } + $checks = array('ied', 'ies'); + foreach ($checks as $check) { + if (!$found && $this->hasEnding($check)) { + $length = $this->length(); + $this->removeEnding($check); + if ($length > 4) { + $this->addEnding('i'); + } + else { + $this->addEnding('ie'); + } + $found = TRUE; + } + } + if ($this->hasEnding('us') || $this->hasEnding('ss')) { + $found = TRUE; + } + // Delete if preceding word part has a vowel not immediately before the s. + if (!$found && $this->hasEnding('s') && $this->containsVowel(substr($this->word, 0, -2))) { + $this->removeEnding('s'); + } + } + + /** + * Handles various suffixes, of which the longest is replaced. + * + * Implements step 1b of the Porter2 algorithm. + */ + protected function step1b() { + $exceptions = array( + 'inning', + 'outing', + 'canning', + 'herring', + 'earring', + 'proceed', + 'exceed', + 'succeed', + ); + if (in_array($this->word, $exceptions)) { + return; + } + $checks = array('eedly', 'eed'); + foreach ($checks as $check) { + if ($this->hasEnding($check)) { + if ($this->r1 !== $this->length()) { + $this->removeEnding($check); + $this->addEnding('ee'); + } + return; + } + } + $checks = array('ingly', 'edly', 'ing', 'ed'); + $second_endings = array('at', 'bl', 'iz'); + foreach ($checks as $check) { + // If the ending is present and the previous part contains a vowel. + if ($this->hasEnding($check) && $this->containsVowel(substr($this->word, 0, -strlen($check)))) { + $this->removeEnding($check); + foreach ($second_endings as $ending) { + if ($this->hasEnding($ending)) { + $this->addEnding('e'); + return; + } + } + // If the word ends with a double, remove the last letter. + $found = $this->removeDoubles(); + // If the word is short, add e (so hop -> hope). + if (!$found && ($this->isShort())) { + $this->addEnding('e'); + } + return; + } + } + } + + /** + * Replaces suffix y or Y with i if after non-vowel not @ word begin. + * + * Implements step 1c of the Porter2 algorithm. + */ + protected function step1c() { + if (($this->hasEnding('y') || $this->hasEnding('Y')) && $this->length() > 2 && !($this->isVowel($this->length() - 2))) { + $this->removeEnding('y'); + $this->addEnding('i'); + } + } + + /** + * Implements step 2 of the Porter2 algorithm. + */ + protected function step2() { + $checks = array( + "ization" => "ize", + "iveness" => "ive", + "fulness" => "ful", + "ational" => "ate", + "ousness" => "ous", + "biliti" => "ble", + "tional" => "tion", + "lessli" => "less", + "fulli" => "ful", + "entli" => "ent", + "ation" => "ate", + "aliti" => "al", + "iviti" => "ive", + "ousli" => "ous", + "alism" => "al", + "abli" => "able", + "anci" => "ance", + "alli" => "al", + "izer" => "ize", + "enci" => "ence", + "ator" => "ate", + "bli" => "ble", + "ogi" => "og", + ); + foreach ($checks as $find => $replace) { + if ($this->hasEnding($find)) { + if ($this->inR1($find)) { + $this->removeEnding($find); + $this->addEnding($replace); + } + return; + } + } + if ($this->hasEnding('li')) { + if ($this->length() > 4 && $this->validLi($this->charAt(-3))) { + $this->removeEnding('li'); + } + } + } + + /** + * Implements step 3 of the Porter2 algorithm. + */ + protected function step3() { + $checks = array( + 'ational' => 'ate', + 'tional' => 'tion', + 'alize' => 'al', + 'icate' => 'ic', + 'iciti' => 'ic', + 'ical' => 'ic', + 'ness' => '', + 'ful' => '', + ); + foreach ($checks as $find => $replace) { + if ($this->hasEnding($find)) { + if ($this->inR1($find)) { + $this->removeEnding($find); + $this->addEnding($replace); + } + return; + } + } + if ($this->hasEnding('ative')) { + if ($this->inR2('ative')) { + $this->removeEnding('ative'); + } + } + } + + /** + * Implements step 4 of the Porter2 algorithm. + */ + protected function step4() { + $checks = array( + 'ement', + 'ment', + 'ance', + 'ence', + 'able', + 'ible', + 'ant', + 'ent', + 'ion', + 'ism', + 'ate', + 'iti', + 'ous', + 'ive', + 'ize', + 'al', + 'er', + 'ic', + ); + foreach ($checks as $check) { + // Among the suffixes, if found and in R2, delete. + if ($this->hasEnding($check)) { + if ($this->inR2($check)) { + if ($check !== 'ion' || in_array($this->charAt(-4), array('s', 't'))) { + $this->removeEnding($check); + } + } + return; + } + } + } + + /** + * Implements step 5 of the Porter2 algorithm. + */ + protected function step5() { + if ($this->hasEnding('e')) { + // Delete if in R2, or in R1 and not preceded by a short syllable. + if ($this->inR2('e') || ($this->inR1('e') && !$this->isShortSyllable($this->length() - 3))) { + $this->removeEnding('e'); + } + return; + } + if ($this->hasEnding('l')) { + // Delete if in R2 and preceded by l. + if ($this->inR2('l') && $this->charAt(-2) == 'l') { + $this->removeEnding('l'); + } + } + } + + /** + * Removes certain double consonants from the word's end. + * + * @return bool + * TRUE if a match was found and removed, FALSE otherwise. + */ + protected function removeDoubles() { + $found = FALSE; + $doubles = array('bb', 'dd', 'ff', 'gg', 'mm', 'nn', 'pp', 'rr', 'tt'); + foreach ($doubles as $double) { + if (substr($this->word, -2) == $double) { + $this->word = substr($this->word, 0, -1); + $found = TRUE; + break; + } + } + return $found; + } + + /** + * Checks whether a character is a vowel. + * + * @param int $position + * The character's position. + * @param string|null $word + * (optional) The word in which to check. Defaults to $this->word. + * @param string[] $additional + * (optional) Additional characters that should count as vowels. + * + * @return bool + * TRUE if the character is a vowel, FALSE otherwise. + */ + protected function isVowel($position, $word = NULL, $additional = array()) { + if ($word === NULL) { + $word = $this->word; + } + $vowels = array_merge(array('a', 'e', 'i', 'o', 'u', 'y'), $additional); + return in_array($this->charAt($position, $word), $vowels); + } + + /** + * Retrieves the character at the given position. + * + * @param int $position + * The 0-based index of the character. If a negative number is given, the + * position is counted from the end of the string. + * @param string|null $word + * (optional) The word from which to retrieve the character. Defaults to + * $this->word. + * + * @return string + * The character at the given position, or an empty string if the given + * position was illegal. + */ + protected function charAt($position, $word = NULL) { + if ($word === NULL) { + $word = $this->word; + } + $length = strlen($word); + if (abs($position) >= $length) { + return ''; + } + if ($position < 0) { + $position += $length; + } + return $word[$position]; + } + + /** + * Determines whether the word ends in a "vowel-consonant" suffix. + * + * Unless the word is only two characters long, it also checks that the + * third-last character is neither "w", "x" nor "Y". + * + * @param int|null $position + * (optional) If given, do not check the end of the word, but the character + * at the given position, and the next one. + * + * @return bool + * TRUE if the word has the described suffix, FALSE otherwise. + */ + protected function isShortSyllable($position = NULL) { + if ($position === NULL) { + $position = $this->length() - 2; + } + // A vowel at the beginning of the word followed by a non-vowel. + if ($position === 0) { + return $this->isVowel(0) && !$this->isVowel(1); + } + // Vowel followed by non-vowel other than w, x, Y and preceded by + // non-vowel. + $additional = array('w', 'x', 'Y'); + return !$this->isVowel($position - 1) && $this->isVowel($position) && !$this->isVowel($position + 1, NULL, $additional); + } + + /** + * Determines whether the word is short. + * + * A word is called short if it ends in a short syllable and if R1 is null. + * + * @return bool + * TRUE if the word is short, FALSE otherwise. + */ + protected function isShort() { + return $this->isShortSyllable() && $this->r1 == $this->length(); + } + + /** + * Determines the start of a certain "R" region. + * + * R is a region after the first non-vowel following a vowel, or end of word. + * + * @param int $type + * (optional) 1 or 2. If 2, then calculate the R after the R1. + * + * @return int + * The R position. + */ + protected function R($type = 1) { + $inc = 1; + if ($type === 2) { + $inc = $this->r1; + } + elseif ($this->length() > 5) { + $prefix_5 = substr($this->word, 0, 5); + if ($prefix_5 === 'gener' || $prefix_5 === 'arsen') { + return 5; + } + if ($this->length() > 6 && substr($this->word, 0, 6) === 'commun') { + return 6; + } + } + + while ($inc <= $this->length()) { + if (!$this->isVowel($inc) && $this->isVowel($inc - 1)) { + $position = $inc; + break; + } + $inc++; + } + if (!isset($position)) { + $position = $this->length(); + } + else { + // We add one, as this is the position AFTER the first non-vowel. + $position++; + } + return $position; + } + + /** + * Checks whether the given string is contained in R1. + * + * @param string $string + * The string. + * + * @return bool + * TRUE if the string is in R1, FALSE otherwise. + */ + protected function inR1($string) { + $r1 = substr($this->word, $this->r1); + return strpos($r1, $string) !== FALSE; + } + + /** + * Checks whether the given string is contained in R2. + * + * @param string $string + * The string. + * + * @return bool + * TRUE if the string is in R2, FALSE otherwise. + */ + protected function inR2($string) { + $r2 = substr($this->word, $this->r2); + return strpos($r2, $string) !== FALSE; + } + + /** + * Determines the string length of the current word. + * + * @return int + * The string length of the current word. + */ + protected function length() { + return strlen($this->word); + } + + /** + * Checks whether the word ends with the given string. + * + * @param string $string + * The string. + * + * @return bool + * TRUE if the word ends with the given string, FALSE otherwise. + */ + protected function hasEnding($string) { + $length = strlen($string); + if ($length > $this->length()) { + return FALSE; + } + return (substr_compare($this->word, $string, -1 * $length, $length) === 0); + } + + /** + * Appends a given string to the current word. + * + * @param string $string + * The ending to append. + */ + protected function addEnding($string) { + $this->word = $this->word . $string; + } + + /** + * Removes a given string from the end of the current word. + * + * Does not check whether the ending is actually there. + * + * @param string $string + * The ending to remove. + */ + protected function removeEnding($string) { + $this->word = substr($this->word, 0, -strlen($string)); + } + + /** + * Checks whether the given string contains a vowel. + * + * @param string $string + * The string to check. + * + * @return bool + * TRUE if the string contains a vowel, FALSE otherwise. + */ + protected function containsVowel($string) { + $inc = 0; + $return = FALSE; + while ($inc < strlen($string)) { + if ($this->isVowel($inc, $string)) { + $return = TRUE; + break; + } + $inc++; + } + return $return; + } + + /** + * Checks whether the given string is a valid -li prefix. + * + * @param string $string + * The string to check. + * + * @return bool + * TRUE if the given string is a valid -li prefix, FALSE otherwise. + */ + protected function validLi($string) { + return in_array($string, array( + 'c', + 'd', + 'e', + 'g', + 'h', + 'k', + 'm', + 'n', + 'r', + 't', + )); + } + +} diff --git a/profiles/wcm_base/modules/contrib/search_api/includes/query.inc b/profiles/wcm_base/modules/contrib/search_api/includes/query.inc index debed66a84ea877a01d478385a37499c2c2fe9ec..640dcd205c9e80bdbe017adce9e39afb27a88743 100644 --- a/profiles/wcm_base/modules/contrib/search_api/includes/query.inc +++ b/profiles/wcm_base/modules/contrib/search_api/includes/query.inc @@ -856,10 +856,33 @@ class SearchApiQuery implements SearchApiQueryInterface { } $ret .= 'Sorting: ' . implode(', ', $sort) . "\n"; } - $ret .= 'Options: ' . str_replace("\n", "\n ", var_export($this->options, TRUE)) . "\n"; + $options = $this->sanitizeOptions($this->options); + $options = str_replace("\n", "\n ", var_export($options, TRUE)); + $ret .= 'Options: ' . $options . "\n"; return $ret; } + /** + * Sanitizes an array of options in a way that plays nice with var_export(). + * + * @param array $options + * An array of options. + * + * @return array + * The sanitized options. + */ + protected function sanitizeOptions(array $options) { + foreach ($options as $key => $value) { + if (is_object($value)) { + $options[$key] = 'object (' . get_class($value) . ')'; + } + elseif (is_array($value)) { + $options[$key] = $this->sanitizeOptions($value); + } + } + return $options; + } + } /** @@ -1048,6 +1071,10 @@ class SearchApiQueryFilter implements SearchApiQueryFilterInterface { * {@inheritdoc} */ public function &getTags() { + // Tags can sometimes be NULL for old serialized query filter objects. + if (!isset($this->tags)) { + $this->tags = array(); + } return $this->tags; } diff --git a/profiles/wcm_base/modules/contrib/search_api/search_api.admin.inc b/profiles/wcm_base/modules/contrib/search_api/search_api.admin.inc index 2167e7872253a8193227e549ce6c147284d9d618..3afbaa7826f0d97528e1cd33024d7dae09e7b193 100644 --- a/profiles/wcm_base/modules/contrib/search_api/search_api.admin.inc +++ b/profiles/wcm_base/modules/contrib/search_api/search_api.admin.inc @@ -337,13 +337,6 @@ function search_api_admin_add_server_submit(array $form, array &$form_state) { drupal_set_message(t('The server was successfully created.')); } -/** - * Title callback for viewing or editing a server or index. - */ -function search_api_admin_item_title($object) { - return $object->name; -} - /** * Page callback: Displays information about a server. * diff --git a/profiles/wcm_base/modules/contrib/search_api/search_api.info b/profiles/wcm_base/modules/contrib/search_api/search_api.info index 1501afb8d4d786b8386f7183d903c44210c980e9..e7317531c989c15dbdc1ecf2f23dcd95ee44443f 100644 --- a/profiles/wcm_base/modules/contrib/search_api/search_api.info +++ b/profiles/wcm_base/modules/contrib/search_api/search_api.info @@ -27,6 +27,7 @@ files[] = includes/processor.inc files[] = includes/processor_highlight.inc files[] = includes/processor_html_filter.inc files[] = includes/processor_ignore_case.inc +files[] = includes/processor_stemmer.inc files[] = includes/processor_stopwords.inc files[] = includes/processor_tokenizer.inc files[] = includes/processor_transliteration.inc @@ -36,9 +37,9 @@ files[] = includes/service.inc configure = admin/config/search/search_api -; Information added by Drupal.org packaging script on 2016-04-20 -version = "7.x-1.18" +; Information added by Drupal.org packaging script on 2017-02-23 +version = "7.x-1.21" core = "7.x" project = "search_api" -datestamp = "1461155351" +datestamp = "1487844493" diff --git a/profiles/wcm_base/modules/contrib/search_api/search_api.install b/profiles/wcm_base/modules/contrib/search_api/search_api.install index 34682d9c9ceeec8756f14422e2e5bf280bf1fd9a..5dc2689547ac83fa24318b8b577f3ec5ece19872 100644 --- a/profiles/wcm_base/modules/contrib/search_api/search_api.install +++ b/profiles/wcm_base/modules/contrib/search_api/search_api.install @@ -362,7 +362,7 @@ function search_api_install() { ), ); search_api_index_insert($values); - drupal_set_message('The Search API module was installed. A new default node index was created.'); + drupal_set_message(t('The Search API module was installed. A new default node index was created.')); } /** diff --git a/profiles/wcm_base/modules/contrib/search_api/search_api.module b/profiles/wcm_base/modules/contrib/search_api/search_api.module index c823bb653766f58cb5e280a4ba126402e7216d04..61385c5d3cfa5872f807bcb47a846bb4f3eb78c3 100644 --- a/profiles/wcm_base/modules/contrib/search_api/search_api.module +++ b/profiles/wcm_base/modules/contrib/search_api/search_api.module @@ -935,7 +935,9 @@ function search_api_node_access_records_alter(&$grants, $node) { $item_ids = array(); if (!empty($index->options['data_alter_callbacks']['search_api_alter_node_access']['status'])) { $item_id = $index->datasource()->getItemId($node); - $item_ids = array($item_id); + if ($item_id !== NULL) { + $item_ids = array($item_id); + } } elseif (!empty($index->options['data_alter_callbacks']['search_api_alter_comment_access']['status'])) { if (!isset($comments)) { @@ -1150,11 +1152,17 @@ function search_api_search_api_processor_info() { 'class' => 'SearchApiStopWords', 'weight' => 30, ); + $processors['search_api_porter_stemmer'] = array( + 'name' => t('Stem words'), + 'description' => t('This processor reduces words to a stem (e.g., "talking" to "talk"). For best results, it should only be executed after tokenizing.'), + 'class' => 'SearchApiPorterStemmer', + 'weight' => 35, + ); $processors['search_api_highlighting'] = array( 'name' => t('Highlighting'), 'description' => t('Adds highlighting for search results.'), 'class' => 'SearchApiHighlight', - 'weight' => 35, + 'weight' => 40, ); return $processors; @@ -2465,6 +2473,13 @@ function search_api_server_url(SearchApiServer $server) { ); } +/** + * Title callback for viewing or editing a server or index. + */ +function search_api_admin_item_title($object) { + return $object->name; +} + /** * Title callback for determining which title should be displayed for the * "delete" local task. @@ -2922,6 +2937,9 @@ function search_api_get_sanitized_field_values(array $values) { * The sanitized field value(s). */ function search_api_sanitize_field_value($field_value, $sanitize_callback = 'check_plain') { + if ($field_value === NULL) { + return $field_value; + } if (is_scalar($field_value)) { return call_user_func($sanitize_callback, $field_value); } diff --git a/profiles/wcm_base/modules/contrib/search_api/search_api.rules.inc b/profiles/wcm_base/modules/contrib/search_api/search_api.rules.inc index 37143f8741d0d4429dcb6a5a35d4a3aec3996bd0..0725f4ce04da321858ba8d22bec13fc9b89c0b9b 100644 --- a/profiles/wcm_base/modules/contrib/search_api/search_api.rules.inc +++ b/profiles/wcm_base/modules/contrib/search_api/search_api.rules.inc @@ -10,7 +10,7 @@ * Implements hook_rules_action_info(). */ function search_api_rules_action_info() { - $items['search_api_index'] = array ( + $items['search_api_index'] = array( 'parameter' => array( 'entity' => array( 'type' => 'entity', diff --git a/profiles/wcm_base/modules/contrib/search_api/search_api.test b/profiles/wcm_base/modules/contrib/search_api/search_api.test index 89883028a17560f2b1652b29cbf50eaf8ceee86e..23f36bcf0789815f44568157e54817c156b16fe2 100644 --- a/profiles/wcm_base/modules/contrib/search_api/search_api.test +++ b/profiles/wcm_base/modules/contrib/search_api/search_api.test @@ -1062,7 +1062,7 @@ class SearchApiUnitTest extends DrupalWebTestCase { protected function checkHtmlFilter() { $orig = <<<END This is <em lang="en" title = -"something">a test</em>. +"something">a test</em>.<h3>Header</h3> How to write <strong>links to <em>other sites</em></strong>: <a href="URL" title="MOUSEOVER TEXT">TEXT</a>. < signs can be <A HREF="http://example.com/topic/html-escapes" TITLE = 'HTML "escapes"' TARGET = '_blank'>escaped</A> with "&lt;". @@ -1071,6 +1071,7 @@ END; $tags = <<<END em = 1.5 strong = 2 +h3 = 3 END; $processed1 = array( array('value' => 'This', 'score' => 1), @@ -1078,6 +1079,7 @@ END; array('value' => 'something', 'score' => 1.5), array('value' => 'a', 'score' => 1.5), array('value' => 'test', 'score' => 1.5), + array('value' => 'Header', 'score' => 3), array('value' => 'How', 'score' => 1), array('value' => 'to', 'score' => 1), array('value' => 'write', 'score' => 1), diff --git a/profiles/wcm_base/modules/contrib/search_api/tests/search_api_test.info b/profiles/wcm_base/modules/contrib/search_api/tests/search_api_test.info index 2ef1f2d84dc95565fb9207911a267eac08b66095..95c999ab72a5cbffc9c51d5f30003be87ab156a7 100644 --- a/profiles/wcm_base/modules/contrib/search_api/tests/search_api_test.info +++ b/profiles/wcm_base/modules/contrib/search_api/tests/search_api_test.info @@ -10,9 +10,9 @@ files[] = search_api_test.module hidden = TRUE -; Information added by Drupal.org packaging script on 2016-04-20 -version = "7.x-1.18" +; Information added by Drupal.org packaging script on 2017-02-23 +version = "7.x-1.21" core = "7.x" project = "search_api" -datestamp = "1461155351" +datestamp = "1487844493" diff --git a/profiles/wcm_base/modules/contrib/search_api_db/CHANGELOG.txt b/profiles/wcm_base/modules/contrib/search_api_db/CHANGELOG.txt index ed7285079fe75391fcd7db4702d4006bf56e6fdc..4b30f594b167f9c7c7c91db68fc7b03df20f0462 100644 --- a/profiles/wcm_base/modules/contrib/search_api_db/CHANGELOG.txt +++ b/profiles/wcm_base/modules/contrib/search_api_db/CHANGELOG.txt @@ -1,3 +1,29 @@ +Search API Database Search 1.6 (2017-02-23): +-------------------------------------------- +- #2840261 by alan-ps, drunken monkey: Fixed usage of outdated hash functions. +- #2844192 by drunken monkey: Fixed switching field boost from zero to other + value. +- #2566329 by drunken monkey: Fixed calculation of fulltext facets. +- #2848199 by renat, drunken monkey: Fixed code style issues and a typo in the + .install file. +- #2841169 by trrroy, drunken monkey: Fixed problems with giant scores in DB + backend. +- #2795245 by drunken monkey: Fixed changing of a field's type to "Fulltext". +- #2807111 by SpadXIII, drunken monkey: Added performance improvements for + multi-field autocompletion. +- #2775627 by cosolom, drunken monkey: Fixed altering of all search-related DB + queries. +- #2745655 by drunken monkey: Fixed "not empty" condition on fulltext fields. +- #2717393 by drunken monkey: Fixed altering of database query for creating a + temporary table. +- #2446741 by drunken monkey: Fixed partial matching on MS SQL Server. +- #2616804 by drunken monkey, mfb: Fixed indexing of words with multi-byte + characters. +- #2632426 by drunken monkey: Fixed "results" key sometimes missing in search + results. +- #2621430 by SpaghettiBolognese: Added "random sorting" feature. +- #2511860 by drunken monkey: Fixed error when search for multiple short words. + Search API Database Search 1.5 (2015-08-30): -------------------------------------------- - #2469547 by drunken monkey: Fixed facets on fulltext fields. diff --git a/profiles/wcm_base/modules/contrib/search_api_db/search_api_db.info b/profiles/wcm_base/modules/contrib/search_api_db/search_api_db.info index a7189c0c3cf0db408097bd3556f15b98825b5a46..df593332c9bb68dfd46d489d6561149881b86071 100644 --- a/profiles/wcm_base/modules/contrib/search_api_db/search_api_db.info +++ b/profiles/wcm_base/modules/contrib/search_api_db/search_api_db.info @@ -6,9 +6,9 @@ package = Search files[] = search_api_db.test files[] = service.inc -; Information added by Drupal.org packaging script on 2015-08-30 -version = "7.x-1.5" +; Information added by Drupal.org packaging script on 2017-02-23 +version = "7.x-1.6" core = "7.x" project = "search_api_db" -datestamp = "1440962643" +datestamp = "1487844786" diff --git a/profiles/wcm_base/modules/contrib/search_api_db/search_api_db.install b/profiles/wcm_base/modules/contrib/search_api_db/search_api_db.install index 11cedafdb6cce3ff7b905c489179eb4206285974..0202a0bf48af92fdde6ef42522055702c5784081 100644 --- a/profiles/wcm_base/modules/contrib/search_api_db/search_api_db.install +++ b/profiles/wcm_base/modules/contrib/search_api_db/search_api_db.install @@ -11,7 +11,8 @@ function search_api_db_uninstall() { * Implements hook_update_dependencies(). */ function search_api_db_update_dependencies() { - // This update should run after primary IDs have been changed to machine names in the framework. + // This update should run after primary IDs have been changed to machine names + // in the framework. $dependencies['search_api_db'][7101] = array( 'search_api' => 7102, ); @@ -19,8 +20,7 @@ function search_api_db_update_dependencies() { } /** - * Re-arranges the $server->options['indexes'] array to be keyed by machine_name - * instead of by id. + * Replace numeric index IDs with machine names in the server options. */ function search_api_db_update_7101() { $query = db_select('search_api_server', 's'); @@ -56,7 +56,7 @@ function search_api_db_update_7101() { } /** - * Solves index problems with umlauts, accented characters, etc. on MySQL servers. + * Solve index problems with non-ASCII characters on MySQL servers. */ function search_api_db_update_7102() { global $databases; @@ -83,7 +83,7 @@ function search_api_db_update_7102() { } /** - * Changes date fields from int to big int. + * Change date fields from int to big int. * * The purpose is to support historical dates. */ @@ -253,7 +253,7 @@ function search_api_db_update_7106() { 'not null' => TRUE, 'default' => 0, ); - // Add new field and poplate data. + // Add new field and populate data. $connection->schema()->addField($field['table'], 'score_int', $spec); $connection->update($field['table']) ->expression('score_int', 'score * 1000') @@ -268,6 +268,51 @@ function search_api_db_update_7106() { } } +/** + * Eliminates the use of low-standard hashes. + */ +function search_api_db_update_7107() { + $spec = array( + 'description' => "The name of the field in which the token appears, or a base-64 encoded sha-256 hash of the field.", + 'not null' => TRUE, + 'type' => 'varchar', + 'length' => 255, + ); + + $server_options = db_select('search_api_server', 's') + ->fields('s', array('id', 'options')) + ->condition('class', 'search_api_db_service') + ->execute() + ->fetchAllKeyed(); + + foreach ($server_options as $id => $options) { + $options = unserialize($options); + + if (!empty($options['indexes'])) { + foreach ($options['indexes'] as $index_id => $fields) { + $text_table = NULL; + + foreach ($fields as $field_id => $field) { + if (search_api_is_text_type($field['type'])) { + $text_table = $field['table']; + if (strlen($field_id) > 255) { + db_update($text_table) + ->fields(array('field_name' => drupal_hash_base64($field_id))) + ->condition('field_name', md5($field_id)) + ->execute(); + } + } + } + + // If there is a text table for this index, update its description. + if ($text_table) { + db_change_field($text_table, 'field_name', 'field_name', $spec); + } + } + } + } +} + /** * Finds a free table name within the given database. * diff --git a/profiles/wcm_base/modules/contrib/search_api_db/search_api_db.test b/profiles/wcm_base/modules/contrib/search_api_db/search_api_db.test index 2f77c13fbb0fe653cc576fe53224b7e83a8ad0a5..f1cc88d0fd94f6550feeb090fb4123e0f97eb455 100644 --- a/profiles/wcm_base/modules/contrib/search_api_db/search_api_db.test +++ b/profiles/wcm_base/modules/contrib/search_api_db/search_api_db.test @@ -875,6 +875,46 @@ class SearchApiDbTest extends DrupalWebTestCase { ); usort($results['search_api_facets']['body'], array($this, 'facetCompare')); $this->assertEqual($results['search_api_facets']['body'], $expected, 'Correct facets were returned for a fulltext field.'); + + // Regression tests for #2511860. + $query = $this->buildSearch(); + $query->condition('body', 'ab xy'); + $results = $query->execute(); + $this->assertEqual($results['result count'], 5, 'Fulltext filters on short words do not change the result.'); + + $query = $this->buildSearch(); + $query->condition('body', 'ab ab'); + $results = $query->execute(); + $this->assertEqual($results['result count'], 5, 'Fulltext filters on duplicate short words do not change the result.'); + + // Regression test for #2632426. + $query = $this->buildSearch(); + $query->condition('type', 'unknown_type'); + $query->setOption('skip result count', TRUE); + $results = $query->execute(); + $this->assertEqual($results['result count'], FALSE, 'Search for unknown type returned correct result count.'); + $this->assertEqual($results['results'], array(), 'Search for unknown type returned an empty result set.'); + + // Regression tests for #2566329. + $query = $this->buildSearch(); + $query->condition('id', 5, '<>'); + $facets['body'] = array( + 'field' => 'body', + 'limit' => 0, + 'min_count' => 0, + 'missing' => FALSE, + ); + $query->setOption('search_api_facets', $facets); + $query->range(0, 0); + $results = $query->execute(); + $expected = array( + array('count' => 4, 'filter' => '"test"'), + array('count' => 1, 'filter' => '"bar"'), + array('count' => 1, 'filter' => '"foobar"'), + array('count' => 0, 'filter' => '"foo"'), + ); + usort($results['search_api_facets']['body'], array($this, 'facetCompare')); + $this->assertEqual($results['search_api_facets']['body'], $expected, 'Correct facets were returned for a fulltext field with minimum count 0.'); } /** @@ -911,8 +951,10 @@ class SearchApiDbTest extends DrupalWebTestCase { $this->indexItems(); $this->drupalGet('search_api_test/insert'); + $mb_string = 'äöüßáŧæøðđŋħĸµäöüßáŧæøðđŋħĸµ'; $this->insertItem(array( 'id' => 6, + 'body' => $mb_string, 'prices' => '3.5,3.25,3.75,3.5', )); @@ -927,6 +969,60 @@ class SearchApiDbTest extends DrupalWebTestCase { $this->assertEqual($results['result count'], 1, 'Filter on decimal field returned correct number of results.'); $this->assertEqual(array_keys($results['results']), array(6), 'Filter on decimal field returned correct result.'); $this->assertEqual($results['warnings'], array(), 'No warnings were displayed.'); + + // Regression test for #2616804. + // The word has 28 Unicode characters but 56 bytes. Verify that it was still + // indexed correctly. + $query = $this->buildSearch($mb_string); + $results = $query->execute(); + $this->assertEqual($results['result count'], 1, 'Search for word with 28 multi-byte characters returned correct number of results.'); + $this->assertEqual(array_keys($results['results']), array(6), 'Search for word with 28 multi-byte characters returned correct result.'); + $this->assertEqual($results['ignored'], array(), 'No keys were ignored.'); + $this->assertEqual($results['warnings'], array(), 'No warnings were displayed.'); + + $query = $this->buildSearch($mb_string . 'ä'); + $results = $query->execute(); + $this->assertEqual($results['result count'], 0, 'Search for unknown word with 29 multi-byte characters returned no results.'); + $this->assertEqual($results['ignored'], array(), 'No keys were ignored.'); + $this->assertEqual($results['warnings'], array(), 'No warnings were displayed.'); + + // Regression tests for #2745655. + $results = $this->buildSearch() + ->condition('title', NULL) + ->execute(); + // "Minimum chars" is 3 at this point, so all items with no longer words in + // their titles will be returned, too. + $this->assertEqual($results['result count'], 4, 'Search for items without title returned correct number of results.'); + $this->assertEqual(array_keys($results['results']), array(3, 4, 5, 6), 'Search for items without title returned correct result.'); + $this->assertEqual($results['ignored'], array(), 'No keys were ignored.'); + $this->assertEqual($results['warnings'], array(), 'No warnings were displayed.'); + + $results = $this->buildSearch() + ->condition('title', NULL, '<>') + ->execute(); + $this->assertEqual($results['result count'], 2, 'Search for items with title returned correct number of results.'); + $this->assertEqual(array_keys($results['results']), array(1, 2), 'Search for items with title returned correct result.'); + $this->assertEqual($results['ignored'], array(), 'No keys were ignored.'); + $this->assertEqual($results['warnings'], array(), 'No warnings were displayed.'); + + // Regression tests for #2795245. + // Make sure changing a field's type from something else to "text" works + // correctly. + $index->options['fields']['type']['type'] = 'text'; + $index->save(); + search_api_index_items($index); + + $results = $this->buildSearch()->condition('type', NULL)->execute(); + $this->assertEqual($results['result count'], 2, 'Search for items without type returned correct number of results.'); + $this->assertEqual(array_keys($results['results']), array(3, 6), 'Search for items without type returned correct result.'); + $this->assertEqual($results['ignored'], array(), 'No keys were ignored.'); + $this->assertEqual($results['warnings'], array(), 'No warnings were displayed.'); + + $results = $this->buildSearch()->condition('type', NULL, '<>')->execute(); + $this->assertEqual($results['result count'], 4, 'Search for items with type returned correct number of results.'); + $this->assertEqual(array_keys($results['results']), array(1, 2, 4, 5), 'Search for items with type returned correct result.'); + $this->assertEqual($results['ignored'], array(), 'No keys were ignored.'); + $this->assertEqual($results['warnings'], array(), 'No warnings were displayed.'); } /** diff --git a/profiles/wcm_base/modules/contrib/search_api_db/service.inc b/profiles/wcm_base/modules/contrib/search_api_db/service.inc index 362bf9b5d973c19a8fcc67cbf3c12ac52af25ac6..609e5d4f1b574e0549f52cf002a0a7b9adeac7ec 100644 --- a/profiles/wcm_base/modules/contrib/search_api_db/service.inc +++ b/profiles/wcm_base/modules/contrib/search_api_db/service.inc @@ -176,6 +176,7 @@ class SearchApiDbService extends SearchApiAbstractService { 'search_api_autocomplete' => TRUE, 'search_api_facets' => TRUE, 'search_api_facets_operator_or' => TRUE, + 'search_api_random_sort' => TRUE, 'search_api_service_extra' => TRUE, ); return isset($supported[$feature]); @@ -570,11 +571,19 @@ class SearchApiDbService extends SearchApiAbstractService { elseif ($text_table && $new_inner_type == 'text' && $field['boost'] != $new_fields[$name]['boost']) { $change = TRUE; if (!$reindex) { - $multiplier = $new_fields[$name]['boost'] / $field['boost']; - $this->connection->update($text_table) - ->expression('score', 'score * :mult', array(':mult' => $multiplier)) - ->condition('field_name', self::getTextFieldName($name)) - ->execute(); + // If there was a non-zero boost set previously, we can just update + // all scores with a single UPDATE query. Otherwise, no way around + // re-indexing. + if ($field['boost']) { + $multiplier = $new_fields[$name]['boost'] / $field['boost']; + $this->connection->update($text_table) + ->expression('score', 'score * :mult', array(':mult' => $multiplier)) + ->condition('field_name', self::getTextFieldName($name)) + ->execute(); + } + else { + $reindex = TRUE; + } } } // Make sure the table and column now exist. (Especially important when @@ -606,15 +615,21 @@ class SearchApiDbService extends SearchApiAbstractService { // If we have not encountered a text table, assign a name for it. $text_table = $this->findFreeTable($prefix . '_', 'text'); } - $fields[$name]['table'] = $text_table; + $fields[$name] = array( + 'table' => $text_table, + ); } else { if ($this->canDenormalize($field)) { - $fields[$name]['table'] = $prefix; - $fields[$name]['column'] = $this->findFreeColumn($fields[$name]['table'], $name); + $fields[$name] = array( + 'table' => $prefix, + 'column' => $this->findFreeColumn($prefix, $name), + ); } else { - $fields[$name]['table'] = $this->findFreeTable($prefix . '_', $name); + $fields[$name] = array( + 'table' => $this->findFreeTable($prefix . '_', $name), + ); } $this->createFieldTable($index, $field, $fields[$name]); } @@ -645,7 +660,7 @@ class SearchApiDbService extends SearchApiAbstractService { 'not null' => TRUE, ), 'field_name' => array( - 'description' => "The name of the field in which the token appears, or an MD5 hash of the field.", + 'description' => "The name of the field in which the token appears, or a base-64 encoded sha-256 hash of the field.", 'not null' => TRUE, 'type' => 'varchar', 'length' => 255, @@ -894,11 +909,15 @@ class SearchApiDbService extends SearchApiAbstractService { if ($words) { $field_name = self::getTextFieldName($name); foreach ($words as $word) { + $score = round($word['score'] * $boost * self::SCORE_MULTIPLIER); + // Take care that the score doesn't exceed the maximum value for + // the database column (2^32-1). + $score = min((int) $score, 4294967295); $text_inserts[$table][] = array( 'item_id' => $id, 'field_name' => $field_name, 'word' => $word['value'], - 'score' => (int) round($word['score'] * $boost * self::SCORE_MULTIPLIER), + 'score' => $score, ); } } @@ -964,7 +983,7 @@ class SearchApiDbService extends SearchApiAbstractService { protected static function getTextFieldName($name) { if (strlen($name) > 255) { // Replace long field names with something unique and predictable. - return md5($name); + return drupal_hash_base64($name); } else { return $name; @@ -1035,9 +1054,9 @@ class SearchApiDbService extends SearchApiAbstractService { // Check for over-long tokens. $score = $v['score']; $v = $v['value']; - if (strlen($v) > 50) { + if (drupal_strlen($v) > 50) { $words = preg_split('/[^\p{L}\p{N}]+/u', $v, -1, PREG_SPLIT_NO_EMPTY); - if (count($words) > 1 && max(array_map('strlen', $words)) <= 50) { + if (count($words) > 1 && max(array_map('drupal_strlen', $words)) <= 50) { // Overlong token is due to bad tokenizing. // Check for "Tokenizer" preprocessor on index. if (empty($index->options['processors']['search_api_tokenizer']['status'])) { @@ -1054,11 +1073,11 @@ class SearchApiDbService extends SearchApiAbstractService { $tokens = array(); foreach ($words as $word) { - if (strlen($word) > 50) { + if (drupal_strlen($word) > 50) { watchdog('search_api_db', 'An overlong word (more than 50 characters) was encountered while indexing: %word.<br />' . 'Database search servers currently cannot index such words correctly – the word was therefore trimmed to the allowed length.', array('%word' => $word), WATCHDOG_WARNING); - $word = self::mbStrcut($word, 0, 50); + $word = drupal_substr($word, 0, 50); } $tokens[] = array( 'value' => $word, @@ -1079,8 +1098,8 @@ class SearchApiDbService extends SearchApiAbstractService { if ($original_type == 'date') { return date('c', $value); } - if (strlen($value) > 255) { - $value = self::mbStrcut($value, 0, 255); + if (drupal_strlen($value) > 255) { + $value = drupal_substr($value, 0, 255); watchdog('search_api_db', 'An overlong value (more than 255 characters) was encountered while indexing: %value.<br />' . 'Database search servers currently cannot index such values correctly – the value was therefore trimmed to the allowed length.', array('%value' => $value), WATCHDOG_WARNING); @@ -1162,13 +1181,10 @@ class SearchApiDbService extends SearchApiAbstractService { $db_query = $this->createDbQuery($query, $fields); - // Allow subclasses and other modules to alter the query (before a count - // query is constructed from it). - drupal_alter('search_api_db_query', $db_query, $query); - $this->preQuery($db_query, $query); - $time_processing_done = microtime(TRUE); - $results = array(); + $results = array( + 'results' => array(), + ); $skip_count = $query->getOption('skip result count'); if (!$skip_count) { @@ -1191,7 +1207,6 @@ class SearchApiDbService extends SearchApiAbstractService { $this->setQuerySort($query, $db_query, $fields); $result = $db_query->execute(); - $time_queries_done = microtime(TRUE); foreach ($result as $row) { $results['results'][$row->item_id] = array( @@ -1203,10 +1218,7 @@ class SearchApiDbService extends SearchApiAbstractService { $results['result count'] = !empty($results['results']); } } - else { - $time_queries_done = microtime(TRUE); - $results['results'] = array(); - } + $time_queries_done = microtime(TRUE); $results['warnings'] = array_keys($this->warnings); $results['ignored'] = array_keys($this->ignored); @@ -1309,6 +1321,10 @@ class SearchApiDbService extends SearchApiAbstractService { $db_query->addMetaData('search_api_query', $query); $db_query->addMetaData('search_api_db_fields', $fields); + // Allow subclasses and other modules to alter the query. + drupal_alter('search_api_db_query', $db_query, $query); + $this->preQuery($db_query, $query); + return $db_query; } @@ -1385,7 +1401,12 @@ class SearchApiDbService extends SearchApiAbstractService { $words = preg_split('/[^\p{L}\p{N}]+/u', $proc, -1, PREG_SPLIT_NO_EMPTY); if (count($words) > 1) { $proc = $this->splitKeys($words); - $proc['#conjunction'] = 'AND'; + if ($proc) { + $proc['#conjunction'] = 'AND'; + } + else { + $proc = NULL; + } } return $proc; } @@ -1521,12 +1542,13 @@ class SearchApiDbService extends SearchApiAbstractService { // "word", which we remove since it will be useless to us in this case. $columns = &$db_query->getFields(); unset($columns['word']); - foreach (array_keys($columns) as $column) { - $db_query->groupBy($column); + foreach ($columns as $column => $info) { + $db_query->groupBy($info['table'] . '.' . $column); } foreach ($words as $i => $word) { - $db_or->condition('t.word', '%' . $this->connection->escapeLike($word) . '%', 'LIKE'); + $like = '%' . $this->connection->escapeLike($word) . '%'; + $db_or->condition('t.word', $like, 'LIKE'); // Add an expression for each keyword that shows whether the indexed // word matches that particular keyword. That way we don't return a @@ -1534,7 +1556,7 @@ class SearchApiDbService extends SearchApiAbstractService { // multiple keywords. We also remember the column name so we can // afterwards verify that each word matched at least once. $alias = 'w' . $i; - $alias = $db_query->addExpression("t.word LIKE '%" . $this->connection->escapeLike($word) . "%'", $alias); + $alias = $db_query->addExpression("CASE WHEN t.word LIKE :like_$alias THEN 1 ELSE 0 END", $alias, array(":like_$alias" => $like)); $db_query->groupBy($alias); $word_hits[] = $alias; } @@ -1651,7 +1673,7 @@ class SearchApiDbService extends SearchApiAbstractService { */ protected function createFilterCondition(SearchApiQueryFilterInterface $filter, array $fields, SelectQueryInterface $db_query) { $cond = db_condition($filter->getConjunction()); - // Store whether a JOIN alrady occurred for a field, so we don't JOIN + // Store whether a JOIN already occurred for a field, so we don't JOIN // repeatedly for OR filters. $first_join = array(); // Store the table aliases for the fields in this condition group. @@ -1669,15 +1691,19 @@ class SearchApiDbService extends SearchApiAbstractService { } $field = $fields[$f[0]]; $not_equals = $f[2] == '<>' || $f[2] == '!='; + $text_type = search_api_is_text_type($field['type']); // If the field is in its own table, we have to check for NULL values in // a special way (i.e., check for missing entries in that table). - if ($f[1] === NULL && $field['column'] === 'value') { + if ($f[1] === NULL && ($field['column'] === 'value' || $text_type)) { $query = $this->connection->select($field['table'], 't') ->fields('t', array('item_id')); + if ($text_type) { + $query->condition('t.field_name', $f[0]); + } $cond->condition('t.item_id', $query, $not_equals ? 'IN' : 'NOT IN'); continue; } - if (search_api_is_text_type($field['type'])) { + if ($text_type) { $keys = $this->prepareKeys($f[1]); if (!isset($keys)) { continue; @@ -1811,6 +1837,10 @@ class SearchApiDbService extends SearchApiAbstractService { $db_query->orderBy('item_id', $order); continue; } + if ($field_name == 'search_api_random') { + $db_query->orderRandom(); + continue; + } if (!isset($fields[$field_name])) { throw new SearchApiException(t('Trying to sort on unknown field @field.', array('@field' => $field_name))); } @@ -1900,7 +1930,7 @@ class SearchApiDbService extends SearchApiAbstractService { // IS NOT NULL for shared tables. $is_text_type = search_api_is_text_type($field['type']); $alias = $this->getTableAlias($field, $select, TRUE, $facet['missing'] ? 'leftJoin' : 'innerJoin'); - $select->addField($alias, $is_text_type ? 'word' : $field['column'], 'value'); + $select->addField($alias, $field['column'], 'value'); if ($is_text_type) { $select->condition("$alias.field_name", $this->getTextFieldName($facet['field'])); } @@ -1946,7 +1976,12 @@ class SearchApiDbService extends SearchApiAbstractService { if ($values) { $select->condition($field['column'], $values, 'NOT IN'); } - $select->isNotNull($field['column']); + if ($is_text_type) { + $select->condition('t.field_name', $this->getTextFieldName($facet['field'])); + } + else { + $select->isNotNull($field['column']); + } // Add tags and metadata. $select->addTag('search_api_db_facet_all'); @@ -1991,7 +2026,7 @@ class SearchApiDbService extends SearchApiAbstractService { * The name of the temporary table, or FALSE on failure. */ protected function getTemporaryResultsTable(SelectQueryInterface $db_query) { - // We only need the id field, not the score. + // We only need the ID column, not the score. $fields = &$db_query->getFields(); unset($fields['score']); if (count($fields) != 1 || !isset($fields['item_id'])) { @@ -2007,6 +2042,11 @@ class SearchApiDbService extends SearchApiAbstractService { $group_by = &$db_query->getGroupBy(); $group_by = array_intersect_key($group_by, array('t.item_id' => TRUE)); + // The order of results also doesn't matter here. Also, this might lead to + // errors if the ORDER BY clause references any expressions we removed. + $sort = &$db_query->getOrderBy(); + $sort = array(); + $db_query->distinct(); if (!$db_query->preExecute()) { return FALSE; @@ -2090,23 +2130,40 @@ class SearchApiDbService extends SearchApiAbstractService { 'pass' => $pass, )); - // We need a list of all current results to match the suggestions against. - // However, since MySQL doesn't allow using a temporary table multiple - // times in one query, we regrettably have to do it this way. - if (count($query->getFields()) > 1) { - $all_results = $db_query->execute()->fetchCol(); - // Compute the total number of results so we can later sort out matches - // that occur too often. - $total = count($all_results); + $text_fields = array(); + foreach ($query->getFields() as $field) { + if (isset($fields[$field]) && search_api_is_text_type($fields[$field]['type'])) { + $text_fields[] = $field; + } } - else { + if (empty($text_fields)) { + return array(); + } + + // For each text field that will be searched, store the item IDs in a + // temporary table. This is unfortunately necessary since MySQL doesn't + // allow using a temporary table multiple times in a single query. + $all_results = array(); + $total = NULL; + $first_temp_table = TRUE; + foreach ($text_fields as $field) { $table = $this->getTemporaryResultsTable($db_query); if (!$table) { return array(); } - $all_results = $this->connection->select($table, 't') + if ($first_temp_table) { + // For subsequent temporary tables, just use a plain SELECT over the + // first to fill them, instead of the (potentially very complex) + // search query. + $first_temp_table = FALSE; + $db_query = $this->connection->select($table) + ->fields($table, array('item_id')); + } + $all_results[$field] = $this->connection->select($table, 't') ->fields('t', array('item_id')); - $total = $this->connection->query("SELECT COUNT(item_id) FROM {{$table}}")->fetchField(); + if ($total === NULL) { + $total = $this->connection->query("SELECT COUNT(item_id) FROM {{$table}}")->fetchField(); + } } $max_occurrences = max(1, floor($total * variable_get('search_api_db_autocomplete_max_occurrences', 0.9))); @@ -2118,13 +2175,10 @@ class SearchApiDbService extends SearchApiAbstractService { } $word_query = NULL; - foreach ($query->getFields() as $field) { - if (!isset($fields[$field]) || !search_api_is_text_type($fields[$field]['type'])) { - continue; - } + foreach ($text_fields as $field) { $field_query = $this->connection->select($fields[$field]['table'], 't') ->fields('t', array('word', 'item_id')) - ->condition('item_id', $all_results, 'IN') + ->condition('item_id', $all_results[$field], 'IN') ->condition('field_name', $this->getTextFieldName($field)); if ($pass == 1) { $field_query->condition('word', $incomplete_like, 'LIKE') @@ -2175,7 +2229,7 @@ class SearchApiDbService extends SearchApiAbstractService { foreach ($fields as $key => $field) { // Legacy fields do not have column set. if (!isset($field['column'])) { - $fields[$key]['column'] = 'value'; + $fields[$key]['column'] = search_api_is_text_type($field['type']) ? 'word' : 'value'; } } return $fields; diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/CHANGELOG.txt b/profiles/wcm_base/modules/contrib/search_api_solr/CHANGELOG.txt index b6d30370788f910a4df670d8906675d9b36de793..68fe9882f4b9b58b1246ccd15b51b8f553bfd7d0 100644 --- a/profiles/wcm_base/modules/contrib/search_api_solr/CHANGELOG.txt +++ b/profiles/wcm_base/modules/contrib/search_api_solr/CHANGELOG.txt @@ -1,3 +1,26 @@ +Search API Solr Search 1.12 (2017-02-23): +----------------------------------------- +- #2612770 by Temoor, drunken monkey: Fixed conjunction in complex filter + conditions. +- #2711685 by berliner: Added support for Solr 6. +- #2842661 by gabrielu, drunken monkey: Fixed duplicate code line in + clearCache(). +- #2834159 by zniki.ru: Fixed left-over explicit + SearchApiSolrConnection::escapeFieldName() call. +- #2677912 by jts86, mian3010: Added option to disable committing for Solr. +- #2828473 by detroz: Fixed incorrect variable initialization. +- #2826565 by Sardis, drunken monkey: Fixed multi-valued field highlighting. +- #2807327 by drunken monkey: Fixed configuration form descriptions. +- #2772199 by drunken monkey: Added a warning to the description for the + highlighting server option. +- #2733625 by joelstein, drunken monkey: Fixed notice in + Connection::getFields(). + +Search API Solr Search 1.11 (2016-07-06): +----------------------------------------- +- #2710397 by drunken monkey: Fixed escaping of highlighting tags. +- #2636016 by drunken monkey: Fixed location search distance facets. + Search API Solr Search 1.10 (2016-03-14): ----------------------------------------- - #2604322 by lex0r, drunken monkey: Added the option to log all Solr queries. diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/includes/service.inc b/profiles/wcm_base/modules/contrib/search_api_solr/includes/service.inc index 8f59e1ddfa021bef0a68813ef51171c32926c324..e80b35fadaef05eca35ccba2d0c3f6d55d0efbc5 100644 --- a/profiles/wcm_base/modules/contrib/search_api_solr/includes/service.inc +++ b/profiles/wcm_base/modules/contrib/search_api_solr/includes/service.inc @@ -82,6 +82,7 @@ class SearchApiSolrService extends SearchApiAbstractService { 'skip_schema_check' => FALSE, 'log_query' => FALSE, 'log_response' => FALSE, + 'commits_disabled' => FALSE, 'solr_version' => '', 'http_method' => 'AUTO', // Default to TRUE for new servers, but to FALSE for existing ones. @@ -163,7 +164,7 @@ class SearchApiSolrService extends SearchApiAbstractService { $form['path'] = array( '#type' => 'textfield', '#title' => t('Solr path'), - '#description' => t('The path that identifies the Solr instance to use on the server. (For Solr 4.x servers, this should include the name of the core to use.)'), + '#description' => t('The path that identifies the Solr instance to use on the server. (For Solr versions 4 and above, this should include the name of the core to use.)'), '#default_value' => $options['path'], ); @@ -213,7 +214,7 @@ class SearchApiSolrService extends SearchApiAbstractService { $form['advanced']['highlight_data'] = array( '#type' => 'checkbox', '#title' => t('Highlight retrieved data'), - '#description' => t('When retrieving result data from the Solr server, try to highlight the search terms in the returned fulltext fields.'), + '#description' => t('When retrieving result data from the Solr server, try to highlight the search terms in the returned fulltext fields. <strong>Note:</strong> Do not use the "Highlighting" processor for the index together with this option – use one or the other.'), '#default_value' => $options['highlight_data'], ); // Highlighting retrieved data only makes sense when we retrieve data. @@ -224,13 +225,13 @@ class SearchApiSolrService extends SearchApiAbstractService { $form['advanced']['skip_schema_check'] = array( '#type' => 'checkbox', '#title' => t('Skip schema verification'), - '#description' => t('Skip the automatic check for schema-compatibillity. Use this override if you are seeing an error-message about an incompatible schema.xml configuration file, and you are sure the configuration is compatible.'), + '#description' => t('Skip the automatic check for schema-compatibility. Use this override if you are seeing an error-message about an incompatible schema.xml configuration file, and you are sure the configuration is compatible.'), '#default_value' => $options['skip_schema_check'], ); $form['advanced']['solr_version'] = array( '#type' => 'select', '#title' => t('Solr version override'), - '#description' => t('Specify the Solr version manually in case it cannot be retrived automatically. The version can be found in the Solr admin interface under "Solr Specification Version" or "solr-spec"'), + '#description' => t('Specify the Solr version manually in case it cannot be retrieved automatically. The version can be found in the Solr admin interface under "Solr Specification Version" or "solr-spec".'), '#options' => array( '' => t('Determine automatically'), '3' => '3.x', @@ -262,6 +263,12 @@ class SearchApiSolrService extends SearchApiAbstractService { '#description' => t('Log all search result responses received from Solr. NOTE: This may slow down your site since all response data (including possible retrieved data) will be saved in the Drupal log.'), '#default_value' => $options['log_response'], ); + $form['advanced']['commits_disabled'] = array( + '#type' => 'checkbox', + '#title' => t('Disable explicit committing'), + '#description' => t('Do not send any commit commands to the Solr server.'), + '#default_value' => $options['commits_disabled'], + ); if (module_exists('search_api_autocomplete')) { $form['advanced']['autocomplete'] = array( @@ -586,7 +593,7 @@ class SearchApiSolrService extends SearchApiAbstractService { // Now add all fields contained in the item, with dynamic fields. Also, // gather the contents of all text fields to also add them to "content". - $text_content = ''; + $text_content = array(); foreach ($item as $key => $field) { // If the field is not known for the index, something weird has // happened. We refuse to index the items and hope that the others are @@ -949,7 +956,7 @@ class SearchApiSolrService extends SearchApiAbstractService { unset($radius); $field = $fields[$spatial['field']]; - $escaped_field = SearchApiSolrConnection::escapeFieldName($field); + $escaped_field = call_user_func(array($this->connection_class, 'escapeFieldName'), $field); // If proper bbox coordinates were given use them to filter. if (isset($spatial['bbox'])) { @@ -983,7 +990,7 @@ class SearchApiSolrService extends SearchApiAbstractService { // If the fq consists only of a filter on this field, replace it with // a range. $preg_field = preg_quote($escaped_field, '/'); - if (preg_match('/^' . $preg_field . ':\["?(\*|\d+(?:\.\d+)?)"? TO "?(\*|\d+(?:\.\d+)?)"?\]$/', $value, $m)) { + if (preg_match('/^(?:\{!tag[^}]+\})?' . $preg_field . ':\["?(\*|\d+(?:\.\d+)?)"? TO "?(\*|\d+(?:\.\d+)?)"?\]$/', $value, $m)) { unset($fq[$key]); if ($m[1] && is_numeric($m[1])) { $min_radius = isset($min_radius) ? max($min_radius, $m[1]) : $m[1]; @@ -1367,6 +1374,7 @@ class SearchApiSolrService extends SearchApiAbstractService { foreach ($response->highlighting->$id->content as $snippet) { $snippet = strip_tags($snippet); $snippet = preg_replace('/^.*>|<.*$/', '', $snippet); + $snippet = check_plain($snippet); $snippet = $this->formatHighlighting($snippet); // The created fragments sometimes have leading or trailing punctuation. // We remove that here for all common cases, but take care not to remove @@ -1380,9 +1388,27 @@ class SearchApiSolrService extends SearchApiAbstractService { $prefix_length = strlen($prefix); foreach ($field_mapping as $search_api_property => $solr_property) { if (substr($solr_property, 0, $prefix_length) == $prefix && !empty($response->highlighting->$id->$solr_property)) { - // Contrary to above, we here want to preserve HTML, so we just - // replace the [HIGHLIGHT] tags with the appropriate format. - $fields[$search_api_property] = $this->formatHighlighting($response->highlighting->$id->$solr_property); + $value = $response->highlighting->$id->$solr_property; + $value = $this->sanitizeHighlightValue($value, $search_api_property); + // Remove highlight prefixes and suffixes so we could compare values + // in order to replace the correspond items. + $orig_value = preg_replace('#\[(/?)HIGHLIGHT\]#', '', $value); + $field_values = $this->sanitizeHighlightValue($fields[$search_api_property]); + foreach ($field_values as $delta => $field_value) { + foreach ($orig_value as $num => $item) { + if ($item === $field_value) { + $field_values[$delta] = $this->formatHighlighting($value[$num]); + $change = TRUE; + continue 2; + } + } + } + if (!empty($change)) { + $fields[$search_api_property] = array( + '#value' => $field_values, + '#sanitize_callback' => FALSE, + ); + } } } } @@ -1390,13 +1416,34 @@ class SearchApiSolrService extends SearchApiAbstractService { return $output; } + /** + * Sanitizes a highlighted field value. + * + * @param string|array $value + * Either a highlighted field value, or an array of such values. + * @param string|null $field_id + * (optional) The ID of the field for which this sanitizing occurs, if any. + * + * @return string|array + * The sanitized input. + */ + protected function sanitizeHighlightValue($value, $field_id = NULL) { + if (is_array($value)) { + foreach ($value as $i => $nested_value) { + $value[$i] = $this->sanitizeHighlightValue($nested_value, $field_id); + } + return $value; + } + return check_plain(strip_tags($value)); + } + /** * Changes highlighting tags from our custom, HTML-safe ones to HTML. * - * @param string|array $snippet + * @param string|string[] $snippet * The snippet(s) to format. * - * @return string|array + * @return string|string[] * The snippet(s), properly formatted as HTML. */ protected function formatHighlighting($snippet) { @@ -1600,9 +1647,7 @@ class SearchApiSolrService extends SearchApiAbstractService { elseif ($f instanceof SearchApiQueryFilterInterface) { $q = $this->createFilterQueries($f, $solr_fields, $fields); if ($filter->getConjunction() != $f->getConjunction() && count($q) > 1) { - // $or == TRUE means the nested filter has conjunction AND, and vice versa - $sep = $or ? ' ' : ' OR '; - $fq[] = '((' . implode(')' . $sep . '(', $q) . '))'; + $fq[] = '((' . implode(') ' . $f->getConjunction() . ' (', $q) . '))'; } else { $fq = array_merge($fq, $q); @@ -2328,6 +2373,10 @@ class SearchApiSolrService extends SearchApiAbstractService { * Sends a commit command to the Solr server. */ public function commit() { + // If committing has been disabled altogether, do nothing here. + if (!empty($this->options['commits_disabled'])) { + return; + } try { $this->connect(); return $this->solr->commit(FALSE); diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/includes/solr_connection.inc b/profiles/wcm_base/modules/contrib/search_api_solr/includes/solr_connection.inc index 5e3e8f55318abaf04aa35983064d20011fcfc63c..6279f05d5ae6de26eea664d64b87652c5ac20c67 100644 --- a/profiles/wcm_base/modules/contrib/search_api_solr/includes/solr_connection.inc +++ b/profiles/wcm_base/modules/contrib/search_api_solr/includes/solr_connection.inc @@ -367,8 +367,11 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface { */ public function getFields($num_terms = 0) { $fields = array(); - foreach ($this->getLuke($num_terms)->fields as $name => $info) { - $fields[$name] = new SearchApiSolrField($info); + $luke_data = $this->getLuke($num_terms); + if (isset($luke_data->fields)) { + foreach ($luke_data->fields as $name => $info) { + $fields[$name] = new SearchApiSolrField($info); + } } return $fields; } @@ -514,7 +517,6 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface { public function clearCache() { if ($cid = $this->getCacheId()) { cache_clear_all($cid, 'cache_search_api_solr', TRUE); - cache_clear_all($cid, 'cache_search_api_solr', TRUE); } $this->luke = array(); $this->stats = NULL; diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/search_api_solr.info b/profiles/wcm_base/modules/contrib/search_api_solr/search_api_solr.info index 6547a4e3ec76b3a7a9b9853d5af6d7717d0f04db..0ea0d30cfce7d43999195cd690b3345555983b04 100644 --- a/profiles/wcm_base/modules/contrib/search_api_solr/search_api_solr.info +++ b/profiles/wcm_base/modules/contrib/search_api_solr/search_api_solr.info @@ -11,9 +11,9 @@ files[] = includes/solr_connection.interface.inc files[] = includes/solr_field.inc files[] = includes/spellcheck.inc -; Information added by Drupal.org packaging script on 2016-03-14 -version = "7.x-1.10" +; Information added by Drupal.org packaging script on 2017-02-23 +version = "7.x-1.12" core = "7.x" project = "search_api_solr" -datestamp = "1457970937" +datestamp = "1487844794" diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/elevate.xml b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/elevate.xml new file mode 100644 index 0000000000000000000000000000000000000000..71ea0006cf12153977aa618d36761e7141071d31 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/elevate.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<!-- + This file allows you to boost certain search items to the top of search + results. You can find out an item's ID by searching directly on the Solr + server. The item IDs are in general constructed as follows: + Search API: + $document->id = $index_id . '-' . $item_id; + Apache Solr Search Integration: + $document->id = $site_hash . '/' . $entity_type . '/' . $entity->id; + + If you want this file to be automatically re-loaded when a Solr commit takes + place (e.g., if you have an automatic script active which updates elevate.xml + according to newly-indexed data), place it into Solr's data/ directory. + Otherwise, place it with the other configuration files into the conf/ + directory. + + See http://wiki.apache.org/solr/QueryElevationComponent for more information. +--> + +<elevate> +<!-- Example for ranking the node #1 first in searches for "example query": --> +<!-- + <query text="example query"> + <doc id="default_node_index-1" /> + <doc id="7v3jsc/node/1" /> + </query> +--> +<!-- Multiple <query> elements can be specified, contained in one <elevate>. --> +<!-- <query text="...">...</query> --> +</elevate> diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/mapping-ISOLatin1Accent.txt b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/mapping-ISOLatin1Accent.txt new file mode 100644 index 0000000000000000000000000000000000000000..b92d03c55005ef6107723cd3575be7f77a7f4346 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/mapping-ISOLatin1Accent.txt @@ -0,0 +1,14 @@ +# This file contains character mappings for the default fulltext field type. +# The source characters (on the left) will be replaced by the respective target +# characters before any other processing takes place. +# Lines starting with a pound character # are ignored. +# +# For sensible defaults, use the mapping-ISOLatin1Accent.txt file distributed +# with the example application of your Solr version. +# +# Examples: +# "À" => "A" +# "\u00c4" => "A" +# "\u00c4" => "\u0041" +# "æ" => "ae" +# "\n" => " " diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/protwords.txt b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/protwords.txt new file mode 100644 index 0000000000000000000000000000000000000000..cda858149750acd3e5f7cf00c8deecb167fa6193 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/protwords.txt @@ -0,0 +1,7 @@ +#----------------------------------------------------------------------- +# This file blocks words from being operated on by the stemmer and word delimiter. +& +< +> +' +" diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/schema.xml b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/schema.xml new file mode 100644 index 0000000000000000000000000000000000000000..d813d128b290c5ca4adc53d0f5f369da40323dbf --- /dev/null +++ b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/schema.xml @@ -0,0 +1,693 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<!-- + This is the Solr schema file. This file should be named "schema.xml" and + should be in the conf directory under the solr home + (i.e. ./solr/conf/schema.xml by default) + or located where the classloader for the Solr webapp can find it. + + For more information, on how to customize this file, please see + http://wiki.apache.org/solr/SchemaXml +--> + +<schema name="drupal-4.4-solr-6.x" version="1.5"> + <!-- attribute "name" is the name of this schema and is only used for + display purposes. Applications should change this to reflect the nature + of the search collection. + version="1.2" is Solr's version number for the schema syntax and + semantics. It should not normally be changed by applications. + + 1.0: multiValued attribute did not exist, all fields are multiValued by + nature + 1.1: multiValued attribute introduced, false by default + 1.2: omitTermFreqAndPositions attribute introduced, true by default + except for text fields. + 1.3: removed optional field compress feature + 1.4: autoGeneratePhraseQueries attribute introduced to drive + QueryParser behavior when a single string produces multiple + tokens. Defaults to off for version >= 1.4 + 1.5: omitNorms defaults to true for primitive field types + (int, float, boolean, string...) + --> + + <types> + <!-- field type definitions. The "name" attribute is + just a label to be used by field definitions. The "class" + attribute and any other attributes determine the real + behavior of the fieldType. + Class names starting with "solr" refer to java classes in the + org.apache.solr.analysis package. + --> + + <!-- The StrField type is not analyzed, but indexed/stored verbatim. + - StrField and TextField support an optional compressThreshold which + limits compression (if enabled in the derived fields) to values which + exceed a certain size (in characters). + --> + <fieldType name="string" class="solr.StrField" sortMissingLast="true"/> + + <!-- boolean type: "true" or "false" --> + <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/> + <!--Binary data type. The data should be sent/retrieved in as Base64 encoded Strings --> + <fieldtype name="binary" class="solr.BinaryField"/> + + <!-- The optional sortMissingLast and sortMissingFirst attributes are + currently supported on types that are sorted internally as strings. + - If sortMissingLast="true", then a sort on this field will cause documents + without the field to come after documents with the field, + regardless of the requested sort order (asc or desc). + - If sortMissingFirst="true", then a sort on this field will cause documents + without the field to come before documents with the field, + regardless of the requested sort order. + - If sortMissingLast="false" and sortMissingFirst="false" (the default), + then default lucene sorting will be used which places docs without the + field first in an ascending sort and last in a descending sort. + --> + + <!-- numeric field types that can be sorted, but are not optimized for range queries --> + <fieldType name="integer" class="solr.TrieIntField" precisionStep="0" positionIncrementGap="0"/> + <fieldType name="float" class="solr.TrieFloatField" precisionStep="0" positionIncrementGap="0"/> + <fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/> + <fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" positionIncrementGap="0"/> + + <!-- + Note: + These should only be used for compatibility with existing indexes (created with older Solr versions) + or if "sortMissingFirst" or "sortMissingLast" functionality is needed. Use Trie based fields instead. + + Numeric field types that manipulate the value into + a string value that isn't human-readable in its internal form, + but with a lexicographic ordering the same as the numeric ordering, + so that range queries work correctly. + --> + <fieldType name="sint" class="solr.TrieIntField" sortMissingLast="true"/> + <fieldType name="sfloat" class="solr.TrieFloatField" sortMissingLast="true"/> + <fieldType name="slong" class="solr.TrieLongField" sortMissingLast="true"/> + <fieldType name="sdouble" class="solr.TrieDoubleField" sortMissingLast="true"/> + + <!-- + Numeric field types that index each value at various levels of precision + to accelerate range queries when the number of values between the range + endpoints is large. See the javadoc for NumericRangeQuery for internal + implementation details. + + Smaller precisionStep values (specified in bits) will lead to more tokens + indexed per value, slightly larger index size, and faster range queries. + A precisionStep of 0 disables indexing at different precision levels. + --> + <fieldType name="tint" class="solr.TrieIntField" precisionStep="8" positionIncrementGap="0"/> + <fieldType name="tfloat" class="solr.TrieFloatField" precisionStep="8" positionIncrementGap="0"/> + <fieldType name="tlong" class="solr.TrieLongField" precisionStep="8" positionIncrementGap="0"/> + <fieldType name="tdouble" class="solr.TrieDoubleField" precisionStep="8" positionIncrementGap="0"/> + + <!-- + The ExternalFileField type gets values from an external file instead of the + index. This is useful for data such as rankings that might change frequently + and require different update frequencies than the documents they are + associated with. + --> + <fieldType name="file" keyField="id" defVal="1" stored="false" indexed="false" class="solr.ExternalFileField" valType="float"/> + + <!-- The format for this date field is of the form 1995-12-31T23:59:59Z, and + is a more restricted form of the canonical representation of dateTime + http://www.w3.org/TR/xmlschema-2/#dateTime + The trailing "Z" designates UTC time and is mandatory. + Optional fractional seconds are allowed: 1995-12-31T23:59:59.999Z + All other components are mandatory. + + Expressions can also be used to denote calculations that should be + performed relative to "NOW" to determine the value, ie... + + NOW/HOUR + ... Round to the start of the current hour + NOW-1DAY + ... Exactly 1 day prior to now + NOW/DAY+6MONTHS+3DAYS + ... 6 months and 3 days in the future from the start of + the current day + + Consult the TrieDateField javadocs for more information. + + Note: For faster range queries, consider the tdate type + --> + <fieldType name="date" class="solr.TrieDateField" precisionStep="0" positionIncrementGap="0" sortMissingLast="true" omitNorms="true"/> + + <!-- A Trie based date field for faster date range queries and date faceting. --> + <fieldType name="tdate" class="solr.TrieDateField" precisionStep="6" positionIncrementGap="0"/> + + <!-- solr.TextField allows the specification of custom text analyzers + specified as a tokenizer and a list of token filters. Different + analyzers may be specified for indexing and querying. + + The optional positionIncrementGap puts space between multiple fields of + this type on the same document, with the purpose of preventing false phrase + matching across fields. + + For more info on customizing your analyzer chain, please see + http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters + --> + + <!-- One can also specify an existing Analyzer class that has a + default constructor via the class attribute on the analyzer element + <fieldType name="text_greek" class="solr.TextField"> + <analyzer class="org.apache.lucene.analysis.el.GreekAnalyzer"/> + </fieldType> + --> + + <!-- A text field that only splits on whitespace for exact matching of words --> + <fieldType name="text_ws" class="solr.TextField" omitNorms="true" positionIncrementGap="100"> + <analyzer> + <tokenizer class="solr.WhitespaceTokenizerFactory"/> + <filter class="solr.LowerCaseFilterFactory"/> + </analyzer> + </fieldType> + + <!-- A text field that uses WordDelimiterFilter to enable splitting and matching of + words on case-change, alpha numeric boundaries, and non-alphanumeric chars, + so that a query of "wifi" or "wi fi" could match a document containing "Wi-Fi". + Synonyms and stopwords are customized by external files, and stemming is enabled. + Duplicate tokens at the same position (which may result from Stemmed Synonyms or + WordDelim parts) are removed. + --> + <fieldType name="text" class="solr.TextField" positionIncrementGap="100"> + <analyzer type="index"> + <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/> + <tokenizer class="solr.WhitespaceTokenizerFactory"/> + <!-- in this example, we will only use synonyms at query time + <filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/> + --> + <!-- Case insensitive stop word removal. --> + <filter class="solr.StopFilterFactory" + ignoreCase="true" + words="stopwords.txt" + /> + <filter class="solr.WordDelimiterFilterFactory" + protected="protwords.txt" + generateWordParts="1" + generateNumberParts="1" + catenateWords="1" + catenateNumbers="1" + catenateAll="0" + splitOnCaseChange="0" + preserveOriginal="1"/> + <filter class="solr.LengthFilterFactory" min="2" max="100" /> + <filter class="solr.LowerCaseFilterFactory"/> + <filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/> + <filter class="solr.RemoveDuplicatesTokenFilterFactory"/> + </analyzer> + <analyzer type="query"> + <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/> + <tokenizer class="solr.WhitespaceTokenizerFactory"/> + <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/> + <filter class="solr.StopFilterFactory" + ignoreCase="true" + words="stopwords.txt" + /> + <filter class="solr.WordDelimiterFilterFactory" + protected="protwords.txt" + generateWordParts="1" + generateNumberParts="1" + catenateWords="0" + catenateNumbers="0" + catenateAll="0" + splitOnCaseChange="0" + preserveOriginal="1"/> + <filter class="solr.LengthFilterFactory" min="2" max="100" /> + <filter class="solr.LowerCaseFilterFactory"/> + <filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/> + <filter class="solr.RemoveDuplicatesTokenFilterFactory"/> + </analyzer> + <analyzer type="multiterm"> + <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/> + <tokenizer class="solr.WhitespaceTokenizerFactory"/> + <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/> + <filter class="solr.StopFilterFactory" + ignoreCase="true" + words="stopwords.txt" + /> + <filter class="solr.WordDelimiterFilterFactory" + protected="protwords.txt" + generateWordParts="1" + generateNumberParts="1" + catenateWords="0" + catenateNumbers="0" + catenateAll="0" + splitOnCaseChange="1" + preserveOriginal="1"/> + <filter class="solr.LengthFilterFactory" min="2" max="100" /> + <filter class="solr.LowerCaseFilterFactory"/> + <filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/> + <filter class="solr.RemoveDuplicatesTokenFilterFactory"/> + </analyzer> + </fieldType> + + <!-- An unstemmed text field - good if one does not know the language of the field --> + <fieldType name="text_und" class="solr.TextField" positionIncrementGap="100"> + <analyzer type="index"> + <tokenizer class="solr.WhitespaceTokenizerFactory"/> + <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" /> + <filter class="solr.WordDelimiterFilterFactory" + protected="protwords.txt" + generateWordParts="1" + generateNumberParts="1" + catenateWords="1" + catenateNumbers="1" + catenateAll="0" + splitOnCaseChange="0"/> + <filter class="solr.LengthFilterFactory" min="2" max="100" /> + <filter class="solr.LowerCaseFilterFactory"/> + </analyzer> + <analyzer type="query"> + <tokenizer class="solr.WhitespaceTokenizerFactory"/> + <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/> + <filter class="solr.StopFilterFactory" + ignoreCase="true" + words="stopwords.txt" + /> + <filter class="solr.WordDelimiterFilterFactory" + protected="protwords.txt" + generateWordParts="1" + generateNumberParts="1" + catenateWords="0" + catenateNumbers="0" + catenateAll="0" + splitOnCaseChange="0"/> + <filter class="solr.LengthFilterFactory" min="2" max="100" /> + <filter class="solr.LowerCaseFilterFactory"/> + </analyzer> + <analyzer type="multiterm"> + <tokenizer class="solr.WhitespaceTokenizerFactory"/> + <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/> + <filter class="solr.StopFilterFactory" + ignoreCase="true" + words="stopwords.txt" + /> + <filter class="solr.WordDelimiterFilterFactory" + protected="protwords.txt" + generateWordParts="1" + generateNumberParts="1" + catenateWords="0" + catenateNumbers="0" + catenateAll="0" + splitOnCaseChange="0"/> + <filter class="solr.LengthFilterFactory" min="2" max="100" /> + <filter class="solr.LowerCaseFilterFactory"/> + </analyzer> + </fieldType> + + <!-- Edge N gram type - for example for matching against queries with results + KeywordTokenizer leaves input string intact as a single term. + see: http://www.lucidimagination.com/blog/2009/09/08/auto-suggest-from-popular-queries-using-edgengrams/ + --> + <fieldType name="edge_n2_kw_text" class="solr.TextField" omitNorms="true" positionIncrementGap="100"> + <analyzer type="index"> + <tokenizer class="solr.KeywordTokenizerFactory"/> + <filter class="solr.LowerCaseFilterFactory"/> + <filter class="solr.EdgeNGramFilterFactory" minGramSize="2" maxGramSize="25" /> + </analyzer> + <analyzer type="query"> + <tokenizer class="solr.KeywordTokenizerFactory"/> + <filter class="solr.LowerCaseFilterFactory"/> + </analyzer> + </fieldType> + <!-- Setup simple analysis for spell checking --> + + <fieldType name="textSpell" class="solr.TextField" positionIncrementGap="100"> + <analyzer> + <tokenizer class="solr.StandardTokenizerFactory" /> + <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/> + <filter class="solr.LengthFilterFactory" min="4" max="20" /> + <filter class="solr.LowerCaseFilterFactory" /> + <filter class="solr.RemoveDuplicatesTokenFilterFactory" /> + </analyzer> + </fieldType> + + <!-- This is an example of using the KeywordTokenizer along + With various TokenFilterFactories to produce a sortable field + that does not include some properties of the source text + --> + <fieldType name="sortString" class="solr.TextField" sortMissingLast="true" omitNorms="true"> + <analyzer> + <!-- KeywordTokenizer does no actual tokenizing, so the entire + input string is preserved as a single token + --> + <tokenizer class="solr.KeywordTokenizerFactory"/> + <!-- The LowerCase TokenFilter does what you expect, which can be + when you want your sorting to be case insensitive + --> + <filter class="solr.LowerCaseFilterFactory" /> + <!-- The TrimFilter removes any leading or trailing whitespace --> + <filter class="solr.TrimFilterFactory" /> + <!-- The PatternReplaceFilter gives you the flexibility to use + Java Regular expression to replace any sequence of characters + matching a pattern with an arbitrary replacement string, + which may include back refrences to portions of the orriginal + string matched by the pattern. + + See the Java Regular Expression documentation for more + infomation on pattern and replacement string syntax. + + http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/package-summary.html + + <filter class="solr.PatternReplaceFilterFactory" + pattern="(^\p{Punct}+)" replacement="" replace="all" + /> + --> + </analyzer> + </fieldType> + + <!-- The "RandomSortField" is not used to store or search any + data. You can declare fields of this type it in your schema + to generate pseudo-random orderings of your docs for sorting + or function purposes. The ordering is generated based on the field + name and the version of the index. As long as the index version + remains unchanged, and the same field name is reused, + the ordering of the docs will be consistent. + If you want different psuedo-random orderings of documents, + for the same version of the index, use a dynamicField and + change the field name in the request. + --> + <fieldType name="rand" class="solr.RandomSortField" indexed="true" /> + + <!-- Fulltext type for matching words based on how they sound – i.e., + "phonetic matching". + --> + <fieldType name="phonetic" class="solr.TextField" > + <analyzer> + <tokenizer class="solr.StandardTokenizerFactory"/> + <filter class="solr.DoubleMetaphoneFilterFactory" inject="false"/> + </analyzer> + </fieldType> + + <!-- since fields of this type are by default not stored or indexed, + any data added to them will be ignored outright. --> + <fieldType name="ignored" stored="false" indexed="false" multiValued="true" class="solr.StrField" /> + + <!-- This point type indexes the coordinates as separate fields (subFields) + If subFieldType is defined, it references a type, and a dynamic field + definition is created matching *___<typename>. Alternately, if + subFieldSuffix is defined, that is used to create the subFields. + Example: if subFieldType="double", then the coordinates would be + indexed in fields myloc_0___double,myloc_1___double. + Example: if subFieldSuffix="_d" then the coordinates would be indexed + in fields myloc_0_d,myloc_1_d + The subFields are an implementation detail of the fieldType, and end + users normally should not need to know about them. + --> + <fieldType name="point" class="solr.PointType" dimension="2" subFieldType="tdouble"/> + + <!-- A specialized field for geospatial search. If indexed, this fieldType must not be multivalued. --> + <fieldType name="location" class="solr.LatLonType" subFieldType="tdouble"/> + + <!-- A Geohash is a compact representation of a latitude longitude pair in a single field. + See http://wiki.apache.org/solr/SpatialSearch + --> + <fieldtype name="geohash" class="solr.GeoHashField"/> + + <!-- Improved location type which supports advanced functionality like + filtering by polygons or other shapes, indexing shapes, multi-valued + fields, etc. + --> + <fieldType name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType" + geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers" /> + + <!-- Spatial rectangle (bounding box) field. It supports most spatial predicates, and has + special relevancy modes: score=overlapRatio|area|area2D (local-param to the query). DocValues is recommended for + relevancy. --> + <fieldType name="bbox" class="solr.BBoxField" + geo="true" distanceUnits="kilometers" numberType="_bbox_coord" /> + <fieldType name="_bbox_coord" class="solr.TrieDoubleField" precisionStep="8" docValues="true" stored="false"/> + + </types> + + <!-- Following is a dynamic way to include other types, added by other contrib modules --> + <xi:include href="schema_extra_types.xml" xmlns:xi="http://www.w3.org/2001/XInclude"> + <xi:fallback></xi:fallback> + </xi:include> + + <!-- Valid attributes for fields: + name: mandatory - the name for the field + type: mandatory - the name of a field type from the <types> fieldType + section + indexed: true if this field should be indexed (searchable or sortable) + stored: true if this field should be retrievable + docValues: true if this field should have doc values. Doc values are + useful for faceting, grouping, sorting and function queries. Although not + required, doc values will make the index faster to load, more + NRT-friendly and more memory-efficient. They however come with some + limitations: they are currently only supported by StrField, UUIDField + and all Trie*Fields, and depending on the field type, they might + require the field to be single-valued, be required or have a default + value (check the documentation of the field type you're interested in + for more information) + multiValued: true if this field may contain multiple values per document + omitNorms: (expert) set to true to omit the norms associated with + this field (this disables length normalization and index-time + boosting for the field, and saves some memory). Only full-text + fields or fields that need an index-time boost need norms. + Norms are omitted for primitive (non-analyzed) types by default. + termVectors: [false] set to true to store the term vector for a + given field. + When using MoreLikeThis, fields used for similarity should be + stored for best performance. + termPositions: Store position information with the term vector. + This will increase storage costs. + termOffsets: Store offset information with the term vector. This + will increase storage costs. + required: The field is required. It will throw an error if the + value does not exist + default: a value that should be used if no value is specified + when adding a document. + --> + <fields> + + <!-- The document id is usually derived from a site-spcific key (hash) and the + entity type and ID like: + Search Api : + The format used is $document->id = $index_id . '-' . $item_id + Apache Solr Search Integration + The format used is $document->id = $site_hash . '/' . $entity_type . '/' . $entity->id; + --> + <field name="id" type="string" indexed="true" stored="true" required="true" /> + + <!-- Add Solr Cloud version field as mentioned in + http://wiki.apache.org/solr/SolrCloud#Required_Config + --> + <field name="_version_" type="long" indexed="true" stored="true" multiValued="false"/> + + <!-- Search Api specific fields --> + <!-- item_id contains the entity ID, e.g. a node's nid. --> + <field name="item_id" type="string" indexed="true" stored="true" /> + <!-- index_id is the machine name of the search index this entry belongs to. --> + <field name="index_id" type="string" indexed="true" stored="true" /> + <!-- copyField commands copy one field to another at the time a document + is added to the index. It's used either to index the same field differently, + or to add multiple fields to the same field for easier/faster searching. --> + <!-- Since sorting by ID is explicitly allowed, store item_id also in a sortable way. --> + <copyField source="item_id" dest="sort_search_api_id" /> + + <!-- Apache Solr Search Integration specific fields --> + <!-- entity_id is the numeric object ID, e.g. Node ID, File ID --> + <field name="entity_id" type="long" indexed="true" stored="true" /> + <!-- entity_type is 'node', 'file', 'user', or some other Drupal object type --> + <field name="entity_type" type="string" indexed="true" stored="true" /> + <!-- bundle is a node type, or as appropriate for other entity types --> + <field name="bundle" type="string" indexed="true" stored="true"/> + <field name="bundle_name" type="string" indexed="true" stored="true"/> + <field name="site" type="string" indexed="true" stored="true"/> + <field name="hash" type="string" indexed="true" stored="true"/> + <field name="url" type="string" indexed="true" stored="true"/> + <!-- label is the default field for a human-readable string for this entity (e.g. the title of a node) --> + <field name="label" type="text" indexed="true" stored="true" termVectors="true" omitNorms="true"/> + <!-- The string version of the title is used for sorting --> + <copyField source="label" dest="sort_label"/> + + <!-- content is the default field for full text search - dump crap here --> + <field name="content" type="text" indexed="true" stored="true" termVectors="true"/> + <field name="teaser" type="text" indexed="false" stored="true"/> + <field name="path" type="string" indexed="true" stored="true"/> + <field name="path_alias" type="text" indexed="true" stored="true" termVectors="true" omitNorms="true"/> + + <!-- These are the fields that correspond to a Drupal node. The beauty of having + Lucene store title, body, type, etc., is that we retrieve them with the search + result set and don't need to go to the database with a node_load. --> + <field name="tid" type="long" indexed="true" stored="true" multiValued="true"/> + <field name="taxonomy_names" type="text" indexed="true" stored="false" termVectors="true" multiValued="true" omitNorms="true"/> + <!-- Copy terms to a single field that contains all taxonomy term names --> + <copyField source="tm_vid_*" dest="taxonomy_names"/> + + <!-- Here, default is used to create a "timestamp" field indicating + when each document was indexed.--> + <field name="timestamp" type="tdate" indexed="true" stored="true" default="NOW" multiValued="false"/> + + <!-- This field is used to build the spellchecker index --> + <field name="spell" type="textSpell" indexed="true" stored="true" multiValued="true"/> + + <!-- copyField commands copy one field to another at the time a document + is added to the index. It's used either to index the same field differently, + or to add multiple fields to the same field for easier/faster searching. --> + <copyField source="label" dest="spell"/> + <copyField source="content" dest="spell"/> + + <copyField source="ts_*" dest="spell"/> + <copyField source="tm_*" dest="spell"/> + + <!-- Dynamic field definitions. If a field name is not found, dynamicFields + will be used if the name matches any of the patterns. + RESTRICTION: the glob-like pattern in the name attribute must have + a "*" only at the start or the end. + EXAMPLE: name="*_i" will match any field ending in _i (like myid_i, z_i) + Longer patterns will be matched first. if equal size patterns + both match, the first appearing in the schema will be used. --> + + <!-- A set of fields to contain text extracted from HTML tag contents which we + can boost at query time. --> + <dynamicField name="tags_*" type="text" indexed="true" stored="false" omitNorms="true"/> + + <!-- For 2 and 3 letter prefix dynamic fields, the 1st letter indicates the data type and + the last letter is 's' for single valued, 'm' for multi-valued --> + + <!-- We use long for integer since 64 bit ints are now common in PHP. --> + <dynamicField name="is_*" type="long" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="im_*" type="long" indexed="true" stored="true" multiValued="true"/> + <!-- List of floats can be saved in a regular float field --> + <dynamicField name="fs_*" type="float" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="fm_*" type="float" indexed="true" stored="true" multiValued="true"/> + <!-- List of doubles can be saved in a regular double field --> + <dynamicField name="ps_*" type="double" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="pm_*" type="double" indexed="true" stored="true" multiValued="true"/> + <!-- List of booleans can be saved in a regular boolean field --> + <dynamicField name="bm_*" type="boolean" indexed="true" stored="true" multiValued="true"/> + <dynamicField name="bs_*" type="boolean" indexed="true" stored="true" multiValued="false"/> + <!-- Regular text (without processing) can be stored in a string field--> + <dynamicField name="ss_*" type="string" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="sm_*" type="string" indexed="true" stored="true" multiValued="true"/> + <!-- Normal text fields are for full text - the relevance of a match depends on the length of the text --> + <dynamicField name="ts_*" type="text" indexed="true" stored="true" multiValued="false" termVectors="true"/> + <dynamicField name="tm_*" type="text" indexed="true" stored="true" multiValued="true" termVectors="true"/> + <!-- Unstemmed text fields for full text - the relevance of a match depends on the length of the text --> + <dynamicField name="tus_*" type="text_und" indexed="true" stored="true" multiValued="false" termVectors="true"/> + <dynamicField name="tum_*" type="text_und" indexed="true" stored="true" multiValued="true" termVectors="true"/> + <!-- These text fields omit norms - useful for extracted text like taxonomy_names --> + <dynamicField name="tos_*" type="text" indexed="true" stored="true" multiValued="false" termVectors="true" omitNorms="true"/> + <dynamicField name="tom_*" type="text" indexed="true" stored="true" multiValued="true" termVectors="true" omitNorms="true"/> + <!-- Special-purpose text fields --> + <dynamicField name="tes_*" type="edge_n2_kw_text" indexed="true" stored="true" multiValued="false" omitTermFreqAndPositions="true" /> + <dynamicField name="tem_*" type="edge_n2_kw_text" indexed="true" stored="true" multiValued="true" omitTermFreqAndPositions="true" /> + <dynamicField name="tws_*" type="text_ws" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="twm_*" type="text_ws" indexed="true" stored="true" multiValued="true"/> + + <!-- trie dates are preferred, so give them the 2 letter prefix --> + <dynamicField name="ds_*" type="tdate" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="dm_*" type="tdate" indexed="true" stored="true" multiValued="true"/> + <dynamicField name="its_*" type="tlong" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="itm_*" type="tlong" indexed="true" stored="true" multiValued="true"/> + <dynamicField name="fts_*" type="tfloat" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="ftm_*" type="tfloat" indexed="true" stored="true" multiValued="true"/> + <dynamicField name="pts_*" type="tdouble" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="ptm_*" type="tdouble" indexed="true" stored="true" multiValued="true"/> + <!-- Binary fields can be populated using base64 encoded data. Useful e.g. for embedding + a small image in a search result using the data URI scheme --> + <dynamicField name="xs_*" type="binary" indexed="false" stored="true" multiValued="false"/> + <dynamicField name="xm_*" type="binary" indexed="false" stored="true" multiValued="true"/> + <!-- In rare cases a date rather than tdate is needed for sortMissingLast --> + <dynamicField name="dds_*" type="date" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="ddm_*" type="date" indexed="true" stored="true" multiValued="true"/> + <!-- Sortable fields, good for sortMissingLast support & + We use long for integer since 64 bit ints are now common in PHP. --> + <dynamicField name="iss_*" type="slong" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="ism_*" type="slong" indexed="true" stored="true" multiValued="true"/> + <!-- In rare cases a sfloat rather than tfloat is needed for sortMissingLast --> + <dynamicField name="fss_*" type="sfloat" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="fsm_*" type="sfloat" indexed="true" stored="true" multiValued="true"/> + <dynamicField name="pss_*" type="sdouble" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="psm_*" type="sdouble" indexed="true" stored="true" multiValued="true"/> + <!-- In case a 32 bit int is really needed, we provide these fields. 'h' is mnemonic for 'half word', i.e. 32 bit on 64 arch --> + <dynamicField name="hs_*" type="integer" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="hm_*" type="integer" indexed="true" stored="true" multiValued="true"/> + <dynamicField name="hss_*" type="sint" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="hsm_*" type="sint" indexed="true" stored="true" multiValued="true"/> + <dynamicField name="hts_*" type="tint" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="htm_*" type="tint" indexed="true" stored="true" multiValued="true"/> + + <!-- Unindexed string fields that can be used to store values that won't be searchable --> + <dynamicField name="zs_*" type="string" indexed="false" stored="true" multiValued="false"/> + <dynamicField name="zm_*" type="string" indexed="false" stored="true" multiValued="true"/> + + <!-- Fields for location searches. + http://wiki.apache.org/solr/SpatialSearch#geodist_-_The_distance_function --> + <dynamicField name="points_*" type="point" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="pointm_*" type="point" indexed="true" stored="true" multiValued="true"/> + <dynamicField name="locs_*" type="location" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="locm_*" type="location" indexed="true" stored="true" multiValued="true"/> + <dynamicField name="geos_*" type="geohash" indexed="true" stored="true" multiValued="false"/> + <dynamicField name="geom_*" type="geohash" indexed="true" stored="true" multiValued="true"/> + <dynamicField name="bboxs_*" type="bbox" indexed="true" stored="true" multiValued="false" /> + <dynamicField name="bboxm_*" type="bbox" indexed="true" stored="true" multiValued="true" /> + <dynamicField name="rpts_*" type="location_rpt" indexed="true" stored="true" multiValued="false" /> + <dynamicField name="rptm_*" type="location_rpt" indexed="true" stored="true" multiValued="true" /> + + <!-- Special fields for Solr 5 functionality. --> + <dynamicField name="phons_*" type="phonetic" indexed="true" stored="true" multiValued="false" /> + <dynamicField name="phonm_*" type="phonetic" indexed="true" stored="true" multiValued="true" /> + + <!-- External file fields --> + <dynamicField name="eff_*" type="file"/> + + <!-- Sortable version of the dynamic string field --> + <dynamicField name="sort_*" type="sortString" indexed="true" stored="false"/> + <copyField source="ss_*" dest="sort_*"/> + + <!-- A random sort field --> + <dynamicField name="random_*" type="rand" indexed="true" stored="true"/> + + <!-- This field is used to store access information (e.g. node access grants), as opposed to field data --> + <dynamicField name="access_*" type="integer" indexed="true" stored="false" multiValued="true"/> + + <!-- The following causes solr to ignore any fields that don't already match an existing + field name or dynamic field, rather than reporting them as an error. + Alternately, change the type="ignored" to some other type e.g. "text" if you want + unknown fields indexed and/or stored by default --> + <dynamicField name="*" type="ignored" multiValued="true" /> + + </fields> + + <!-- Following is a dynamic way to include other fields, added by other contrib modules --> + <xi:include href="schema_extra_fields.xml" xmlns:xi="http://www.w3.org/2001/XInclude"> + <xi:fallback></xi:fallback> + </xi:include> + + <!-- Field to use to determine and enforce document uniqueness. + Unless this field is marked with required="false", it will be a required field + --> + <uniqueKey>id</uniqueKey> + + <!-- Similarity is the scoring routine for each document vs. a query. + A custom Similarity or SimilarityFactory may be specified here, but + the default is fine for most applications. + For more info: http://wiki.apache.org/solr/SchemaXml#Similarity + --> + <!-- + <similarity class="com.example.solr.CustomSimilarityFactory"> + <str name="paramkey">param value</str> + </similarity> + --> + + <!-- DEPRECATED: The defaultSearchField is consulted by various query parsers + when parsing a query string that isn't explicit about the field. Machine + (non-user) generated queries are best made explicit, or they can use the + "df" request parameter which takes precedence over this. + Note: Un-commenting defaultSearchField will be insufficient if your request + handler in solrconfig.xml defines "df", which takes precedence. That would + need to be removed. + <defaultSearchField>content</defaultSearchField> --> + + <!-- DEPRECATED: The defaultOperator (AND|OR) is consulted by various query + parsers when parsing a query string to determine if a clause of the query + should be marked as required or optional, assuming the clause isn't already + marked by some operator. The default is OR, which is generally assumed so it + is not a good idea to change it globally here. The "q.op" request parameter + takes precedence over this. + <solrQueryParser defaultOperator="OR"/> --> + +</schema> diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/schema_extra_fields.xml b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/schema_extra_fields.xml new file mode 100644 index 0000000000000000000000000000000000000000..02b365551cdf151614e552461001712aaae26e3d --- /dev/null +++ b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/schema_extra_fields.xml @@ -0,0 +1,23 @@ +<fields> +<!-- + Example: Adding German dynamic field types to our Solr Schema. + If you enable this, make sure you have a folder called lang containing + stopwords_de.txt and synonyms_de.txt. + This also requires to enable the content in schema_extra_types.xml. +--> +<!-- + <field name="label_de" type="text_de" indexed="true" stored="true" termVectors="true" omitNorms="true"/> + <field name="content_de" type="text_de" indexed="true" stored="true" termVectors="true"/> + <field name="teaser_de" type="text_de" indexed="false" stored="true"/> + <field name="path_alias_de" type="text_de" indexed="true" stored="true" termVectors="true" omitNorms="true"/> + <field name="taxonomy_names_de" type="text_de" indexed="true" stored="false" termVectors="true" multiValued="true" omitNorms="true"/> + <field name="spell_de" type="text_de" indexed="true" stored="true" multiValued="true"/> + <copyField source="label_de" dest="spell_de"/> + <copyField source="content_de" dest="spell_de"/> + <dynamicField name="tags_de_*" type="text_de" indexed="true" stored="false" omitNorms="true"/> + <dynamicField name="ts_de_*" type="text_de" indexed="true" stored="true" multiValued="false" termVectors="true"/> + <dynamicField name="tm_de_*" type="text_de" indexed="true" stored="true" multiValued="true" termVectors="true"/> + <dynamicField name="tos_de_*" type="text_de" indexed="true" stored="true" multiValued="false" termVectors="true" omitNorms="true"/> + <dynamicField name="tom_de_*" type="text_de" indexed="true" stored="true" multiValued="true" termVectors="true" omitNorms="true"/> +--> +</fields> diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/schema_extra_types.xml b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/schema_extra_types.xml new file mode 100644 index 0000000000000000000000000000000000000000..bd716b82acc3179b58a2bc6402950b203f913f8a --- /dev/null +++ b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/schema_extra_types.xml @@ -0,0 +1,34 @@ +<types> +<!-- + Example: Adding German language field types to our Solr Schema. + If you enable this, make sure you have a folder called lang containing + stopwords_de.txt and synonyms_de.txt. + + For examples from other languages, see + ./server/solr/configsets/sample_techproducts_configs/conf/schema.xml + from your Solr installation. +--> +<!-- + <fieldType name="text_de" class="solr.TextField" positionIncrementGap="100"> + <analyzer type="index"> + <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/> + <tokenizer class="solr.WhitespaceTokenizerFactory"/> + <filter class="solr.StopFilterFactory" words="lang/stopwords_de.txt" format="snowball" ignoreCase="true"/> + <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnCaseChange="1" splitOnNumerics="1" catenateWords="1" catenateNumbers="1" catenateAll="0" protected="protwords.txt" preserveOriginal="1"/> + <filter class="solr.LowerCaseFilterFactory"/> + <filter class="solr.GermanLightStemFilterFactory"/> + <filter class="solr.RemoveDuplicatesTokenFilterFactory"/> + </analyzer> + <analyzer type="query"> + <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/> + <tokenizer class="solr.WhitespaceTokenizerFactory"/> + <filter class="solr.SynonymFilterFactory" synonyms="lang/synonyms_de.txt" ignoreCase="true" expand="true"/> + <filter class="solr.StopFilterFactory" words="lang/stopwords_de.txt" format="snowball" ignoreCase="true"/> + <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnCaseChange="1" splitOnNumerics="1" catenateWords="0" catenateNumbers="0" catenateAll="0" protected="protwords.txt" preserveOriginal="1"/> + <filter class="solr.LowerCaseFilterFactory"/> + <filter class="solr.GermanLightStemFilterFactory"/> + <filter class="solr.RemoveDuplicatesTokenFilterFactory"/> + </analyzer> + </fieldType> +--> +</types> diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/solrconfig.xml b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/solrconfig.xml new file mode 100644 index 0000000000000000000000000000000000000000..136ccfe5042bfb2db575100f835cf605e8e8c75a --- /dev/null +++ b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/solrconfig.xml @@ -0,0 +1,1793 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- + For more details about configurations options that may appear in + this file, see http://wiki.apache.org/solr/SolrConfigXml. +--> +<config name="drupal-4.4-solr-6.x" > + <!-- In all configuration below, a prefix of "solr." for class names + is an alias that causes solr to search appropriate packages, + including org.apache.solr.(search|update|request|core|analysis) + + You may also specify a fully qualified Java classname if you + have your own custom plugins. + --> + + <!-- Set this to 'false' if you want solr to continue working after + it has encountered an severe configuration error. In a + production environment, you may want solr to keep working even + if one handler is mis-configured. + + You may also set this to false using by setting the system + property: + + -Dsolr.abortOnConfigurationError=false + --> + <abortOnConfigurationError>${solr.abortOnConfigurationError:true}</abortOnConfigurationError> + + <!-- Controls what version of Lucene various components of Solr + adhere to. Generally, you want to use the latest version to + get all bug fixes and improvements. It is highly recommended + that you fully re-index after changing this setting as it can + affect both how text is indexed and queried. + --> + <luceneMatchVersion>${solr.luceneMatchVersion:LUCENE_60}</luceneMatchVersion> + + <!-- <lib/> directives can be used to instruct Solr to load any Jars + identified and use them to resolve any "plugins" specified in + your solrconfig.xml or schema.xml (ie: Analyzers, Request + Handlers, etc...). + + All directories and paths are resolved relative to the + instanceDir. + + Please note that <lib/> directives are processed in the order + that they appear in your solrconfig.xml file, and are "stacked" + on top of each other when building a ClassLoader - so if you have + plugin jars with dependencies on other jars, the "lower level" + dependency jars should be loaded first. + + If a "./lib" directory exists in your instanceDir, all files + found in it are included as if you had used the following + syntax... + + <lib dir="./lib" /> + --> + + <!-- A "dir" option by itself adds any files found in the directory to the + classpath, this is useful for including all jars in a directory. + --> + <lib dir="${solr.contrib.dir:../../../contrib}/extraction/lib" /> + <lib dir="${solr.contrib.dir:../../../contrib}/clustering/lib/" /> + + <!-- The velocity library has been known to crash Solr in some + instances when deployed as a war file to Tomcat. Therefore all + references have been removed from the default configuration. + @see http://drupal.org/node/1612556 + --> + <!-- <lib dir="../../contrib/velocity/lib" /> --> + + <!-- When a regex is specified in addition to a directory, only the + files in that directory which completely match the regex + (anchored on both ends) will be included. + --> + <!--<lib dir="../../dist/" regex="apache-solr-cell-\d.*\.jar" />--> + <!--<lib dir="../../dist/" regex="apache-solr-clustering-\d.*\.jar" />--> + <!--<lib dir="../../dist/" regex="apache-solr-dataimporthandler-\d.*\.jar" />--> + <!--<lib dir="../../dist/" regex="apache-solr-langid-\d.*\.jar" />--> + <!-- <lib dir="../../dist/" regex="apache-solr-velocity-\d.*\.jar" /> --> + + <!-- If a dir option (with or without a regex) is used and nothing + is found that matches, it will be ignored + --> + <!--<lib dir="../../contrib/clustering/lib/" />--> + <!--<lib dir="/total/crap/dir/ignored" />--> + + <!-- an exact path can be used to specify a specific file. This + will cause a serious error to be logged if it can't be loaded. + --> + <!-- + <lib path="../a-jar-that-does-not-exist.jar" /> + --> + + <!-- Data Directory + + Used to specify an alternate directory to hold all index data + other than the default ./data under the Solr home. If + replication is in use, this should match the replication + configuration. + --> + <dataDir>${solr.data.dir:}</dataDir> + + <!-- The DirectoryFactory to use for indexes. + + solr.StandardDirectoryFactory is filesystem + based and tries to pick the best implementation for the current + JVM and platform. solr.NRTCachingDirectoryFactory, the default, + wraps solr.StandardDirectoryFactory and caches small files in memory + for better NRT performance. + + One can force a particular implementation via solr.MMapDirectoryFactory, + solr.NIOFSDirectoryFactory, or solr.SimpleFSDirectoryFactory. + + solr.RAMDirectoryFactory is memory based, not + persistent, and doesn't work with replication. + --> + <directoryFactory name="DirectoryFactory" + class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}"/> + + <!-- The CodecFactory for defining the format of the inverted index. + The default implementation is SchemaCodecFactory, which is the official + Lucene index format, but hooks into the schema to provide per-field + customization of the postings lists and per-document values in the + fieldType element (postingsFormat/docValuesFormat). Note that most of the + alternative implementations are experimental, so if you choose to + customize the index format, it's a good idea to convert back to the + official format e.g. via IndexWriter.addIndexes(IndexReader) before + upgrading to a newer version to avoid unnecessary reindexing. + --> + <codecFactory class="solr.SchemaCodecFactory"/> + + <!-- To enable dynamic schema REST APIs, use the following for <schemaFactory>: + + <schemaFactory class="ManagedIndexSchemaFactory"> + <bool name="mutable">true</bool> + <str name="managedSchemaResourceName">managed-schema</str> + </schemaFactory> + + When ManagedIndexSchemaFactory is specified, Solr will load the schema from + the resource named in 'managedSchemaResourceName', rather than from schema.xml. + Note that the managed schema resource CANNOT be named schema.xml. If the managed + schema does not exist, Solr will create it after reading schema.xml, then rename + 'schema.xml' to 'schema.xml.bak'. + + Do NOT hand edit the managed schema - external modifications will be ignored and + overwritten as a result of schema modification REST API calls. + + When ManagedIndexSchemaFactory is specified with mutable = true, schema + modification REST API calls will be allowed; otherwise, error responses will be + sent back for these requests. + --> + <schemaFactory class="ClassicIndexSchemaFactory"/> + + <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Index Config - These settings control low-level behavior of indexing + Most example settings here show the default value, but are commented + out, to more easily see where customizations have been made. + + Note: This replaces <indexDefaults> and <mainIndex> from older versions + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> + <indexConfig> + <!-- maxFieldLength was removed in 4.0. To get similar behavior, include a + LimitTokenCountFilterFactory in your fieldType definition. E.g. + <filter class="solr.LimitTokenCountFilterFactory" maxTokenCount="10000"/> + --> + <!-- Maximum time to wait for a write lock (ms) for an IndexWriter. Default: 1000 --> + <!-- <writeLockTimeout>1000</writeLockTimeout> --> + + <!-- The maximum number of simultaneous threads that may be + indexing documents at once in IndexWriter; if more than this + many threads arrive they will wait for others to finish. + Default in Solr/Lucene is 8. --> + <!-- <maxIndexingThreads>8</maxIndexingThreads> --> + + <!-- Expert: Enabling compound file will use less files for the index, + using fewer file descriptors on the expense of performance decrease. + Default in Lucene is "true". Default in Solr is "false" (since 3.6) --> + <!-- <useCompoundFile>false</useCompoundFile> --> + + <!-- ramBufferSizeMB sets the amount of RAM that may be used by Lucene + indexing for buffering added documents and deletions before they are + flushed to the Directory. + maxBufferedDocs sets a limit on the number of documents buffered + before flushing. + If both ramBufferSizeMB and maxBufferedDocs is set, then + Lucene will flush based on whichever limit is hit first. + The default is 100 MB. --> + <ramBufferSizeMB>32</ramBufferSizeMB> + <!-- <maxBufferedDocs>1000</maxBufferedDocs> --> + + <!-- Expert: Merge Policy + + The Merge Policy in Lucene controls how merging is handled by + Lucene. The default in Solr 3.3 is TieredMergePolicy. + + The default in 2.3 was the LogByteSizeMergePolicy, + previous versions used LogDocMergePolicy. + + LogByteSizeMergePolicy chooses segments to merge based on + their size. The Lucene 2.2 default, LogDocMergePolicy chose + when to merge based on number of documents + + Other implementations of MergePolicy must have a no-argument + constructor + --> + + <mergePolicyFactory class="org.apache.solr.index.LogByteSizeMergePolicyFactory"> + <!-- Merge Factor + The merge factor controls how many segments will get merged at a time. + For TieredMergePolicy, mergeFactor is a convenience parameter which + will set both MaxMergeAtOnce and SegmentsPerTier at once. + For LogByteSizeMergePolicy, mergeFactor decides how many new segments + will be allowed before they are merged into one. + --> + <int name="mergeFactor">4</int> + </mergePolicyFactory> + + <!-- Expert: Merge Scheduler + + The Merge Scheduler in Lucene controls how merges are + performed. The ConcurrentMergeScheduler (Lucene 2.3 default) + can perform merges in the background using separate threads. + The SerialMergeScheduler (Lucene 2.2 default) does not. + --> + <!-- + <mergeScheduler class="org.apache.lucene.index.ConcurrentMergeScheduler"/> + --> + + <!-- LockFactory + + This option specifies which Lucene LockFactory implementation + to use. + + single = SingleInstanceLockFactory - suggested for a + read-only index or when there is no possibility of + another process trying to modify the index. + native = NativeFSLockFactory - uses OS native file locking. + Do not use when multiple solr webapps in the same + JVM are attempting to share a single index. + simple = SimpleFSLockFactory - uses a plain file for locking + + Defaults: 'native' is default for Solr3.6 and later, otherwise + 'simple' is the default + + More details on the nuances of each LockFactory... + http://wiki.apache.org/lucene-java/AvailableLockFactories + --> + <lockType>${solr.lock.type:native}</lockType> + + <!-- Expert: Controls how often Lucene loads terms into memory + Default is 128 and is likely good for most everyone. + --> + <!-- <termIndexInterval>256</termIndexInterval> --> + + <!-- If true, IndexReaders will be reopened (often more efficient) + instead of closed and then opened. + --> + <reopenReaders>true</reopenReaders> + + <!-- Commit Deletion Policy + + Custom deletion policies can be specified here. The class must + implement org.apache.lucene.index.IndexDeletionPolicy. + + http://lucene.apache.org/java/2_9_1/api/all/org/apache/lucene/index/IndexDeletionPolicy.html + + The default Solr IndexDeletionPolicy implementation supports + deleting index commit points on number of commits, age of + commit point and optimized status. + + The latest commit point should always be preserved regardless + of the criteria. + --> + <deletionPolicy class="solr.SolrDeletionPolicy"> + <!-- The number of commit points to be kept --> + <str name="maxCommitsToKeep">1</str> + <!-- The number of optimized commit points to be kept --> + <str name="maxOptimizedCommitsToKeep">0</str> + <!-- + Delete all commit points once they have reached the given age. + Supports DateMathParser syntax e.g. + --> + <!-- + <str name="maxCommitAge">30MINUTES</str> + <str name="maxCommitAge">1DAY</str> + --> + </deletionPolicy> + + <!-- Lucene Infostream + + To aid in advanced debugging, Lucene provides an "InfoStream" + of detailed information when indexing. + + Setting the value to true will instruct the underlying Lucene + IndexWriter to write its info stream to solr's log. By default, + this is enabled here, and controlled through log4j.properties. + --> + <infoStream>true</infoStream> + + </indexConfig> + + <!-- JMX + + This example enables JMX if and only if an existing MBeanServer + is found, use this if you want to configure JMX through JVM + parameters. Remove this to disable exposing Solr configuration + and statistics to JMX. + + For more details see http://wiki.apache.org/solr/SolrJmx + --> + <!-- <jmx /> --> + <!-- If you want to connect to a particular server, specify the + agentId + --> + <!-- <jmx agentId="myAgent" /> --> + <!-- If you want to start a new MBeanServer, specify the serviceUrl --> + <!-- <jmx serviceUrl="service:jmx:rmi:///jndi/rmi://localhost:9999/solr"/> + --> + + <!-- The default high-performance update handler --> + <updateHandler class="solr.DirectUpdateHandler2"> + + <!-- AutoCommit + + Perform a <commit/> automatically under certain conditions. + Instead of enabling autoCommit, consider using "commitWithin" + when adding documents. + + http://wiki.apache.org/solr/UpdateXmlMessages + + maxDocs - Maximum number of documents to add since the last + commit before automatically triggering a new commit. + + maxTime - Maximum amount of time that is allowed to pass + since a document was added before automaticly + triggering a new commit. + --> + <autoCommit> + <maxDocs>${solr.autoCommit.MaxDocs:10000}</maxDocs> + <maxTime>${solr.autoCommit.MaxTime:120000}</maxTime> + </autoCommit> + + <!-- softAutoCommit is like autoCommit except it causes a + 'soft' commit which only ensures that changes are visible + but does not ensure that data is synced to disk. This is + faster and more near-realtime friendly than a hard commit. + --> + <autoSoftCommit> + <maxDocs>${solr.autoSoftCommit.MaxDocs:2000}</maxDocs> + <maxTime>${solr.autoSoftCommit.MaxTime:10000}</maxTime> + </autoSoftCommit> + + <!-- Update Related Event Listeners + + Various IndexWriter related events can trigger Listeners to + take actions. + + postCommit - fired after every commit or optimize command + postOptimize - fired after every optimize command + --> + <!-- The RunExecutableListener executes an external command from a + hook such as postCommit or postOptimize. + + exe - the name of the executable to run + dir - dir to use as the current working directory. (default=".") + wait - the calling thread waits until the executable returns. + (default="true") + args - the arguments to pass to the program. (default is none) + env - environment variables to set. (default is none) + --> + <!-- This example shows how RunExecutableListener could be used + with the script based replication... + http://wiki.apache.org/solr/CollectionDistribution + --> + <!-- + <listener event="postCommit" class="solr.RunExecutableListener"> + <str name="exe">solr/bin/snapshooter</str> + <str name="dir">.</str> + <bool name="wait">true</bool> + <arr name="args"> <str>arg1</str> <str>arg2</str> </arr> + <arr name="env"> <str>MYVAR=val1</str> </arr> + </listener> + --> + <!-- Enables a transaction log, currently used for real-time get. + "dir" - the target directory for transaction logs, defaults to the + solr data directory. --> + <updateLog> + <str name="dir">${solr.data.dir:}</str> + <!-- if you want to take control of the synchronization you may specify + the syncLevel as one of the following where ''flush'' is the default. + Fsync will reduce throughput. + <str name="syncLevel">flush|fsync|none</str> + --> + </updateLog> + </updateHandler> + + <!-- IndexReaderFactory + + Use the following format to specify a custom IndexReaderFactory, + which allows for alternate IndexReader implementations. + + ** Experimental Feature ** + + Please note - Using a custom IndexReaderFactory may prevent + certain other features from working. The API to + IndexReaderFactory may change without warning or may even be + removed from future releases if the problems cannot be + resolved. + + ** Features that may not work with custom IndexReaderFactory ** + + The ReplicationHandler assumes a disk-resident index. Using a + custom IndexReader implementation may cause incompatibility + with ReplicationHandler and may cause replication to not work + correctly. See SOLR-1366 for details. + + --> + <!-- + <indexReaderFactory name="IndexReaderFactory" class="package.class"> + <str name="someArg">Some Value</str> + </indexReaderFactory > + --> + + <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Query section - these settings control query time things like caches + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> + <query> + <!-- Max Boolean Clauses + + Maximum number of clauses in each BooleanQuery, an exception + is thrown if exceeded. + + ** WARNING ** + + This option actually modifies a global Lucene property that + will affect all SolrCores. If multiple solrconfig.xml files + disagree on this property, the value at any given moment will + be based on the last SolrCore to be initialized. + + --> + <maxBooleanClauses>1024</maxBooleanClauses> + + <!-- Slow Query Threshold (in millis) + + At high request rates, logging all requests can become a bottleneck + and therefore INFO logging is often turned off. However, it is still + useful to be able to set a latency threshold above which a request + is considered "slow" and log that request at WARN level so we can + easily identify slow queries. + --> + <slowQueryThresholdMillis>-1</slowQueryThresholdMillis> + + <!-- Solr Internal Query Caches + + There are two implementations of cache available for Solr, + LRUCache, based on a synchronized LinkedHashMap, and + FastLRUCache, based on a ConcurrentHashMap. + + FastLRUCache has faster gets and slower puts in single + threaded operation and thus is generally faster than LRUCache + when the hit ratio of the cache is high (> 75%), and may be + faster under other scenarios on multi-cpu systems. + --> + + <!-- Filter Cache + + Cache used by SolrIndexSearcher for filters (DocSets), + unordered sets of *all* documents that match a query. When a + new searcher is opened, its caches may be prepopulated or + "autowarmed" using data from caches in the old searcher. + autowarmCount is the number of items to prepopulate. For + LRUCache, the autowarmed items will be the most recently + accessed items. + + Parameters: + class - the SolrCache implementation LRUCache or + (LRUCache or FastLRUCache) + size - the maximum number of entries in the cache + initialSize - the initial capacity (number of entries) of + the cache. (see java.util.HashMap) + autowarmCount - the number of entries to prepopulate from + and old cache. + --> + <filterCache class="solr.FastLRUCache" + size="512" + initialSize="512" + autowarmCount="0"/> + + <!-- Query Result Cache + + Caches results of searches - ordered lists of document ids + (DocList) based on a query, a sort, and the range of documents requested. + --> + <queryResultCache class="solr.LRUCache" + size="512" + initialSize="512" + autowarmCount="32"/> + + <!-- Document Cache + + Caches Lucene Document objects (the stored fields for each + document). Since Lucene internal document ids are transient, + this cache will not be autowarmed. + --> + <documentCache class="solr.LRUCache" + size="512" + initialSize="512" + autowarmCount="0"/> + + <!-- Field Value Cache + + Cache used to hold field values that are quickly accessible + by document id. The fieldValueCache is created by default + even if not configured here. + --> + <!-- + <fieldValueCache class="solr.FastLRUCache" + size="512" + autowarmCount="128" + showItems="32" /> + --> + + <!-- Custom Cache + + Example of a generic cache. These caches may be accessed by + name through SolrIndexSearcher.getCache(),cacheLookup(), and + cacheInsert(). The purpose is to enable easy caching of + user/application level data. The regenerator argument should + be specified as an implementation of solr.CacheRegenerator + if autowarming is desired. + --> + <!-- + <cache name="myUserCache" + class="solr.LRUCache" + size="4096" + initialSize="1024" + autowarmCount="1024" + regenerator="com.mycompany.MyRegenerator" + /> + --> + + <!-- Lazy Field Loading + + If true, stored fields that are not requested will be loaded + lazily. This can result in a significant speed improvement + if the usual case is to not load all stored fields, + especially if the skipped fields are large compressed text + fields. + --> + <enableLazyFieldLoading>true</enableLazyFieldLoading> + + <!-- Use Filter For Sorted Query + + A possible optimization that attempts to use a filter to + satisfy a search. If the requested sort does not include + score, then the filterCache will be checked for a filter + matching the query. If found, the filter will be used as the + source of document ids, and then the sort will be applied to + that. + + For most situations, this will not be useful unless you + frequently get the same search repeatedly with different sort + options, and none of them ever use "score" + --> + <!-- + <useFilterForSortedQuery>true</useFilterForSortedQuery> + --> + + <!-- Result Window Size + + An optimization for use with the queryResultCache. When a search + is requested, a superset of the requested number of document ids + are collected. For example, if a search for a particular query + requests matching documents 10 through 19, and queryWindowSize is 50, + then documents 0 through 49 will be collected and cached. Any further + requests in that range can be satisfied via the cache. + --> + <queryResultWindowSize>20</queryResultWindowSize> + + <!-- Maximum number of documents to cache for any entry in the + queryResultCache. + --> + <queryResultMaxDocsCached>200</queryResultMaxDocsCached> + + <!-- Query Related Event Listeners + + Various IndexSearcher related events can trigger Listeners to + take actions. + + newSearcher - fired whenever a new searcher is being prepared + and there is a current searcher handling requests (aka + registered). It can be used to prime certain caches to + prevent long request times for certain requests. + + firstSearcher - fired whenever a new searcher is being + prepared but there is no current registered searcher to handle + requests or to gain autowarming data from. + + --> + <!-- QuerySenderListener takes an array of NamedList and executes a + local query request for each NamedList in sequence. + --> + <listener event="newSearcher" class="solr.QuerySenderListener"> + <arr name="queries"> + <!-- + <lst><str name="q">solr</str><str name="sort">price asc</str></lst> + <lst><str name="q">rocks</str><str name="sort">weight asc</str></lst> + --> + </arr> + </listener> + <listener event="firstSearcher" class="solr.QuerySenderListener"> + <arr name="queries"> + <lst> + <str name="q">solr rocks</str><str name="start">0</str><str name="rows">10</str> + </lst> + </arr> + </listener> + + <!-- Use Cold Searcher + + If a search request comes in and there is no current + registered searcher, then immediately register the still + warming searcher and use it. If "false" then all requests + will block until the first searcher is done warming. + --> + <useColdSearcher>false</useColdSearcher> + + <!-- Max Warming Searchers + + Maximum number of searchers that may be warming in the + background concurrently. An error is returned if this limit + is exceeded. + + Recommend values of 1-2 for read-only slaves, higher for + masters w/o cache warming. + --> + <maxWarmingSearchers>2</maxWarmingSearchers> + + </query> + + <!-- Request Dispatcher + + This section contains instructions for how the SolrDispatchFilter + should behave when processing requests for this SolrCore. + + handleSelect affects the behavior of requests such as /select?qt=XXX + + handleSelect="true" will cause the SolrDispatchFilter to process + the request and will result in consistent error handling and + formatting for all types of requests. + + handleSelect="false" will cause the SolrDispatchFilter to + ignore "/select" requests and fallback to using the legacy + SolrServlet and it's Solr 1.1 style error formatting + --> + <requestDispatcher handleSelect="true" > + <!-- Request Parsing + + These settings indicate how Solr Requests may be parsed, and + what restrictions may be placed on the ContentStreams from + those requests + + enableRemoteStreaming - enables use of the stream.file + and stream.url parameters for specifying remote streams. + + multipartUploadLimitInKB - specifies the max size (in KiB) of + Multipart File Uploads that Solr will allow in a Request. + + formdataUploadLimitInKB - specifies the max size (in KiB) of + form data (application/x-www-form-urlencoded) sent via + POST. You can use POST to pass request parameters not + fitting into the URL. + + addHttpRequestToContext - if set to true, it will instruct + the requestParsers to include the original HttpServletRequest + object in the context map of the SolrQueryRequest under the + key "httpRequest". It will not be used by any of the existing + Solr components, but may be useful when developing custom + plugins. + + *** WARNING *** + The settings below authorize Solr to fetch remote files, You + should make sure your system has some authentication before + using enableRemoteStreaming="true" + + --> + <requestParsers enableRemoteStreaming="true" + multipartUploadLimitInKB="2048000" + formdataUploadLimitInKB="2048" + addHttpRequestToContext="false"/> + + <!-- HTTP Caching + + Set HTTP caching related parameters (for proxy caches and clients). + + The options below instruct Solr not to output any HTTP Caching + related headers + --> + <httpCaching never304="true" /> + <!-- If you include a <cacheControl> directive, it will be used to + generate a Cache-Control header (as well as an Expires header + if the value contains "max-age=") + + By default, no Cache-Control header is generated. + + You can use the <cacheControl> option even if you have set + never304="true" + --> + <!-- + <httpCaching never304="true" > + <cacheControl>max-age=30, public</cacheControl> + </httpCaching> + --> + <!-- To enable Solr to respond with automatically generated HTTP + Caching headers, and to response to Cache Validation requests + correctly, set the value of never304="false" + + This will cause Solr to generate Last-Modified and ETag + headers based on the properties of the Index. + + The following options can also be specified to affect the + values of these headers... + + lastModFrom - the default value is "openTime" which means the + Last-Modified value (and validation against If-Modified-Since + requests) will all be relative to when the current Searcher + was opened. You can change it to lastModFrom="dirLastMod" if + you want the value to exactly correspond to when the physical + index was last modified. + + etagSeed="..." is an option you can change to force the ETag + header (and validation against If-None-Match requests) to be + different even if the index has not changed (ie: when making + significant changes to your config file) + + (lastModifiedFrom and etagSeed are both ignored if you use + the never304="true" option) + --> + <!-- + <httpCaching lastModifiedFrom="openTime" + etagSeed="Solr"> + <cacheControl>max-age=30, public</cacheControl> + </httpCaching> + --> + </requestDispatcher> + + <!-- Request Handlers + + http://wiki.apache.org/solr/SolrRequestHandler + + Incoming queries will be dispatched to a specific handler by name + based on the path specified in the request. + + Legacy behavior: If the request path uses "/select" but no Request + Handler has that name, and if handleSelect="true" has been specified in + the requestDispatcher, then the Request Handler is dispatched based on + the qt parameter. Handlers without a leading '/' are accessed this way + like so: http://host/app/[core/]select?qt=name If no qt is + given, then the requestHandler that declares default="true" will be + used or the one named "standard". + + If a Request Handler is declared with startup="lazy", then it will + not be initialized until the first request that uses it. + + --> + <!-- SearchHandler + + http://wiki.apache.org/solr/SearchHandler + + For processing Search Queries, the primary Request Handler + provided with Solr is "SearchHandler" It delegates to a sequent + of SearchComponents (see below) and supports distributed + queries across multiple shards + --> + <!--<requestHandler name="/select" class="solr.SearchHandler">--> + <!-- default values for query parameters can be specified, these + will be overridden by parameters in the request + --> + <!--<lst name="defaults"> + <str name="echoParams">explicit</str> + <int name="rows">10</int> + </lst>--> + <!-- In addition to defaults, "appends" params can be specified + to identify values which should be appended to the list of + multi-val params from the query (or the existing "defaults"). + --> + <!-- In this example, the param "fq=instock:true" would be appended to + any query time fq params the user may specify, as a mechanism for + partitioning the index, independent of any user selected filtering + that may also be desired (perhaps as a result of faceted searching). + + NOTE: there is *absolutely* nothing a client can do to prevent these + "appends" values from being used, so don't use this mechanism + unless you are sure you always want it. + --> + <!-- + <lst name="appends"> + <str name="fq">inStock:true</str> + </lst> + --> + <!-- "invariants" are a way of letting the Solr maintainer lock down + the options available to Solr clients. Any params values + specified here are used regardless of what values may be specified + in either the query, the "defaults", or the "appends" params. + + In this example, the facet.field and facet.query params would + be fixed, limiting the facets clients can use. Faceting is + not turned on by default - but if the client does specify + facet=true in the request, these are the only facets they + will be able to see counts for; regardless of what other + facet.field or facet.query params they may specify. + + NOTE: there is *absolutely* nothing a client can do to prevent these + "invariants" values from being used, so don't use this mechanism + unless you are sure you always want it. + --> + <!-- + <lst name="invariants"> + <str name="facet.field">cat</str> + <str name="facet.field">manu_exact</str> + <str name="facet.query">price:[* TO 500]</str> + <str name="facet.query">price:[500 TO *]</str> + </lst> + --> + <!-- If the default list of SearchComponents is not desired, that + list can either be overridden completely, or components can be + prepended or appended to the default list. (see below) + --> + <!-- + <arr name="components"> + <str>nameOfCustomComponent1</str> + <str>nameOfCustomComponent2</str> + </arr> + --> + <!--</requestHandler>--> + + <!-- A request handler that returns indented JSON by default --> + <requestHandler name="/query" class="solr.SearchHandler"> + <lst name="defaults"> + <str name="echoParams">explicit</str> + <str name="wt">json</str> + <str name="indent">true</str> + <str name="df">text</str> + </lst> + </requestHandler> + + <!-- + The export request handler is used to export full sorted result sets. + Do not change these defaults. + --> + + <requestHandler name="/export" class="solr.SearchHandler"> + <lst name="invariants"> + <str name="rq">{!xport}</str> + <str name="wt">xsort</str> + <str name="distrib">false</str> + </lst> + + <arr name="components"> + <str>query</str> + </arr> + </requestHandler> + + <!-- A Robust Example + + This example SearchHandler declaration shows off usage of the + SearchHandler with many defaults declared + + Note that multiple instances of the same Request Handler + (SearchHandler) can be registered multiple times with different + names (and different init parameters) + --> + <!-- + <requestHandler name="/browse" class="solr.SearchHandler"> + <lst name="defaults"> + <str name="echoParams">explicit</str>--> + + <!-- VelocityResponseWriter settings --> + <!--<str name="wt">velocity</str> + + <str name="v.template">browse</str> + <str name="v.layout">layout</str> + <str name="title">Solritas</str> + + <str name="defType">edismax</str> + <str name="qf"> + text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0 manu^1.1 cat^1.4 + title^10.0 description^5.0 keywords^5.0 author^2.0 resourcename^1.0 + </str> + <str name="mm">100%</str> + <str name="q.alt">*:*</str> + <str name="rows">10</str> + <str name="fl">*,score</str> + <str name="mlt.qf"> + text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0 manu^1.1 cat^1.4 + </str> + <str name="mlt.fl">text,features,name,sku,id,manu,cat</str> + <int name="mlt.count">3</int> + + <str name="qf"> + text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0 manu^1.1 cat^1.4 + </str> + + <str name="facet">on</str> + <str name="facet.field">cat</str> + <str name="facet.field">manu_exact</str> + <str name="facet.query">ipod</str> + <str name="facet.query">GB</str> + <str name="facet.mincount">1</str> + <str name="facet.pivot">cat,inStock</str> + <str name="facet.range.other">after</str> + <str name="facet.range">price</str> + <int name="f.price.facet.range.start">0</int> + <int name="f.price.facet.range.end">600</int> + <int name="f.price.facet.range.gap">50</int> + <str name="facet.range">popularity</str> + <int name="f.popularity.facet.range.start">0</int> + <int name="f.popularity.facet.range.end">10</int> + <int name="f.popularity.facet.range.gap">3</int> + <str name="facet.range">manufacturedate_dt</str> + <str name="f.manufacturedate_dt.facet.range.start">NOW/YEAR-10YEARS</str> + <str name="f.manufacturedate_dt.facet.range.end">NOW</str> + <str name="f.manufacturedate_dt.facet.range.gap">+1YEAR</str> + <str name="f.manufacturedate_dt.facet.range.other">before</str> + <str name="f.manufacturedate_dt.facet.range.other">after</str>--> + + <!-- Highlighting defaults --> + <!--<str name="hl">on</str> + <str name="hl.fl">text features name</str> + <str name="f.name.hl.fragsize">0</str> + <str name="f.name.hl.alternateField">name</str> + </lst> + <arr name="last-components"> + <str>spellcheck</str> + </arr>--> + <!-- + <str name="url-scheme">httpx</str> + --> + <!--</requestHandler>--> + <!-- trivia: the name pinkPony requestHandler was an agreement between the Search API and the + apachesolr maintainers. The decision was taken during the Drupalcon Munich codesprint. + --> + <requestHandler name="pinkPony" class="solr.SearchHandler" default="true"> + <lst name="defaults"> + <str name="defType">edismax</str> + <str name="df">content</str> + <str name="echoParams">explicit</str> + <bool name="omitHeader">true</bool> + <float name="tie">0.01</float> + <!-- Don't abort searches for the pinkPony request handler (set in solrcore.properties) --> + <int name="timeAllowed">${solr.pinkPony.timeAllowed:-1}</int> + <str name="q.alt">*:*</str> + + <!-- By default, don't spell check --> + <str name="spellcheck">false</str> + <!-- Defaults for the spell checker when used --> + <str name="spellcheck.onlyMorePopular">true</str> + <str name="spellcheck.extendedResults">false</str> + <!-- The number of suggestions to return --> + <str name="spellcheck.count">1</str> + </lst> + <arr name="last-components"> + <str>spellcheck</str> + <str>elevator</str> + </arr> + </requestHandler> + + <!-- The more like this handler offers many advantages over the standard handler, + when performing moreLikeThis requests.--> + <requestHandler name="mlt" class="solr.MoreLikeThisHandler"> + <lst name="defaults"> + <str name="df">content</str> + <str name="mlt.mintf">1</str> + <str name="mlt.mindf">1</str> + <str name="mlt.minwl">3</str> + <str name="mlt.maxwl">15</str> + <str name="mlt.maxqt">20</str> + <str name="mlt.match.include">false</str> + <!-- Abort any searches longer than 2 seconds (set in solrcore.properties) --> + <int name="timeAllowed">${solr.mlt.timeAllowed:2000}</int> + </lst> + </requestHandler> + + <!-- A minimal query type for doing luene queries --> + <requestHandler name="standard" class="solr.SearchHandler"> + <lst name="defaults"> + <str name="df">content</str> + <str name="echoParams">explicit</str> + <bool name="omitHeader">true</bool> + </lst> + </requestHandler> + + <!-- Update Request Handler. + + http://wiki.apache.org/solr/UpdateXmlMessages + + The canonical Request Handler for Modifying the Index through + commands specified using XML, JSON, CSV, or JAVABIN + + Note: Since solr1.1 requestHandlers requires a valid content + type header if posted in the body. For example, curl now + requires: -H 'Content-type:text/xml; charset=utf-8' + + To override the request content type and force a specific + Content-type, use the request parameter: + ?update.contentType=text/csv + + This handler will pick a response format to match the input + if the 'wt' parameter is not explicit + --> + <!--<requestHandler name="/update" class="solr.UpdateRequestHandler"> + </requestHandler>--> + <initParams path="/update/**,/query,/select,/tvrh,/elevate,/spell,/browse"> + <lst name="defaults"> + <str name="df">text</str> + </lst> + </initParams> + + <initParams path="/update/json/docs"> + <lst name="defaults"> + <!--this ensures that the entire json doc will be stored verbatim into one field--> + <str name="srcField">_src_</str> + <!--This means a the uniqueKeyField will be extracted from the fields and + all fields go into the 'df' field. In this config df is already configured to be 'text' + --> + <str name="mapUniqueKeyOnly">true</str> + </lst> + + </initParams> + + <!-- CSV Update Request Handler + http://wiki.apache.org/solr/UpdateCSV + --> + <requestHandler name="/update/csv" + class="solr.CSVRequestHandler" + startup="lazy" /> + + <!-- JSON Update Request Handler + http://wiki.apache.org/solr/UpdateJSON + --> + <requestHandler name="/update/json" + class="solr.JsonUpdateRequestHandler" + startup="lazy" /> + + <!-- Solr Cell Update Request Handler + + http://wiki.apache.org/solr/ExtractingRequestHandler + + --> + <requestHandler name="/update/extract" + startup="lazy" + class="solr.extraction.ExtractingRequestHandler" > + <lst name="defaults"> + <!-- All the main content goes into "text"... if you need to return + the extracted text or do highlighting, use a stored field. --> + <str name="fmap.content">text</str> + <str name="lowernames">true</str> + <str name="uprefix">ignored_</str> + + <!-- capture link hrefs but ignore div attributes --> + <str name="captureAttr">true</str> + <str name="fmap.a">links</str> + <str name="fmap.div">ignored_</str> + </lst> + </requestHandler> + + <!-- XSLT Update Request Handler + Transforms incoming XML with stylesheet identified by tr= + --> + <requestHandler name="/update/xslt" + startup="lazy" + class="solr.XsltUpdateRequestHandler"/> + + <!-- Field Analysis Request Handler + + RequestHandler that provides much the same functionality as + analysis.jsp. Provides the ability to specify multiple field + types and field names in the same request and outputs + index-time and query-time analysis for each of them. + + Request parameters are: + analysis.fieldname - field name whose analyzers are to be used + + analysis.fieldtype - field type whose analyzers are to be used + analysis.fieldvalue - text for index-time analysis + q (or analysis.q) - text for query time analysis + analysis.showmatch (true|false) - When set to true and when + query analysis is performed, the produced tokens of the + field value analysis will be marked as "matched" for every + token that is produces by the query analysis + --> + <requestHandler name="/analysis/field" + startup="lazy" + class="solr.FieldAnalysisRequestHandler" /> + + <!-- Document Analysis Handler + + http://wiki.apache.org/solr/AnalysisRequestHandler + + An analysis handler that provides a breakdown of the analysis + process of provided documents. This handler expects a (single) + content stream with the following format: + + <docs> + <doc> + <field name="id">1</field> + <field name="name">The Name</field> + <field name="text">The Text Value</field> + </doc> + <doc>...</doc> + <doc>...</doc> + ... + </docs> + + Note: Each document must contain a field which serves as the + unique key. This key is used in the returned response to associate + an analysis breakdown to the analyzed document. + + Like the FieldAnalysisRequestHandler, this handler also supports + query analysis by sending either an "analysis.query" or "q" + request parameter that holds the query text to be analyzed. It + also supports the "analysis.showmatch" parameter which when set to + true, all field tokens that match the query tokens will be marked + as a "match". + --> + <requestHandler name="/analysis/document" + class="solr.DocumentAnalysisRequestHandler" + startup="lazy" /> + + <!-- Admin Handlers + + As of Solr 5.0.0, the "/admin/" handlers are registered implicitly. + --> + <!-- <requestHandler name="/admin/" class="solr.admin.AdminHandlers" /> --> + <!-- This single handler is equivalent to the following... --> + <!-- + <requestHandler name="/admin/luke" class="solr.admin.LukeRequestHandler" /> + <requestHandler name="/admin/system" class="solr.admin.SystemInfoHandler" /> + <requestHandler name="/admin/plugins" class="solr.admin.PluginInfoHandler" /> + <requestHandler name="/admin/threads" class="solr.admin.ThreadDumpHandler" /> + <requestHandler name="/admin/properties" class="solr.admin.PropertiesRequestHandler" /> + <requestHandler name="/admin/file" class="solr.admin.ShowFileRequestHandler" > + --> + <!-- If you wish to hide files under ${solr.home}/conf, explicitly + register the ShowFileRequestHandler using the definition below. + NOTE: The glob pattern ('*') is the only pattern supported at present, *.xml will + not exclude all files ending in '.xml'. Use it to exclude _all_ updates + --> + <!-- + <requestHandler name="/admin/file" + class="solr.admin.ShowFileRequestHandler" > + <lst name="invariants"> + <str name="hidden">synonyms.txt</str> + <str name="hidden">anotherfile.txt</str> + <str name="hidden">*</str> + </lst> + </requestHandler> + --> + <!-- + Enabling this request handler (which is NOT a default part of the admin handler) will allow the Solr UI to edit + all the config files. This is intended for secure/development use ONLY! Leaving available and publically + accessible is a security vulnerability and should be done with extreme caution! + --> + <!-- + <requestHandler name="/admin/fileedit" class="solr.admin.EditFileRequestHandler" > + <lst name="invariants"> + <str name="qt">pinkPony</str> + <str name="q">solrpingquery</str> + <str name="omitHeader">false</str> + </lst> + <lst name="defaults"> + <str name="echoParams">all</str> + </lst> + <!- An optional feature of the PingRequestHandler is to configure the + handler with a "healthcheckFile" which can be used to enable/disable + the PingRequestHandler. + relative paths are resolved against the data dir + --> + <!-- <str name="healthcheckFile">server-enabled.txt</str> --> + <!-- </requestHandler> + --> + + <!-- Echo the request contents back to the client --> + <requestHandler name="/debug/dump" class="solr.DumpRequestHandler" > + <lst name="defaults"> + <str name="echoParams">explicit</str> + <str name="echoHandler">true</str> + </lst> + </requestHandler> + + <!-- Solr Replication + + The SolrReplicationHandler supports replicating indexes from a + "master" used for indexing and "slaves" used for queries. + + http://wiki.apache.org/solr/SolrReplication + + In the example below, remove the <lst name="master"> section if + this is just a slave and remove the <lst name="slave"> section + if this is just a master. + --> + <requestHandler name="/replication" class="solr.ReplicationHandler" > + <lst name="master"> + <str name="enable">${solr.replication.master:false}</str> + <str name="replicateAfter">commit</str> + <str name="replicateAfter">startup</str> + <str name="confFiles">${solr.replication.confFiles:schema.xml,mapping-ISOLatin1Accent.txt,protwords.txt,stopwords.txt,synonyms.txt,elevate.xml}</str> + </lst> + <lst name="slave"> + <str name="enable">${solr.replication.slave:false}</str> + <str name="masterUrl">${solr.replication.masterUrl:http://localhost:8983/solr}/replication</str> + <str name="pollInterval">${solr.replication.pollInterval:00:00:60}</str> + </lst> + </requestHandler> + + <!-- Realtime get handler, guaranteed to return the latest stored fields of + any document, without the need to commit or open a new searcher. The + current implementation relies on the updateLog feature being enabled. + --> + <requestHandler name="/get" class="solr.RealTimeGetHandler"> + <lst name="defaults"> + <str name="omitHeader">true</str> + <str name="wt">json</str> + <str name="indent">true</str> + </lst> + </requestHandler> + + <!-- Search Components + + Search components are registered to SolrCore and used by + instances of SearchHandler (which can access them by name) + + By default, the following components are available: + + <searchComponent name="query" class="solr.QueryComponent" /> + <searchComponent name="facet" class="solr.FacetComponent" /> + <searchComponent name="mlt" class="solr.MoreLikeThisComponent" /> + <searchComponent name="highlight" class="solr.HighlightComponent" /> + <searchComponent name="stats" class="solr.StatsComponent" /> + <searchComponent name="debug" class="solr.DebugComponent" /> + + Default configuration in a requestHandler would look like: + + <arr name="components"> + <str>query</str> + <str>facet</str> + <str>mlt</str> + <str>highlight</str> + <str>stats</str> + <str>debug</str> + </arr> + + If you register a searchComponent to one of the standard names, + that will be used instead of the default. + + To insert components before or after the 'standard' components, use: + + <arr name="first-components"> + <str>myFirstComponentName</str> + </arr> + + <arr name="last-components"> + <str>myLastComponentName</str> + </arr> + + NOTE: The component registered with the name "debug" will + always be executed after the "last-components" + + --> + + <!-- A request handler for demonstrating the spellcheck component. + + NOTE: This is purely as an example. The whole purpose of the + SpellCheckComponent is to hook it into the request handler that + handles your normal user queries so that a separate request is + not needed to get suggestions. + + IN OTHER WORDS, THERE IS REALLY GOOD CHANCE THE SETUP BELOW IS + NOT WHAT YOU WANT FOR YOUR PRODUCTION SYSTEM! + + See http://wiki.apache.org/solr/SpellCheckComponent for details + on the request parameters. + --> + <requestHandler name="/spell" class="solr.SearchHandler" startup="lazy"> + <lst name="defaults"> + <!-- Solr will use suggestions from both the 'default' spellchecker + and from the 'wordbreak' spellchecker and combine them. + collations (re-written queries) can include a combination of + corrections from both spellcheckers --> + <str name="spellcheck.dictionary">default</str> + <str name="spellcheck.dictionary">wordbreak</str> + <str name="spellcheck.onlyMorePopular">false</str> + <str name="spellcheck.extendedResults">false</str> + <str name="spellcheck.count">1</str> + <str name="spellcheck.alternativeTermCount">5</str> + <str name="spellcheck.maxResultsForSuggest">5</str> + <str name="spellcheck.collate">true</str> + <str name="spellcheck.collateExtendedResults">true</str> + <str name="spellcheck.maxCollationTries">10</str> + <str name="spellcheck.maxCollations">5</str> + </lst> + <arr name="last-components"> + <str>spellcheck</str> + </arr> + </requestHandler> + + <!-- This is disabled by default because it currently causes long startup times on + big indexes, even when never used. See SOLR-6679 for background. + + To use this suggester, set the "solr.suggester.enabled=true" system property + --> + <searchComponent name="suggest" class="solr.SuggestComponent" + enable="${solr.suggester.enabled:false}" > + <lst name="suggester"> + <str name="name">mySuggester</str> + <str name="lookupImpl">FuzzyLookupFactory</str> + <str name="dictionaryImpl">DocumentDictionaryFactory</str> + <str name="field">cat</str> + <str name="weightField">price</str> + <str name="suggestAnalyzerFieldType">string</str> + </lst> + </searchComponent> + + <requestHandler name="/suggest" class="solr.SearchHandler" + startup="lazy" enable="${solr.suggester.enabled:false}" > + <lst name="defaults"> + <str name="suggest">true</str> + <str name="suggest.count">10</str> + </lst> + <arr name="components"> + <str>suggest</str> + </arr> + </requestHandler> + + <!-- Term Vector Component + + http://wiki.apache.org/solr/TermVectorComponent + --> + <searchComponent name="tvComponent" class="solr.TermVectorComponent"/> + + <!-- A request handler for demonstrating the term vector component + + This is purely as an example. + + In reality you will likely want to add the component to your + already specified request handlers. + --> + <requestHandler name="/tvrh" class="solr.SearchHandler" startup="lazy"> + <lst name="defaults"> + <bool name="tv">true</bool> + </lst> + <arr name="last-components"> + <str>tvComponent</str> + </arr> + </requestHandler> + + <!-- Clustering Component + + http://wiki.apache.org/solr/ClusteringComponent + + This relies on third party jars which are notincluded in the + release. To use this component (and the "/clustering" handler) + Those jars will need to be downloaded, and you'll need to set + the solr.cluster.enabled system property when running solr... + + java -Dsolr.clustering.enabled=true -jar start.jar + --> + <!-- <searchComponent name="clustering" + enable="${solr.clustering.enabled:false}" + class="solr.clustering.ClusteringComponent" > --> + <!-- Declare an engine --> + <!--<lst name="engine">--> + <!-- The name, only one can be named "default" --> + <!--<str name="name">default</str>--> + + <!-- Class name of Carrot2 clustering algorithm. + + Currently available algorithms are: + + * org.carrot2.clustering.lingo.LingoClusteringAlgorithm + * org.carrot2.clustering.stc.STCClusteringAlgorithm + * org.carrot2.clustering.kmeans.BisectingKMeansClusteringAlgorithm + + See http://project.carrot2.org/algorithms.html for the + algorithm's characteristics. + --> + <!--<str name="carrot.algorithm">org.carrot2.clustering.lingo.LingoClusteringAlgorithm</str>--> + + <!-- Overriding values for Carrot2 default algorithm attributes. + + For a description of all available attributes, see: + http://download.carrot2.org/stable/manual/#chapter.components. + Use attribute key as name attribute of str elements + below. These can be further overridden for individual + requests by specifying attribute key as request parameter + name and attribute value as parameter value. + --> + <!--<str name="LingoClusteringAlgorithm.desiredClusterCountBase">20</str>--> + + <!-- Location of Carrot2 lexical resources. + + A directory from which to load Carrot2-specific stop words + and stop labels. Absolute or relative to Solr config directory. + If a specific resource (e.g. stopwords.en) is present in the + specified dir, it will completely override the corresponding + default one that ships with Carrot2. + + For an overview of Carrot2 lexical resources, see: + http://download.carrot2.org/head/manual/#chapter.lexical-resources + --> + <!--<str name="carrot.lexicalResourcesDir">clustering/carrot2</str>--> + + <!-- The language to assume for the documents. + + For a list of allowed values, see: + http://download.carrot2.org/stable/manual/#section.attribute.lingo.MultilingualClustering.defaultLanguage + --> + <!--<str name="MultilingualClustering.defaultLanguage">ENGLISH</str> + </lst> + <lst name="engine"> + <str name="name">stc</str> + <str name="carrot.algorithm">org.carrot2.clustering.stc.STCClusteringAlgorithm</str> + </lst> + </searchComponent>--> + + <!-- A request handler for demonstrating the clustering component + + This is purely as an example. + + In reality you will likely want to add the component to your + already specified request handlers. + --> + <!--<requestHandler name="/clustering" + startup="lazy" + enable="${solr.clustering.enabled:false}" + class="solr.SearchHandler"> + <lst name="defaults"> + <bool name="clustering">true</bool> + <str name="clustering.engine">default</str> + <bool name="clustering.results">true</bool>--> + <!-- The title field --> + <!--<str name="carrot.title">name</str>--> + <!--<str name="carrot.url">id</str>--> + <!-- The field to cluster on --> + <!--<str name="carrot.snippet">features</str>--> + <!-- produce summaries --> + <!--<bool name="carrot.produceSummary">true</bool>--> + <!-- the maximum number of labels per cluster --> + <!--<int name="carrot.numDescriptions">5</int>--> + <!-- produce sub clusters --> + <!--<bool name="carrot.outputSubClusters">false</bool>--> + + <!--<str name="defType">edismax</str> + <str name="qf"> + text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0 manu^1.1 cat^1.4 + </str> + <str name="q.alt">*:*</str> + <str name="rows">10</str> + <str name="fl">*,score</str> + </lst> + <arr name="last-components"> + <str>clustering</str> + </arr> + </requestHandler>--> + + <!-- Terms Component + + http://wiki.apache.org/solr/TermsComponent + + A component to return terms and document frequency of those + terms + --> + <searchComponent name="terms" class="solr.TermsComponent"/> + + <!-- A request handler for demonstrating the terms component --> + <requestHandler name="/terms" class="solr.SearchHandler" startup="lazy"> + <lst name="defaults"> + <bool name="terms">true</bool> + </lst> + <arr name="components"> + <str>terms</str> + </arr> + </requestHandler> + + <!-- Query Elevation Component + + http://wiki.apache.org/solr/QueryElevationComponent + + a search component that enables you to configure the top + results for a given query regardless of the normal lucene + scoring. + --> + <searchComponent name="elevator" class="solr.QueryElevationComponent" > + <!-- pick a fieldType to analyze queries --> + <str name="queryFieldType">string</str> + <str name="config-file">elevate.xml</str> + </searchComponent> + + <!-- A request handler for demonstrating the elevator component --> + <requestHandler name="/elevate" class="solr.SearchHandler" startup="lazy"> + <lst name="defaults"> + <str name="echoParams">explicit</str> + </lst> + <arr name="last-components"> + <str>elevator</str> + </arr> + </requestHandler> + + <!-- Highlighting Component + + http://wiki.apache.org/solr/HighlightingParameters + --> + <searchComponent class="solr.HighlightComponent" name="highlight"> + <highlighting> + <!-- Configure the standard fragmenter --> + <!-- This could most likely be commented out in the "default" case --> + <fragmenter name="gap" + default="true" + class="solr.highlight.GapFragmenter"> + <lst name="defaults"> + <int name="hl.fragsize">100</int> + </lst> + </fragmenter> + + <!-- A regular-expression-based fragmenter + (for sentence extraction) + --> + <fragmenter name="regex" + class="solr.highlight.RegexFragmenter"> + <lst name="defaults"> + <!-- slightly smaller fragsizes work better because of slop --> + <int name="hl.fragsize">70</int> + <!-- allow 50% slop on fragment sizes --> + <float name="hl.regex.slop">0.5</float> + <!-- a basic sentence pattern --> + <str name="hl.regex.pattern">[-\w ,/\n\"']{20,200}</str> + </lst> + </fragmenter> + + <!-- Configure the standard formatter --> + <formatter name="html" + default="true" + class="solr.highlight.HtmlFormatter"> + <lst name="defaults"> + <str name="hl.simple.pre"><![CDATA[<strong>]]></str> + <str name="hl.simple.post"><![CDATA[</strong>]]></str> + </lst> + </formatter> + + <!-- Configure the standard encoder --> + <encoder name="html" + class="solr.highlight.HtmlEncoder" /> + + <!-- Configure the standard fragListBuilder --> + <fragListBuilder name="simple" + default="true" + class="solr.highlight.SimpleFragListBuilder"/> + + <!-- Configure the single fragListBuilder --> + <fragListBuilder name="single" + class="solr.highlight.SingleFragListBuilder"/> + + <!-- default tag FragmentsBuilder --> + <fragmentsBuilder name="default" + default="true" + class="solr.highlight.ScoreOrderFragmentsBuilder"> + <!-- + <lst name="defaults"> + <str name="hl.multiValuedSeparatorChar">/</str> + </lst> + --> + </fragmentsBuilder> + + <!-- multi-colored tag FragmentsBuilder --> + <fragmentsBuilder name="colored" + class="solr.highlight.ScoreOrderFragmentsBuilder"> + <lst name="defaults"> + <str name="hl.tag.pre"><![CDATA[ + <b style="background:yellow">,<b style="background:lawgreen">, + <b style="background:aquamarine">,<b style="background:magenta">, + <b style="background:palegreen">,<b style="background:coral">, + <b style="background:wheat">,<b style="background:khaki">, + <b style="background:lime">,<b style="background:deepskyblue">]]></str> + <str name="hl.tag.post"><![CDATA[</b>]]></str> + </lst> + </fragmentsBuilder> + + <boundaryScanner name="default" + default="true" + class="solr.highlight.SimpleBoundaryScanner"> + <lst name="defaults"> + <str name="hl.bs.maxScan">10</str> + <str name="hl.bs.chars">.,!? 	 </str> + </lst> + </boundaryScanner> + + <boundaryScanner name="breakIterator" + class="solr.highlight.BreakIteratorBoundaryScanner"> + <lst name="defaults"> + <!-- type should be one of CHARACTER, WORD(default), LINE and SENTENCE --> + <str name="hl.bs.type">WORD</str> + <!-- language and country are used when constructing Locale object. --> + <!-- And the Locale object will be used when getting instance of BreakIterator --> + <str name="hl.bs.language">en</str> + <str name="hl.bs.country">US</str> + </lst> + </boundaryScanner> + </highlighting> + </searchComponent> + + <!-- Update Processors + + Chains of Update Processor Factories for dealing with Update + Requests can be declared, and then used by name in Update + Request Processors + + http://wiki.apache.org/solr/UpdateRequestProcessor + + --> + <!-- Deduplication + + An example dedup update processor that creates the "id" field + on the fly based on the hash code of some other fields. This + example has overwriteDupes set to false since we are using the + id field as the signatureField and Solr will maintain + uniqueness based on that anyway. + + --> + <!-- + <updateRequestProcessorChain name="dedupe"> + <processor class="solr.processor.SignatureUpdateProcessorFactory"> + <bool name="enabled">true</bool> + <str name="signatureField">id</str> + <bool name="overwriteDupes">false</bool> + <str name="fields">name,features,cat</str> + <str name="signatureClass">solr.processor.Lookup3Signature</str> + </processor> + <processor class="solr.LogUpdateProcessorFactory" /> + <processor class="solr.RunUpdateProcessorFactory" /> + </updateRequestProcessorChain> + --> + + <!-- Language identification + + This example update chain identifies the language of the incoming + documents using the langid contrib. The detected language is + written to field language_s. No field name mapping is done. + The fields used for detection are text, title, subject and description, + making this example suitable for detecting languages form full-text + rich documents injected via ExtractingRequestHandler. + See more about langId at http://wiki.apache.org/solr/LanguageDetection + --> + <!-- + <updateRequestProcessorChain name="langid"> + <processor class="org.apache.solr.update.processor.TikaLanguageIdentifierUpdateProcessorFactory"> + <str name="langid.fl">text,title,subject,description</str> + <str name="langid.langField">language_s</str> + <str name="langid.fallback">en</str> + </processor> + <processor class="solr.LogUpdateProcessorFactory" /> + <processor class="solr.RunUpdateProcessorFactory" /> + </updateRequestProcessorChain> + --> + + <!-- Response Writers + + http://wiki.apache.org/solr/QueryResponseWriter + + Request responses will be written using the writer specified by + the 'wt' request parameter matching the name of a registered + writer. + + The "default" writer is the default and will be used if 'wt' is + not specified in the request. + --> + <!-- The following response writers are implicitly configured unless + overridden... + --> + <!-- + <queryResponseWriter name="xml" + default="true" + class="solr.XMLResponseWriter" /> + <queryResponseWriter name="json" class="solr.JSONResponseWriter"/> + <queryResponseWriter name="python" class="solr.PythonResponseWriter"/> + <queryResponseWriter name="ruby" class="solr.RubyResponseWriter"/> + <queryResponseWriter name="php" class="solr.PHPResponseWriter"/> + <queryResponseWriter name="phps" class="solr.PHPSerializedResponseWriter"/> + <queryResponseWriter name="csv" class="solr.CSVResponseWriter"/> + --> + + <queryResponseWriter name="json" class="solr.JSONResponseWriter"> + <!-- For the purposes of the tutorial, JSON responses are written as + plain text so that they are easy to read in *any* browser. + If you expect a MIME type of "application/json" just remove this override. + --> + <str name="content-type">text/plain; charset=UTF-8</str> + </queryResponseWriter> + + <!-- + Custom response writers can be declared as needed... + --> + <!-- The solr.velocity.enabled flag is used by Solr's test cases so that this response writer is not + loaded (causing an error if contrib/velocity has not been built fully) --> + <!-- <queryResponseWriter name="velocity" class="solr.VelocityResponseWriter" enable="${solr.velocity.enabled:true}"/> --> + + <!-- XSLT response writer transforms the XML output by any xslt file found + in Solr's conf/xslt directory. Changes to xslt files are checked for + every xsltCacheLifetimeSeconds. + --> + <queryResponseWriter name="xslt" class="solr.XSLTResponseWriter"> + <int name="xsltCacheLifetimeSeconds">5</int> + </queryResponseWriter> + + <!-- Query Parsers + + http://wiki.apache.org/solr/SolrQuerySyntax + + Multiple QParserPlugins can be registered by name, and then + used in either the "defType" param for the QueryComponent (used + by SearchHandler) or in LocalParams + --> + <!-- example of registering a query parser --> + <!-- + <queryParser name="myparser" class="com.mycompany.MyQParserPlugin"/> + --> + + <!-- Function Parsers + + http://wiki.apache.org/solr/FunctionQuery + + Multiple ValueSourceParsers can be registered by name, and then + used as function names when using the "func" QParser. + --> + <!-- example of registering a custom function parser --> + <!-- + <valueSourceParser name="myfunc" + class="com.mycompany.MyValueSourceParser" /> + --> + + <!-- Legacy config for the admin interface --> + <admin> + <defaultQuery>*:*</defaultQuery> + + <!-- configure a healthcheck file for servers behind a + loadbalancer + --> + <!-- + <healthcheck type="file">server-enabled</healthcheck> + --> + </admin> + + <!-- Following is a dynamic way to include other components or any customized solrconfig.xml stuff, added by other contrib modules --> + <xi:include href="solrconfig_extra.xml" xmlns:xi="http://www.w3.org/2001/XInclude"> + <xi:fallback> + <!-- Spell Check + + The spell check component can return a list of alternative spelling + suggestions. This component must be defined in + solrconfig_extra.xml if present, since it's used in the search handler. + + http://wiki.apache.org/solr/SpellCheckComponent + --> + <searchComponent name="spellcheck" class="solr.SpellCheckComponent"> + + <str name="queryAnalyzerFieldType">textSpell</str> + + <!-- a spellchecker built from a field of the main index --> + <lst name="spellchecker"> + <str name="name">default</str> + <str name="field">spell</str> + <str name="spellcheckIndexDir">spellchecker</str> + <str name="buildOnOptimize">true</str> + </lst> + </searchComponent> + </xi:fallback> + </xi:include> + +</config> diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/solrconfig_extra.xml b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/solrconfig_extra.xml new file mode 100644 index 0000000000000000000000000000000000000000..c5bc3acfb52805c4f16d8ebf5239ea6443923030 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/solrconfig_extra.xml @@ -0,0 +1,80 @@ +<!-- Spell Check + + The spell check component can return a list of alternative spelling + suggestions. + + http://wiki.apache.org/solr/SpellCheckComponent + --> +<searchComponent name="spellcheck" class="solr.SpellCheckComponent"> + +<str name="queryAnalyzerFieldType">textSpell</str> + +<!-- Multiple "Spell Checkers" can be declared and used by this + component + --> + +<!-- a spellchecker built from a field of the main index, and + written to disk + --> +<lst name="spellchecker"> + <str name="name">default</str> + <str name="field">spell</str> + <str name="spellcheckIndexDir">spellchecker</str> + <str name="buildOnOptimize">true</str> + <!-- uncomment this to require terms to occur in 1% of the documents in order to be included in the dictionary + <float name="thresholdTokenFrequency">.01</float> + --> +</lst> + +<!-- + Adding German spellhecker index to our Solr index + This also requires to enable the content in schema_extra_types.xml and schema_extra_fields.xml +--> +<!-- +<lst name="spellchecker"> + <str name="name">spellchecker_de</str> + <str name="field">spell_de</str> + <str name="spellcheckIndexDir">./spellchecker_de</str> + <str name="buildOnOptimize">true</str> +</lst> +--> + +<!-- a spellchecker that uses a different distance measure --> +<!-- + <lst name="spellchecker"> + <str name="name">jarowinkler</str> + <str name="field">spell</str> + <str name="distanceMeasure"> + org.apache.lucene.search.spell.JaroWinklerDistance + </str> + <str name="spellcheckIndexDir">spellcheckerJaro</str> + </lst> + --> + +<!-- a spellchecker that use an alternate comparator + + comparatorClass be one of: + 1. score (default) + 2. freq (Frequency first, then score) + 3. A fully qualified class name + --> +<!-- + <lst name="spellchecker"> + <str name="name">freq</str> + <str name="field">lowerfilt</str> + <str name="spellcheckIndexDir">spellcheckerFreq</str> + <str name="comparatorClass">freq</str> + <str name="buildOnCommit">true</str> + --> + +<!-- A spellchecker that reads the list of words from a file --> +<!-- + <lst name="spellchecker"> + <str name="classname">solr.FileBasedSpellChecker</str> + <str name="name">file</str> + <str name="sourceLocation">spellings.txt</str> + <str name="characterEncoding">UTF-8</str> + <str name="spellcheckIndexDir">spellcheckerFile</str> + </lst> + --> +</searchComponent> diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/solrcore.properties b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/solrcore.properties new file mode 100644 index 0000000000000000000000000000000000000000..fb8d7d05c69c41a3d6df5285d9830964cfb75ce2 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/solrcore.properties @@ -0,0 +1,20 @@ +# Defines Solr properties for this specific core. +solr.replication.master=false +solr.replication.slave=false +solr.replication.pollInterval=00:00:60 +solr.replication.masterUrl=http://localhost:8983/solr +solr.replication.confFiles=schema.xml,mapping-ISOLatin1Accent.txt,protwords.txt,stopwords.txt,synonyms.txt,elevate.xml +solr.mlt.timeAllowed=2000 +# You should not set your luceneMatchVersion to anything lower than your Solr +# Version. +solr.luceneMatchVersion=6.0 +solr.pinkPony.timeAllowed=-1 +# autoCommit after 10000 docs +solr.autoCommit.MaxDocs=10000 +# autoCommit after 2 minutes +solr.autoCommit.MaxTime=120000 +# autoSoftCommit after 2000 docs +solr.autoSoftCommit.MaxDocs=2000 +# autoSoftCommit after 10 seconds +solr.autoSoftCommit.MaxTime=10000 +solr.contrib.dir=../../../contrib diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/stopwords.txt b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/stopwords.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7f243e48a9f8706cf8ba5aeb3218558e716fa0b --- /dev/null +++ b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/stopwords.txt @@ -0,0 +1,4 @@ +# Contains words which shouldn't be indexed for fulltext fields, e.g., because +# they're too common. For documentation of the format, see +# http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters#solr.StopFilterFactory +# (Lines starting with a pound character # are ignored.) diff --git a/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/synonyms.txt b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/synonyms.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d22eea6d6ee1548e239d42bfe44515370a2a091 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/search_api_solr/solr-conf/6.x/synonyms.txt @@ -0,0 +1,3 @@ +# Contains synonyms to use for your index. For the format used, see +# http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters#solr.SynonymFilterFactory +# (Lines starting with a pound character # are ignored.) diff --git a/profiles/wcm_base/modules/custom/news_client/README.md b/profiles/wcm_base/modules/custom/news_client/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6e9424e49ec72a4db698047f56c380b2ec48c7c1 --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/README.md @@ -0,0 +1,76 @@ +# News Client (news_client) + +A Drupal module which works to consume content from the news_service module. + +## Notes + +Originally authored by **Joe Bondra** (bondra.4@osu.edu). If any of this seems weird (and it just might) he'd probably be the one to ask... + +## Dependencies + +* OAuth2 Client ([oauth2_client](https://www.drupal.org/project/oauth2_client)) +* Entity API ([entity](https://www.drupal.org/project/entity)) +* Link ([link](https://www.drupal.org/project/link)) + +## Setup + +### News Client (news_client) + +#### OAuth2 Client configuration + +There is a configuration file which should contain a JSON encoded configuration profile for the OAuth2 client. It should look something like: + +```js +{ + "client_id" : "news_client", + "client_secret" : "<the client secret for the client id>", + "scope" : "news_access" +} +``` + +This file is consumed by the implementation of hook_oauth2_client_info in news_client.module. + +On Pantheon, this file should be placed in the /private directory in the site repository. + +Set up the location of this file at admin/config/services/news_client/oauth2. Enter the path of the file in the **OAuth2 Configuration File Path** field. There is an option there specifically for supporting a Pantheon binding under in the "Advanced" fieldset. + +#### Settings + +For the options found at admin/config/services/news_client + +* **OAuth2 Server URL** - This should be the URL of the site where the news_service module is installed. +* **Service Path** - This is set by default. It will only change if something on the service side changes. +* **Update Service Path** - This is set by default. +* **Sites Service Path** - This is set by default. +* **Site Tid(s)** - You should first save all of the other settings successfully and then the Site Reference for the news service will appear below the field. Enter a comma-delimited field of tids from the table. + +Be certain to save the settings before doing anything else...! + +The test configuration button will make a call to the /news_service/article path on the endpoint with the provided site tids and display the results. + +**NOTE** The site tid reference is cached. If you update something on the service end involving the sites taxonomy, make sure you clear the cache. + +## Cache + +**IMPORTANT** After setting up the module, you should do an import. See "Import" below. + +All articles are imported from the service in to a Content Type called "News Client Cached Article". It's best just to leave these alone and let the module manage them. + +One of the more important things in the News Client Cached Article type is the field News Service ID which contains the nid of the article on the news service. + +Articles currently in the cache can be found in a convenient list at admin/config/services/news_client/cache. You can sync these individually if necessary. Only use the Sync All Articles functionality if you have a good deal of orphaned articles. It will delete these and do a full import/update of all remaining articles. + +Ideally you shouldn't have to worry about the cache since articles *should be getting updated during cron using the /news_service/article_updates resource on the service endpoint*. Though, there are a lot of ways to deal with weird stuff happening using the sync and import tools. + +## Import + +At admin/config/services/news_client/import there are two tools. + +* Import/Update Articles - allows you to import/update articles by sites defined as tids in on admin/config/services/news_client/ +* Import/Update Single Article - Allows you to import/update a single article using its news service nid. + +**IMPORTANT** You should run an import of all articles from the sites you added in settings. Otherwise you'll just be getting any new articles via cron, but the old articles won't show up (unless they've been updated). + +## Purge + +The button at admin/config/services/news_client/purge is the nuclear option for dealing with the cache. It will obliterate everything. It will probably only help in extreme circumstances and its use should be avoided... diff --git a/profiles/wcm_base/modules/custom/news_client/includes/article_sync.admin.inc b/profiles/wcm_base/modules/custom/news_client/includes/article_sync.admin.inc new file mode 100644 index 0000000000000000000000000000000000000000..0811e584f7162eee21bd25ad0657eb8ac983c806 --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/includes/article_sync.admin.inc @@ -0,0 +1,78 @@ +<?php +/** + * Article sync function for news_client. + */ + +/** + * Menu callback for admin/config/services/news_client/sync/%. + */ +function news_client_article_sync_page($cached_article_nid) { + $cached_article = entity_load_single('node', $cached_article_nid); + $news_service_id = NULL; + $title = ''; + + try { + $ca_wrapper = entity_metadata_wrapper('node', $cached_article); + $title = $ca_wrapper->title->value(); + $news_service_id = $ca_wrapper->news_client_news_service_nid->value(); + } + catch (Exception $e) { + _news_client_entitymetadatawrapper_exception($e); + } + + $build = array(); + + if (!is_null($news_service_id)) { + $build['sync_text'] = array( + '#markup' => '<p>' . t('Would you like to sync %title?', array('%title' => $title)) . '</p>', + ); + $build['sync_form'] = drupal_get_form('news_client_sync_form', $news_service_id); + } + else { + drupal_set_message(t('Unable to load article with news service id.')); + } + + return $build; +} + +/** + * Form for sync callback. + */ +function news_client_sync_form($form, &$form_state, $news_service_id) { + $form = array(); + + $form['news_service_id'] = array ( + '#type' => 'hidden', + '#value' => $news_service_id, + ); + + $form['actions'] = array( + '#type' => 'actions', + ); + + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Sync Cached Article'), + ); + + return $form; +} + +/** + * Sync form submit callback. + */ +function news_client_sync_form_submit($form, &$form_state) { + $news_service_id = $form_state['values']['news_service_id']; + $site_identifiers = variable_get('news_client_site_identifiers'); + + $article = _news_client_fetch_article($news_service_id, $site_identifiers); + + if (!is_null($article) && !empty($article)) { + _news_client_cached_article_populate($article); + } + else { + drupal_set_message(t('Failed to retrieve article with id %id from service.', array('%id' => $news_service_id)), 'warning'); + } + + $form_state['redirect'] = 'admin/config/services/news_client/cache'; +} diff --git a/profiles/wcm_base/modules/custom/news_client/includes/cache.admin.inc b/profiles/wcm_base/modules/custom/news_client/includes/cache.admin.inc new file mode 100644 index 0000000000000000000000000000000000000000..f86cc2fc31896a06d57851f9f6dcbd14227ddc36 --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/includes/cache.admin.inc @@ -0,0 +1,131 @@ +<?php +/** + * Cache functions for news_client. + */ + +/** + * Page callback for admin/config/services/news_client/cache. + */ +function news_client_cache_page() { + $last_cron = variable_get('news_client_last_cron', 0); + $last_cron_text = ($last_cron > 0) ? format_date($last_cron) : 'Never'; + + $last_update = variable_get('news_client_last_update', 0); + $last_update_text = ($last_update > 0) ? format_date($last_update) : 'Never'; + + $view = views_get_view('news_client_cache_view'); + + // Need to change override path or filter form actions will redirect to home. + $view->override_path = current_path(); + + $build = array(); + + if (user_access('news client full sync')) { + $build['sync'] = drupal_get_form('news_client_sync_form'); + } + + $build['last_cron'] = array( + '#type' => 'markup', + '#markup' => '<p>Last update check: ' . $last_cron_text . '</p>', + ); + $build['last_update'] = array( + '#type' => 'markup', + '#markup' => '<p>Last import/update: ' . $last_update_text . '</p>', + ); + $build['news_client_cache_view'] = array( + '#type' => 'markup', + '#markup' => $view->render('default'), + ); + + return $build; +} + +/** + * Sync all articles form. + */ +function news_client_sync_form($form, &$form_state) { + $form = array(); + + $form['sync'] = array( + '#type' => 'fieldset', + '#title' => t('Sync All Articles'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); + + $form['sync']['description'] = array( + '#type' => 'markup', + '#markup' => '<p>' . + t('This will DELETE all articles from the cache not currently defined on the service for the sites defined in settings, and update all other articles.') . + '</p>', + ); + + $form['sync']['actions'] = array( + '#type' => 'actions', + ); + + $form['sync']['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Start Sync'), + ); + + return $form; +} + +/** + * Sync all articles submit callback. + */ +function news_client_sync_form_submit($form, &$form_state) { + $query = db_select('node', 'n'); + $query->fields('n', array('nid')); + $query->condition('n.type', 'news_client_cached_article'); + + $result = $query->execute(); + + $operations = array(); + + foreach ($result as $row) { + $operations[] = array('news_client_batch_sync_cached_article', array($row->nid)); + } + + $sync_batch = array( + 'title' => t('Syncing Articles'), + 'operations' => $operations, + 'finished' => 'news_client_batch_sync_finished', + 'init_message' => t('Sync is starting...'), + 'progress_message' => t('@current out of @total. @remaining remaining. (@percentage%)'), + 'error_message' => t('Sync has encountered an error'), + 'file' => drupal_get_path('module', 'news_client') . '/includes/sync.batch.inc', + ); + + batch_set($sync_batch); + + $site_identifiers = variable_get('news_client_site_identifiers'); + $article_page = _news_client_fetch_article_page(0, 5, $site_identifiers, '', 1); + + if (!is_null($article_page) && !empty($article_page)) { + $total_articles = $article_page['info']['total_articles']; + $total_pages = $article_page['info']['total_pages']; + + $operations = array(); + + for($i = 0; $i < $total_pages; $i++) { + $operations[] = array('news_client_batch_import_process_page', array($i, 5, $site_identifiers, '')); + } + + $import_batch = array( + 'title' => t('Importing Articles'), + 'operations' => $operations, + 'finished' => 'news_client_batch_import_finished', + 'init_message' => t('Import is starting...'), + 'progress_message' => t('@current out of @total. @remaining remaining. (@percentage%)'), + 'error_message' => t('Import has encountered an error'), + 'file' => drupal_get_path('module', 'news_client') . '/includes/import.batch.inc', + ); + + batch_set($import_batch); + } + else { + drupal_set_message(t('Import failed to get article info from service.'), 'error'); + } +} diff --git a/profiles/wcm_base/modules/custom/news_client/includes/import.admin.inc b/profiles/wcm_base/modules/custom/news_client/includes/import.admin.inc new file mode 100644 index 0000000000000000000000000000000000000000..4297b1b204d4c8b43ee70f77bf1c66da23adeadb --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/includes/import.admin.inc @@ -0,0 +1,162 @@ +<?php +/** + * Import functions for news_client. + */ + +/** + * Page callback for admin/config/services/news_client/import. + */ +function news_client_import_page() { + $build = array(); + + $build['import_by_site'] = drupal_get_form('news_client_import_by_site_form'); + $build['import_single'] = drupal_get_form('news_client_import_single_form'); + + return $build; +} + +/** + * Import by site form. + */ +function news_client_import_by_site_form($form, &$form_state) { + $sites_list = _news_client_fetch_sites_list(); + $site_identifiers = variable_get('news_client_site_identifiers'); + + $site_ids = explode(',', $site_identifiers); + $site_ids = array_map('trim', $site_ids); + $site_ids = array_map('intval', $site_ids); + + $form = array(); + + $form['by_site'] = array( + '#type' => 'fieldset', + '#title' => t('Import/Update Articles'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); + + $site_options = array(); + + foreach ($site_ids as $site_id) { + if (isset($sites_list[$site_id])) { + $site_options[$site_id] = $sites_list[$site_id]; + } + } + + $form['by_site']['sites'] = array( + '#type' => 'checkboxes', + '#title' => t('Import From'), + '#description' => t('Select the sites from which to import/update articles.'), + '#options' => $site_options, + ); + + $form['by_site']['actions'] = array( + '#type' => 'actions', + ); + + $form['by_site']['actions'] = array( + '#type' => 'submit', + '#value' => t('Import'), + ); + + return $form; +} + +/** + * Import by site form submit callback. + */ +function news_client_import_by_site_form_submit($form, &$form_state) { + $sites = $form_state['values']['sites']; + + $selected_sites = array(); + + foreach ($sites as $site) { + if ($site != 0) { + $selected_sites[] = $site; + } + } + + $sites_query_var = implode(',', $selected_sites); + + $article_page = _news_client_fetch_article_page(0, 5, $sites_query_var, '', 1); + + if (!is_null($article_page) && !empty($article_page)) { + $total_articles = $article_page['info']['total_articles']; + $total_pages = $article_page['info']['total_pages']; + + $operations = array(); + + for($i = 0; $i < $total_pages; $i++) { + $operations[] = array('news_client_batch_import_process_page', array($i, 5, $sites_query_var, '')); + } + + $batch = array( + 'title' => t('Importing Articles'), + 'operations' => $operations, + 'finished' => 'news_client_batch_import_finished', + 'init_message' => t('Import is starting...'), + 'progress_message' => t('@current out of @total. @remaining remaining. (@percentage%)'), + 'error_message' => t('Import has encountered an error'), + 'file' => drupal_get_path('module', 'news_client') . '/includes/import.batch.inc', + ); + + batch_set($batch); + } + else { + drupal_set_message(t('Failed to get article info from service.'), 'error'); + } +} + +/** + * Import single form. + */ +function news_client_import_single_form($form, &$form_state) { + $form = array(); + + $form['import_single'] = array( + '#type' => 'fieldset', + '#title' => t('Import/Update Single Article'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); + + $form['import_single']['news_service_nid'] = array( + '#type' => 'textfield', + '#title' => t('News Service NID'), + '#description' => t('Nid of the article on the news service.'), + '#size' => 20, + '#required' => TRUE, + ); + + $form['import_single']['actions'] = array( + '#type' => 'actions', + ); + + $form['import_single']['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Import Single Article'), + ); + + return $form; +} + +/** + * Import single form submit callback. + */ +function news_client_import_single_form_submit($form, &$form_state) { + $news_service_nid = $form_state['values']['news_service_nid']; + $site_identifiers = variable_get('news_client_site_identifiers'); + + $article = _news_client_fetch_article($news_service_nid, $site_identifiers); + + if (!is_null($article) && !empty($article)) { + $entity = _news_client_cached_article_populate($article); + drupal_set_message(t('Article %title was imported from news service.', array('%title' => $entity->title))); + } + else { + drupal_set_message(t('Fetching article from news service endpoint failed.'), 'error'); + if (empty($article)) { + drupal_set_message('Response from news service was empty. (Article may exist on service, just not for the defined sites on the client.)', 'warning'); + } + } +} diff --git a/profiles/wcm_base/modules/custom/news_client/includes/import.batch.inc b/profiles/wcm_base/modules/custom/news_client/includes/import.batch.inc new file mode 100644 index 0000000000000000000000000000000000000000..6de7f608509c4dc4b48b8d7c1c8126ed8fec6f6f --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/includes/import.batch.inc @@ -0,0 +1,69 @@ +<?php +/** + * Batch operations for news_client import processes. + */ + +/** + * Process a page of results from the news service. + */ +function news_client_batch_import_process_page($page_num, $per_page, $sites, $tags, &$context) { + if (!isset($context['sandbox']['progress'])) { + $context['sandbox']['progress'] = 0; + $context['sandbox']['page_num'] = 1; + $context['sandbox']['per_page'] = $per_page; + } + + // Update progress info. + $context['sandbox']['progress']++; + $context['message'] = t('Now processing page %page_num', array('%page_num' => $page_num)); + + // Process page. + $article_page = _news_client_fetch_article_page($page_num, $per_page, $sites, $tags, 0); + + if (!is_null($article_page) && !empty($article_page)) { + $article_nids = $article_page['articles']; + + foreach ($article_nids as $nid) { + $article = _news_client_fetch_article($nid); + + $cached_article = NULL; + + if (!is_null($article) && !empty($article)) { + $cached_article = _news_client_cached_article_populate($article); + } + + if (!is_null($cached_article)) { + $context['results'][] = t('Import/Update complete for %nid. (%title)', array('%nid' => $nid, '%title' => $cached_article->title)); + } + else { + $context['results'][] = t('Import/Update failed for %nid.', array('%nid' => $nid)); + } + } + } + else { + $context['results'][] = t('Import/Update for page %page_num failed.', array('%page_num', $page_num)); + } + +} + +/** + * Finish callback for news_client batch import. + */ +function news_client_batch_import_finished($success, $results, $operations) { + if ($success) { + // Here we do something meaningful with the results. + $message = t('@count items successfully processed:', array('@count' => count($results))); + $message .= theme('item_list', array('items' => $results)); + drupal_set_message($message); + + // Update last update time. + variable_set('news_client_last_update', REQUEST_TIME); + } + else { + // An error occurred. + // $operations contains the operations that remained unprocessed. + $error_operation = reset($operations); + $message = t('An error occurred while processing %error_operation with arguments: @arguments', array('%error_operation' => $error_operation[0], '@arguments' => print_r($error_operation[1], TRUE))); + drupal_set_message($message, 'error'); + } +} diff --git a/profiles/wcm_base/modules/custom/news_client/includes/news_client.admin.inc b/profiles/wcm_base/modules/custom/news_client/includes/news_client.admin.inc new file mode 100644 index 0000000000000000000000000000000000000000..41429cec834fb47c69fec9e40399962b9947aa30 --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/includes/news_client.admin.inc @@ -0,0 +1,115 @@ +<?php +/** + * Configuration functions for news_client. + */ + +/** + * Page callback for admin/config/news_client. + */ +function news_client_admin_page() { + $build = array(); + + $build['settings'] = drupal_get_form('news_client_admin_settings_form'); + $build['settings_test'] = drupal_get_form('news_client_admin_settings_test_form'); + + return $build; +} + +/** + * General admin settings form. + */ +function news_client_admin_settings_form() { + $sites_list = _news_client_fetch_sites_list(); + + $sites_reference = ''; + + if (!is_null($sites_list)) { + $header = array( + array('data' => t('Site Name')), + array('data' => t('Site Tid')), + ); + + $rows = array(); + + foreach ($sites_list as $id => $name) { + $rows[] = array($name, $id); + } + + $sites_reference_variables = array( + 'header' => $header, + 'rows' => $rows, + 'empty' => t('No site data.'), + 'caption' => t('Site Reference from news service.'), + ); + + $sites_reference = theme('table', $sites_reference_variables); + } + + $form = array(); + + $form['news_client_oauth2_server_url'] = array( + '#type' => 'textfield', + '#title' => t('OAuth2 Server URL'), + '#description' => t('URL of the news service\'s OAuth2 server. (Add an ending slash.)'), + '#default_value' => variable_get('news_client_oauth2_server_url', 'https://staff.it.osu.edu/'), + ); + + $form['news_client_service_path'] = array( + '#type' => 'textfield', + '#title' => t('Service Path'), + '#description' => t('Path of the news service endpoint. (Add an ending slash.)'), + '#default_value' => variable_get('news_client_service_path', 'news_service/article/'), + ); + + $form['news_client_service_update_path'] = array( + '#type' => 'textfield', + '#title' => t('Update Service Path'), + '#description' => t('Path of the news service update endpoint. (Add an ending slash.)'), + '#default_value' => variable_get('news_client_service_update_path', 'news_service/article_updates/'), + ); + + $form['news_client_sites_path'] = array( + '#type' => 'textfield', + '#title' => t('Sites Service Path'), + '#description' => t('Path of the news service sites endpoint. (Add an ending slash.)'), + '#default_value' => variable_get('news_client_sites_path', 'news_service/sites/'), + ); + + $form['news_client_site_identifiers'] = array( + '#type' => 'textfield', + '#title' => t('Site Tid(s)'), + '#description' => t('A comma delimited list of tids representing sites on the news service.') . '<br>' . $sites_reference, + '#default_value' => variable_get('news_client_site_identifiers'), + ); + + return system_settings_form($form); +} + +/** + * Settings test form. + */ +function news_client_admin_settings_test_form($form, &$form_state) { + $form = array(); + + $form['actions'] = array( + '#type' => 'actions', + ); + + $form['actions']['test_settings'] = array( + '#type' => 'submit', + '#value' => t('Test Configuration'), + ); + + return $form; +} + +/** + * Settings test form submit callback. + */ +function news_client_admin_settings_test_form_submit($form, &$form_state) { + $sites = variable_get('news_client_site_identifiers'); + $article_page = _news_client_fetch_article_page(0, 10, $sites, '', 1); + + drupal_set_message(t('Test complete:<br><br>Results:<br> <pre>@article_page</pre>', array('@article_page' => print_r($article_page, TRUE)))); + +} diff --git a/profiles/wcm_base/modules/custom/news_client/includes/oauth2.admin.inc b/profiles/wcm_base/modules/custom/news_client/includes/oauth2.admin.inc new file mode 100644 index 0000000000000000000000000000000000000000..529ec86833d84f760c7c583725040afefa1b4883 --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/includes/oauth2.admin.inc @@ -0,0 +1,67 @@ +<?php +/** + * OAuth2 configuration functions for news_client. + */ + +/** + * Page callback for admin/config/services/news_client/oauth2. + */ +function news_client_oauth2_page() { + $config_file_path = _news_client_get_config_file_path(); + + if (!file_exists($config_file_path)) { + drupal_set_message(t('News Client OAuth2 config file not found at :path', array(':path' => $config_file_path)), 'warning', FALSE); + } + + $build = array(); + + $build['form'] = drupal_get_form('news_client_oauth2_settings_form'); + + return $build; +} + +/** + * Admin settings form. + */ +function news_client_oauth2_settings_form() { + $config_file_path = variable_get('news_client_config_file_path', '/tmp/news_client_oauth2_config.txt'); + $pantheon_support_enabled = variable_get('news_client_pantheon_support_enabled', 0); + + $form = array(); + + $form['news_client_config_file_path'] = array( + '#type' => 'textfield', + '#title' => t('OAuth2 Configuration File Path'), + '#description' => t('The location of the configuration file.'), + '#default_value' => $config_file_path, + '#size' => 100, + '#required' => TRUE, + ); + + if ($pantheon_support_enabled && isset($_SERVER['PRESSFLOW_SETTINGS'])) { + // Add prefix to config file path field. + $pressflow_settings = json_decode($_SERVER['PRESSFLOW_SETTINGS'], TRUE); + $pantheon_binding = $pressflow_settings['conf']['pantheon_binding']; + + $form['news_client_config_file_path']['#field_prefix'] = '/srv/bindings/' . $pantheon_binding . '/'; + + $form['news_client_config_file_path']['#description'] .= ' <strong>Note:</strong> Pantheon support enabled. A location starting at the server root is assumed.'; + } + + $form['advanced'] = array( + '#type' => 'fieldset', + '#title' => t('Advanced'), + '#description' => t('Advanced configuration settings.'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); + + $form['advanced']['news_client_pantheon_support_enabled'] = array( + '#type' => 'checkbox', + '#title' => t('Enable Pantheon Support'), + '#description' => t('Enables support for adding configuration file into Pantheon\'s server root. (i.e. Figures out the current Pantheon environments binding identifier to create a path like /srv/bindings/<pantheon binding>/<etc.>.)'), + '#default_value' => $pantheon_support_enabled, + ); + + return system_settings_form($form); +} diff --git a/profiles/wcm_base/modules/custom/news_client/includes/purge.admin.inc b/profiles/wcm_base/modules/custom/news_client/includes/purge.admin.inc new file mode 100644 index 0000000000000000000000000000000000000000..f2715d56fd2e6a59c7eb5849d3bf3c1c97c19cd5 --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/includes/purge.admin.inc @@ -0,0 +1,85 @@ +<?php +/** + * Purge functions for news_client. + */ + +/** + * Page callback for admin/config/services/news_client/purge. + */ +function news_client_purge_page() { + $build = array(); + + $build['purge_form'] = drupal_get_form('news_client_purge_form'); + + return $build; +} + +/** + * Purge form. + */ +function news_client_purge_form($form, &$form_state) { + $form = array(); + + if (!isset($form_state['storage']['confirm'])) { + $form['description'] = array( + '#type' => 'markup', + '#markup' => '<h2>' . t('Purge ALL Cached Article/Taxonomies.') . '</h2><p>WARNING: This will DELETE all cached articles and taxonomies.</p>', + ); + + $form['actions'] = array( + '#type' => 'actions', + ); + + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Purge ALL Cached Articles/Taxonomies'), + ); + + return $form; + } + else { + return confirm_form($form, t('Purge All Articles/Taxonomies'), array('path' => 'admin/config/services/news_client/cache'), t('This will DELETE ALL cached articles and taxonomies. This cannot be undone.')); + } +} + +/** + * Purge form submit callback. + */ +function news_client_purge_form_submit($form, &$form_state) { + if (!isset($form_state['storage']['confirm'])) { + $form_state['storage']['confirm'] = TRUE; + $form_state['rebuild'] = TRUE; + } + else { + // Delete all nodes of type news_client_cached_article. + $cached_article_query = new EntityFieldQuery(); + $cached_article_query->entityCondition('entity_type', 'node'); + $cached_article_query->entityCondition('bundle', 'news_client_cached_article'); + + $result = $cached_article_query->execute(); + + if (isset($result['node'])) { + // Delete all cached article nodes. + $cached_article_nids = array_keys($result['node']); + node_delete_multiple($cached_article_nids); + } + + // Delete all terms in news_client_sites and news_client_tags. + $sites_vocabulary = taxonomy_vocabulary_machine_name_load('news_client_sites'); + foreach (taxonomy_get_tree($sites_vocabulary->vid) as $term) { + taxonomy_term_delete($term->tid); + } + + $tags_vocabulary = taxonomy_vocabulary_machine_name_load('news_client_tags'); + foreach (taxonomy_get_tree($tags_vocabulary->vid) as $term) { + taxonomy_term_delete($term->tid); + } + + // Reset last update time. + variable_set('news_client_last_update', 0); + + drupal_set_message(t('Cached News Articles and Taxonomies Purged.')); + + $form_state['redirect'] = 'admin/config/services/news_client/cache'; + } +} diff --git a/profiles/wcm_base/modules/custom/news_client/includes/sync.batch.inc b/profiles/wcm_base/modules/custom/news_client/includes/sync.batch.inc new file mode 100644 index 0000000000000000000000000000000000000000..990fb7fb889f47b60c749d293b40dfb55fc52cac --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/includes/sync.batch.inc @@ -0,0 +1,67 @@ +<?php +/** + * Batch operations for news_client sync process. + */ + +/** + * Sync a cached article. + */ +function news_client_batch_sync_cached_article($nid, &$context) { + if (!isset($context['sandbox']['progress'])) { + $context['sandbox']['progress'] = 0; + } + + // Update progress info. + $context['sandbox']['progress']++; + $context['message'] = t('Now processing nid %nid', array('%nid' => $nid)); + + $site_identifiers = variable_get('news_client_site_identifiers'); + + $cached_article = entity_load_single('node', $nid); + + try { + $ca_wrapper = entity_metadata_wrapper('node', $cached_article); + $news_service_id = $ca_wrapper->news_client_news_service_nid->value(); + } + catch (Exception $e) { + _news_client_entitymetadatawrapper_exception($e); + } + + $article = _news_client_fetch_article($news_service_id, $site_identifiers); + + if (is_null($article)) { + // Most likely a request failure. + $context['results'][] = t('Processing failed for %nid. (Potential request failure)', array('%nid' => $nid)); + } + else if (empty($article)) { + // Most likely article doesn't exist, or no longer exists for the sites. + entity_delete('node', $cached_article->nid); + + $context['results'][] = t('Deleted %nid. (%title)', array('%nid' => $nid, '%title' => $cached_article->title)); + } + else { + // More than likely still a valid article. + $synced_article = _news_client_cached_article_populate($article); + + $context['results'][] = t('Sync complete for %nid. (%title)', array('%nid' => $nid, '%title' => $synced_article->title)); + } +} + +/** + * Finish callback for news_client batch sync. + */ +function news_client_batch_sync_finished($success, $results, $operations) { + if ($success) { + // Here we do something meaningful with the results. + $message = t('@count items successfully processed:', array('@count' => count($results))); + $message .= theme('item_list', array('items' => $results)); + drupal_set_message($message); + } + else { + // An error occurred. + // $operations contains the operations that remained unprocessed. + $error_operation = reset($operations); + $message = t('An error occurred while processing %error_operation with arguments: @arguments', array('%error_operation' => $error_operation[0], '@arguments' => print_r($error_operation[1], TRUE))); + drupal_set_message($message, 'error'); + } +} diff --git a/profiles/wcm_base/modules/custom/news_client/news_client.info b/profiles/wcm_base/modules/custom/news_client/news_client.info new file mode 100644 index 0000000000000000000000000000000000000000..046ac767bbabf7c2298a7d994287304742b3c355 --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/news_client.info @@ -0,0 +1,14 @@ +name = News Client +description = Client interface module for the News Service (news_service) module. +core = 7.x +package = Services +version = 7.x-1.0 + +dependencies[] = oauth2_client +dependencies[] = entity +dependencies[] = link +dependencies[] = views +dependencies[] = better_exposed_filters + +files[] = views/handlers/news_client_views_handler_field_news_client_image_json.inc +files[] = views/handlers/news_client_views_handler_field_news_client_operations.inc diff --git a/profiles/wcm_base/modules/custom/news_client/news_client.install b/profiles/wcm_base/modules/custom/news_client/news_client.install new file mode 100644 index 0000000000000000000000000000000000000000..63ee4ff97c0a167fb045ee2d258aaf90696894b8 --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/news_client.install @@ -0,0 +1,420 @@ +<?php +/** + * Install file for news_client. + */ + +/** + * Implements hook_install(). + */ +function news_client_install() { + // Ensure news_client_cached_article type is available. + node_types_rebuild(); + $types = node_type_get_types(); + + // Create taxonomies for sites and tags. + $news_client_sites = (object) array( + 'name' => 'News Client Sites', + 'description' => 'Sites from the news service.', + 'machine_name' => 'news_client_sites', + ); + taxonomy_vocabulary_save($news_client_sites); + + $news_client_tags = (object) array( + 'name' => 'News Client Tags', + 'description' => 'Tags from the news service.', + 'machine_name' => 'news_client_tags', + ); + taxonomy_vocabulary_save($news_client_tags); + + // Create fields. + // -- Body field. + $field_body = array( + 'field_name' => 'news_client_body', + 'cardinality' => 1, + 'type' => 'text_with_summary', + ); + field_create_field($field_body); + + $field_body_instance = array( + 'field_name' => 'news_client_body', + 'label' => st('Body'), + 'bundle' => 'news_client_cached_article', + 'entity_type' => 'node', + 'settings' => array( + 'text_processing' => 1, + ), + 'widget' => array( + 'type' => 'text_textarea', + ), + ); + field_create_instance($field_body_instance); + + // -- Byline field. + $field_byline = array( + 'field_name' => 'news_client_byline', + 'cardinality' => 1, + 'type' => 'text', + ); + field_create_field($field_byline); + + $field_byline_instance = array( + 'field_name' => 'news_client_byline', + 'label' => st('Byline'), + 'bundle' => 'news_client_cached_article', + 'entity_type' => 'node', + 'widget' => array( + 'type' => 'text_textfield', + ), + ); + field_create_instance($field_byline_instance); + + // -- Sites field. + $field_sites = array( + 'field_name' => 'news_client_sites', + 'cardinality' => FIELD_CARDINALITY_UNLIMITED, + 'type' => 'taxonomy_term_reference', + 'settings' => array( + 'allowed_values' => array( + array( + 'vocabulary' => 'news_client_sites', + 'parent' => 0, + ), + ), + ), + ); + field_create_field($field_sites); + + $field_sites_instance = array( + 'field_name' => 'news_client_sites', + 'label' => st('Sites'), + 'bundle' => 'news_client_cached_article', + 'entity_type' => 'node', + 'widget' => array( + 'type' => 'taxonomy_autocomplete', + ), + ); + field_create_instance($field_sites_instance); + + // -- Tags field. + $field_tags = array( + 'field_name' => 'news_client_tags', + 'cardinality' => FIELD_CARDINALITY_UNLIMITED, + 'type' => 'taxonomy_term_reference', + 'settings' => array( + 'allowed_values' => array( + array( + 'vocabulary' => 'news_client_tags', + 'parent' => 0, + ), + ), + ), + ); + field_create_field($field_tags); + + $field_tags_instance = array( + 'field_name' => 'news_client_tags', + 'label' => st('Tags'), + 'bundle' => 'news_client_cached_article', + 'entity_type' => 'node', + 'widget' => array( + 'type' => 'taxonomy_autocomplete', + ), + ); + field_create_instance($field_tags_instance); + + // -- News service id field. + $field_news_service_nid = array( + 'field_name' => 'news_client_news_service_nid', + 'cardinality' => 1, + 'type' => 'number_integer', + ); + field_create_field($field_news_service_nid); + + $field_news_service_nid_instance = array( + 'field_name' => 'news_client_news_service_nid', + 'label' => st('News Service Identifier'), + 'bundle' => 'news_client_cached_article', + 'entity_type' => 'node', + 'widget' => array( + 'type' => 'text_textfield', + ), + ); + field_create_instance($field_news_service_nid_instance); + + // -- Imported/Updated timestamp. + $field_last_retrieve = array( + 'field_name' => 'news_client_last_retrieve', + 'cardinality' => 1, + 'type' => 'datestamp', + ); + field_create_field($field_last_retrieve); + + $field_last_retrieve_instance = array( + 'field_name' => 'news_client_last_retrieve', + 'label' => st('Most Recent Retrieval Date'), + 'bundle' => 'news_client_cached_article', + 'entity_type' => 'node', + 'widget' => array( + 'type' => 'text_textfield', + ), + ); + field_create_instance($field_last_retrieve_instance); + + // -- Featured Image data field (may just be better to store this as a JSON block. + $field_image_json = array( + 'field_name' => 'news_client_image_json', + 'cardinality' => 1, + 'type' => 'text_long', + ); + field_create_field($field_image_json); + + $field_image_json_instance = array( + 'field_name' => 'news_client_image_json', + 'label' => st('Featured Image'), + 'bundle' => 'news_client_cached_article', + 'entity_type' => 'node', + 'settings' => array( + 'text_processing' => 0, + ), + 'widget' => array( + 'type' => 'text_textarea', + ), + ); + field_create_instance($field_image_json_instance); + + // -- Links field. + $field_links = array( + 'field_name' => 'news_client_links', + 'cardinality' => FIELD_CARDINALITY_UNLIMITED, + 'type' => 'link_field', + ); + field_create_field($field_links); + + $field_links_instance = array( + 'field_name' => 'news_client_links', + 'label' => st('Learn More'), + 'bundle' => 'news_client_cached_article', + 'entity_type' => 'node', + 'widget' => array( + 'type' => 'link_field', + ), + ); + field_create_instance($field_links_instance); + + // -- Sidebar field. + $field_sidebar = array( + 'field_name' => 'news_client_sidebar', + 'cardinality' => 1, + 'type' => 'text_long', + ); + field_create_field($field_sidebar); + + $field_sidebar_instance = array( + 'field_name' => 'news_client_sidebar', + 'label' => st('Sidebar'), + 'bundle' => 'news_client_cached_article', + 'entity_type' => 'node', + 'settings' => array( + 'text_processing' => 1, + ), + 'widget' => array( + 'type' => 'text_textarea', + ), + ); + field_create_instance($field_sidebar_instance); + + // -- Kicker field. + $field_kicker = array( + 'field_name' => 'news_client_kicker', + 'cardinality' => 1, + 'type' => 'text', + ); + field_create_field($field_kicker); + + $field_kicker_instance = array( + 'field_name' => 'news_client_kicker', + 'label' => st('Kicker'), + 'bundle' => 'news_client_cached_article', + 'entity_type' => 'node', + 'widget' => array( + 'type' => 'text_textfield', + ), + ); + field_create_instance($field_kicker_instance); +} + +/** + * Implements hook_uninstall(). + */ +function news_client_uninstall() { + // Remove variables. + variable_del('news_client_oauth2_server_url'); + variable_del('news_client_service_path'); + variable_del('news_client_service_update_path'); + variable_del('news_client_client_url'); + variable_del('news_client_oauth2_client_url'); + variable_del('news_client_site_identifiers'); + variable_del('news_client_last_udpate'); + variable_del('news_client_last_cron'); + + // Remove vocabularies. + $sites_vocabulary = taxonomy_vocabulary_machine_name_load('news_client_sites'); + taxonomy_vocabulary_delete($sites_vocabulary->vid); + + $tags_vocabulary = taxonomy_vocabulary_machine_name_load('news_client_tags'); + taxonomy_vocabulary_delete($tags_vocabulary->vid); + + // Remove fields. + field_delete_field('news_client_body'); + field_delete_field('news_client_byline'); + field_delete_field('news_client_sites'); + field_delete_field('news_client_tags'); + field_delete_field('news_client_news_service_nid'); + field_delete_field('news_client_last_retrieve'); + field_delete_field('news_client_image_json'); + field_delete_field('news_client_links'); + field_delete_field('news_client_sidebar'); + field_delete_field('news_client_kicker'); + + // Remove cached article nodes and content type. + $cached_article_query = new EntityFieldQuery(); + $cached_article_query->entityCondition('entity_type', 'node'); + $cached_article_query->entityCondition('bundle', 'news_client_cached_article'); + + $result = $cached_article_query->execute(); + + if (isset($result['node'])) { + // Delete all cached article nodes. + $cached_article_nids = array_keys($result['node']); + node_delete_multiple($cached_article_nids); + } + + // Delete content type. + if (node_type_load('news_client_cached_article')) { + node_type_delete('news_client_cached_article'); + node_types_rebuild(); + menu_rebuild(); + } +} + +/** + * Adds kicker field. + */ +function news_client_update_7100(&$sandbox) { + // -- Kicker field. + $field_kicker = array( + 'field_name' => 'news_client_kicker', + 'cardinality' => 1, + 'type' => 'text', + ); + field_create_field($field_kicker); + + $field_kicker_instance = array( + 'field_name' => 'news_client_kicker', + 'label' => st('Kicker'), + 'bundle' => 'news_client_cached_article', + 'entity_type' => 'node', + 'widget' => array( + 'type' => 'text_textfield', + ), + ); + field_create_instance($field_kicker_instance); +} + +/** + * Changes type of News Client Identifier from text to number_integer. + * Changes type of Most Recent Retrieval Date from text to datetime. + */ +function news_client_update_7101(&$sandbox) { + if (!isset($sandbox['progress'])) { + $query = db_select('node', 'n'); + $query->fields('n'); + $query->condition('type', 'news_client_cached_article', '='); + + $total_cached_articles = $query->countQuery()->execute()->fetchField(); + + $sandbox['progress'] = 0; + $sandbox['max'] = $total_cached_articles; + $sandbox['messages'] = array(); + $sandbox['current_node'] = -1; + + // Create field/instance. + $field_news_service_nid = array( + 'field_name' => 'news_client_news_service_nid', + 'cardinality' => 1, + 'type' => 'number_integer', + ); + field_create_field($field_news_service_nid); + + $field_news_service_nid_instance = array( + 'field_name' => 'news_client_news_service_nid', + 'label' => st('News Service Identifier'), + 'bundle' => 'news_client_cached_article', + 'entity_type' => 'node', + 'widget' => array( + 'type' => 'text_textfield', + ), + ); + field_create_instance($field_news_service_nid_instance); + + $field_last_retrieve = array( + 'field_name' => 'news_client_last_retrieve', + 'cardinality' => 1, + 'type' => 'datestamp', + ); + field_create_field($field_last_retrieve); + + $field_last_retrieve_instance = array( + 'field_name' => 'news_client_last_retrieve', + 'label' => st('Most Recent Retrieval Date'), + 'bundle' => 'news_client_cached_article', + 'entity_type' => 'node', + 'widget' => array( + 'type' => 'text_textfield', + ), + ); + field_create_instance($field_last_retrieve_instance); + } + + $limit = 10; + + $result = db_select('node', 'n') + ->fields('n', array('nid')) + ->condition('type', 'news_client_cached_article', '=') + ->orderBy('n.nid', 'ASC') + ->where('n.nid > :nid', array(':nid' => $sandbox['current_node'])) + ->extend('PagerDefault') + ->limit($limit) + ->execute(); + + foreach ($result as $row) { + // Copy data. + $node = node_load($row->nid); + + try { + $wrapper = entity_metadata_wrapper('node', $node); + + $news_service_id = $wrapper->news_client_news_service_id->value(); + $wrapper->news_client_news_service_nid->set($news_service_id); + + $most_recent_retrieve = $wrapper->news_client_most_recent_retrieve->value(); + $wrapper->news_client_last_retrieve->set($most_recent_retrieve); + + $wrapper->save(); + } + catch (Exception $e) { + $sandbox['messages'][] = $e->getMessage(); + } + + $sandbox['progress']++; + $sandbox['current_node'] = $row->nid; + } + + $sandbox['#finished'] = ($sandbox['progress'] >= $sandbox['max']) ? TRUE : ($sandbox['progress'] / $sandbox['max']); + + if ($sandbox['#finished'] === TRUE) { + // Delete old field. + field_delete_field('news_client_news_service_id'); + field_delete_field('news_client_most_recent_retrieve'); + } +} diff --git a/profiles/wcm_base/modules/custom/news_client/news_client.make b/profiles/wcm_base/modules/custom/news_client/news_client.make new file mode 100644 index 0000000000000000000000000000000000000000..fd800e6e2bbeb7c7cfbfa33e9292375da54c7798 --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/news_client.make @@ -0,0 +1,9 @@ +; News Client Makefile + +api = 2 +core = 7.x + +; modules + +projects[oauth2_client][version] = 1.6 +projects[oauth2_client][subdir] = contrib \ No newline at end of file diff --git a/profiles/wcm_base/modules/custom/news_client/news_client.module b/profiles/wcm_base/modules/custom/news_client/news_client.module new file mode 100644 index 0000000000000000000000000000000000000000..62d316e8f1d8356fda1e6954fda1b95a287be6bd --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/news_client.module @@ -0,0 +1,761 @@ +<?php +/** + * @file + * Main module file for news_client. + */ + +/** + * Implements hook_help(). + */ +function news_client_help($path, $args) { + switch ($path) { + case 'admin/help#news_client': + return '<p>' . t('The News Client module consumes news articles from the News Service module.') . '</p>'; + break; + } +} + +/** + * Implements hook_views_api(). + */ +function news_client_views_api() { + return array( + 'api' => 3, + 'path' => drupal_get_path('module', 'news_client') . '/views', + ); +} + +/** + * Implements hook_views_data(). + */ +function news_client_views_data() { + $data = array(); + + $data['node'] = array( + 'news_client_image_json' => array( + 'title' => t('News Client Featured Image(s)'), + 'real field' => 'nid', + 'field' => array( + 'handler' => 'news_client_views_handler_field_news_client_image_json', + 'help' => t('Converts image JSON field to image display.'), + ), + ), + 'news_client_operations' => array( + 'title' => t('News Client Operations'), + 'real field' => 'nid', + 'field' => array( + 'handler' => 'news_client_views_handler_field_news_client_operations', + 'help' => t('Displays operations for News Client Cached Articles.'), + ), + ), + ); + + return $data; +} + +/** + * Implements hook_permission(). + */ +function news_client_permission() { + return array( + 'access news client configuration page' => array( + 'title' => t('Access configuration page'), + 'description' => t('Access the configuration and administration pages.'), + ), + 'access news client cache page' => array( + 'title' => t('Access cache page'), + 'description' => t('Access the cache page in the configuration settings.'), + ), + 'news client full sync' => array( + 'title' => t('Perform a full sync of all articles.'), + 'description' => t('Access the \'Sync all articles\' form on the cache page.'), + ), + 'news client purge' => array( + 'title' => t('Purge cached articles.'), + 'description' => t('Access the purge page in the configuration settings.'), + ), + ); +} + +/** + * Implements hook_menu(). + */ +function news_client_menu() { + $items = array(); + + $items['admin/config/services/news_client'] = array( + 'title' => t('News Client Configuration'), + 'description' => t('Configuration page for the news client.'), + 'file' => 'news_client.admin.inc', + 'file path' => drupal_get_path('module', 'news_client') . '/includes', + 'page callback' => 'news_client_admin_page', + 'access arguments' => array('access news client configuration page'), + 'type' => MENU_NORMAL_ITEM, + ); + + $items['admin/config/services/news_client/settings'] = array( + 'title' => t('Settings'), + 'description' => t('Manage general settings for news client.'), + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => 0, + ); + + $items['admin/config/services/news_client/cache'] = array( + 'title' => t('Cache'), + 'description' => t('Manage news client caches.'), + 'file' => 'cache.admin.inc', + 'file path' => drupal_get_path('module', 'news_client') . '/includes', + 'page callback' => 'news_client_cache_page', + 'access arguments' => array('access news client cache page'), + 'type' => MENU_LOCAL_TASK, + 'weight' => 1, + ); + + $items['admin/config/services/news_client/import'] = array( + 'title' => t('Import'), + 'description' => t('Import news articles from service.'), + 'file' => 'import.admin.inc', + 'file path' => drupal_get_path('module', 'news_client') . '/includes', + 'page callback' => 'news_client_import_page', + 'access arguments' => array('access news client configuration page'), + 'type' => MENU_LOCAL_TASK, + 'weight' => 2, + ); + + $items['admin/config/services/news_client/purge'] = array( + 'title' => t('Purge'), + 'description' => t('Purge cached articles and taxonomies.'), + 'file' => 'purge.admin.inc', + 'file path' => drupal_get_path('module', 'news_client') . '/includes', + 'page callback' => 'news_client_purge_page', + 'access arguments' => array('news client purge'), + 'type' => MENU_LOCAL_TASK, + 'weight' => 3, + ); + + $items['admin/config/services/news_client/oauth2'] = array( + 'title' => t('OAuth2 Client'), + 'description' => t('Load OAuth2 configuration from a configuration file'), + 'file' => 'oauth2.admin.inc', + 'file path' => drupal_get_path('module', 'news_client') . '/includes', + 'page callback' => 'news_client_oauth2_page', + 'access arguments' => array('access news client configuration page'), + 'type' => MENU_LOCAL_TASK, + 'weight' => 4, + ); + + $items['admin/config/services/news_client/sync/%'] = array( + 'title' => t('Sync Article'), + 'description' => t('Syncs an individual article'), + 'file' => 'article_sync.admin.inc', + 'file path' => drupal_get_path('module', 'news_client') . '/includes', + 'page callback' => 'news_client_article_sync_page', + 'page arguments' => array(5), + 'access arguments' => array('access news client cache page'), + 'type' => MENU_NORMAL_ITEM, + ); + + if (module_exists('workbench')) { + $items['admin/workbench/my/news_client_cache'] = array( + 'title' => t('News Client Cache'), + 'description' => t('Access the News Client cache page.'), + 'page callback' => 'drupal_goto', + 'page arguments' => array('/admin/config/services/news_client/cache'), + 'access arguments' => array('access news client cache page'), + 'type' => MENU_LOCAL_TASK, + 'weight' => 10, + ); + } + + return $items; +} + +/** + * Implements hook_oauth2_clients(). + */ +function news_client_oauth2_clients() { + $oauth2_clients = array(); + $config_file_path = _news_client_get_config_file_path(); + + if (!file_exists($config_file_path)) { + watchdog( + 'news_client', + t('News Client OAuth2 config file not found at :path', array(':path' => $config_file_path)), + NULL, + WATCHDOG_WARNING + ); + } + else { + $config = json_decode(file_get_contents($config_file_path)); + + $server_url = variable_get('news_client_oauth2_server_url', 'https://it.osu.edu/'); + + $oauth2_clients['news_client'] = array( + 'token_endpoint' => $server_url . 'oauth2/token', + 'auth_flow' => 'client-credentials', + 'client_id' => $config->client_id, + 'client_secret' => $config->client_secret, + 'scope' => $config->scope, + ); + } + + return $oauth2_clients; +} + +/** + * Implements hook_node_info(). + */ +function news_client_node_info() { + $info = array(); + + $info['news_client_cached_article'] = array( + 'name' => t('News Client Cached Article'), + 'base' => 'news_client', + 'description' => t('Holds a synced article from the news service.'), + 'help' => t('This content type is managed by the News Client module. DO NOT create or edit nodes of this type by hand.'), + 'has_title' => TRUE, + 'title_label' => t('Title'), + 'locked' => TRUE, + 'comment' => array( + 'status' => FALSE, + ), + ); + + return $info; +} + +/** + * Implements hook_form(). + */ +function news_client_form($node, &$form_state) { + return node_content_form($node, $form_state); +} + +/** + * Implements hook_theme(). + */ +function news_client_theme($existing, $type, $theme, $path) { + $theme = array(); + + $theme['field__news_client_image_json'] = array( + 'template' => 'templates/field--news-client-image-json', + ); + + return $theme; +} + +/** + * Implements hook_preprocess_HOOK(). + */ +function news_client_preprocess_field(&$variables, $hook) { + if ($variables['element']['#field_name'] == 'news_client_image_json') { + $image_markup = ''; + + $image_data = json_decode($variables['element']['#items'][0]['value']); + + if (!empty($image_data)) { + foreach ($image_data as $image) { + $data = array( + 'path' => $image->url, + 'alt' => $image->alt, + 'title' => $image->title, + 'attributes' => array( + 'class' => array('news_client_image_json'), + ), + ); + $image_markup .= theme_image($data); + } + + $variables['image_markup'] = $image_markup; + } + } + +} + +/** + * Implements hook_cron(). + */ +function news_client_cron() { + variable_set('news_client_last_cron', REQUEST_TIME); + + $updates = _news_client_fetch_article_updates(); + + if (!is_null($updates) && !empty($updates)) { + $queue = DrupalQueue::get('newsClientCacheProcessUpdate'); + + foreach ($updates as $update) { + $item = array( + 'nid' => $update['nid'], + 'operation' => $update['operation'], + ); + $queue->createItem($item); + } + + variable_set('news_client_last_update', REQUEST_TIME); + } +} + +/** + * Implements hook_cron_queue_info(). + */ +function news_client_cron_queue_info() { + $queues = array(); + + $queues['newsClientCacheProcessUpdate'] = array( + 'worker callback' => 'news_client_cache_process_update_item', + 'time' => 60, + ); + + return $queues; +} + +/** + * Worker callback for newsClientCacheUpdate. + */ +function news_client_cache_process_update_item($item) { + $nid = $item['nid']; + $operation = $item['operation']; + + switch ($operation) { + case 'fetch': + $article = _news_client_fetch_article($nid); + + if (!is_null($article) && !empty($article)) { + _news_client_cached_article_populate($article); + } + break; + + case 'remove': + $query = new EntityFieldQuery(); + $query->entityCondition('entity_type', 'node'); + $query->entityCondition('bundle', 'news_client_cached_article'); + $query->fieldCondition('news_client_news_service_nid', 'value', $nid, '='); + + $result = $query->execute(); + + if (isset($result['node'])) { + $cached_article_nids = array_keys($result['node']); + entity_delete_multiple('node', $cached_article_nids); + } + break; + } + +} + +/** + * Fetches a response from the news service. + * + * @param String $service_path Location of resource on service endpoint. + * @param Array $parameters Array with 'path' and 'query' keys for service endpoint. + * + * @return Mixed NULL or String of JSON data. + */ +function _news_client_service_request($service_path, $parameters = array()) { + $response = NULL; + + try { + $oauth2_client = oauth2_client_load('news_client'); + $access_token = $oauth2_client->getAccessToken(); + + $server_url = variable_get('news_client_oauth2_server_url'); + + $options = array( + 'headers' => array( + 'Authorization' => 'Bearer ' . $access_token, + ) + ); + + $path = isset($parameters['path']) ? implode('/', $parameters['path']) : ''; + $query_str = isset($parameters['query']) ? '?' . drupal_http_build_query($parameters['query']) : ''; + $url = $server_url . $service_path . $path . $query_str; + + $drupal_response = drupal_http_request($url, $options); + + if (!isset($drupal_response->error)) { + $response = isset($drupal_response->data) ? $drupal_response->data : ''; + } + else { + $response_data = array( + 'code' => $drupal_response->code, + 'error' => $drupal_response->error, + ); + watchdog('news_client', t('_news_client_service_request failed. <br><pre>%response_data</pre>'), array('%response_data' => print_r($response_data, TRUE)), WATCHDOG_ERROR); + } + } + catch (Exception $e) { + drupal_set_message($e->getMessage(), 'error'); + watchdog('news_client', t('_news_client_service_request Exception: <pre>%exception</pre>'), array('%exception' => print_r($e, TRUE)), WATCHDOG_ERROR); + } + + return $response; +} + +/** + * Fetches a news article from the service. + * + * @param $id Primary key of an article on the news service. + * + * @return Mixed NULL or Array of article data. + */ +function _news_client_fetch_article($nid, $sites = '') { + $service_path = variable_get('news_client_service_path'); + + $parameters = array( + 'path' => array($nid), + 'query' => array( + 'sites' => $sites, + ), + ); + + $article_json = _news_client_service_request($service_path, $parameters); + + $article = json_decode($article_json, TRUE); + + return $article; +} + +/** + * Fetches a news article list from the service. + * + * @param Integer $page The page of an article list on the news service. + * @param Integer $num The number of articles to fetch at one time from the news service. + * @param String $sites The site corresponding to a taxonomy term on the news service. (comma separated) + * @param String $tags The tags corresponding to a taxonomy term on the news service. (comma separated) + * @param Integer $info_only Whether or not just to return the page and item totals. + * + * @return Mixed NULL or Array of article list data. + */ +function _news_client_fetch_article_page($page, $num, $sites, $tags, $info_only = 0) { + $service_path = variable_get('news_client_service_path'); + + $query = array(); + if (!empty($page)) { + $query['page'] = $page; + } + if (!empty($num)) { + $query['num'] = $num; + } + if (!empty($sites)) { + $query['sites'] = $sites; + } + if (!empty($tags)) { + $query['tags'] = $tags; + } + if ($info_only) { + $query['info_only'] = $info_only; + } + + $parameters = array( + 'query' => $query, + ); + + $article_page_json = _news_client_service_request($service_path, $parameters); + + $article_page = json_decode($article_page_json, TRUE); + + return $article_page; +} + +/** + * Fetches update information from news_service. + * + * @return Mixed NULL or Array of update data. + */ +function _news_client_fetch_article_updates() { + $service_path = variable_get('news_client_service_update_path'); + $sites = variable_get('news_client_site_identifiers', ''); + $timestamp = variable_get('news_client_last_update', 0); + + $parameters = array( + 'query' => array( + 'sites' => $sites, + 'timestamp' => $timestamp, + ), + ); + + $update_json = _news_client_service_request($service_path, $parameters); + + $updates = json_decode($update_json, TRUE); + + return $updates; +} + +/** + * Fetches sites list from news service. + * + * @return Mixed NULL or Array of tid => name of sites. + */ +function _news_client_fetch_sites_list() { + $sites_list_cache = cache_get('news_client_sites_list'); + $sites_list = NULL; + + if ($sites_list_cache != FALSE) { + $sites_list = $sites_list_cache->data; + } + else { + $sites_path = variable_get('news_client_sites_path'); + + $sites_list_json = _news_client_service_request($sites_path); + + $sites_list = json_decode($sites_list_json, TRUE); + + if (!empty($sites_list)) { + cache_set('news_client_sites_list', $sites_list); + } + } + + return $sites_list; +} + +/** + * Looks up a news_client_cached_article_by_id. + * + * @param $id ID of article on the news service. + * + * @return NULL or StdClass Entity object. + */ +function _news_client_cached_article_lookup_by_news_service_id($id) { + $query = new EntityFieldQuery(); + $query->entityCondition('entity_type', 'node'); + $query->entityCondition('bundle', 'news_client_cached_article'); + $query->fieldCondition('news_client_news_service_nid', 'value', $id); + + $result = $query->execute(); + + $cached_article = NULL; + + if (isset($result['node'])) { + // Since we're dealing with nids, assume that only one result comes back if any. + $cached_article_nids = array_keys($result['node']); + $cached_article_nid = array_shift($cached_article_nids); + $cached_article = entity_load_single('node', $cached_article_nid); + } + + return $cached_article; +} + +/** + * Populates a news_client_cached article node with array of article data. + * + * @param Array $article_data + * + * @return Mixed NULL or StdClass Entity + */ +function _news_client_cached_article_populate($article_data) { + $cached_article = _news_client_cached_article_lookup_by_news_service_id($article_data['nid']); + + $entity = NULL; + + if (is_null($cached_article)) { + // Create a new node. + $values = array( + 'type' => 'news_client_cached_article', + 'uid' => 1, + 'status' => NODE_PUBLISHED, + 'comment' => 0, + 'promote' => 0, + ); + + $entity = entity_create('node', $values); + } + else { + $entity = $cached_article; + } + + // Make sure that any empty fields are set to NULL to keep them from being displayed. + // "Deleting Values" https://www.drupal.org/docs/7/api/entity-api/entity-metadata-wrappers + foreach ($article_data as $key => $value) { + if (empty($value)) { + $article_data[$key] = NULL; + } + } + + try { + $wrapper = entity_metadata_wrapper('node', $entity); + $wrapper->title->set($article_data['title']); + + if (!is_null($article_data['body'])) { + $body = array( + 'value' => $article_data['body'], + 'format' => 'raw', + 'summary' => $article_data['summary'], + ); + + $wrapper->news_client_body->set($body); + } + else { + $wrapper->news_client_body->set(NULL); + } + + $wrapper->news_client_byline->set($article_data['byline']); + $wrapper->news_client_kicker->set($article_data['kicker']); + $wrapper->news_client_news_service_nid->set($article_data['nid']); + $wrapper->news_client_links->set($article_data['links']); + + if (!is_null($article_data['sidebar'])) { + $wrapper->news_client_sidebar->set(array('value' => $article_data['sidebar'], 'format' => 'raw')); + } + else { + $wrapper->news_client_sidebar->set(NULL); + } + + $wrapper->created->set($article_data['created']); + $wrapper->news_client_last_retrieve->set(REQUEST_TIME); + } + catch (Exception $e) { + _news_client_entitymetadatawrapper_exception($e); + } + + // Taxonomy import. + // --Sites. + $site_tids = NULL; + + if (!empty($article_data['sites'])) { + $sites = $article_data['sites']; + + foreach ($sites as $site) { + // Correcting a strange issue with NULL sites names after taxonomy term delete. + if (!empty($site)) { + // Add to taxonomy if it doesn't exist. + _news_client_add_taxonomy_term($site, 'news_client_sites'); + + // Look up tid. + $terms = taxonomy_get_term_by_name($site, 'news_client_sites'); + + if (count($terms)) { + $term = array_shift($terms); + $site_tids[] = $term->tid; + } + } + } + } + + try { + $wrapper->news_client_sites = $site_tids; + } + catch (Exception $e) { + _news_client_entitymetadatawrapper_exception($e); + } + + + // --Tags. + $tag_tids = NULL; + + if (!empty($article_data['tags'])) { + $tags = $article_data['tags']; + + foreach ($tags as $tag) { + // Correcting a strange issue with NULL tag names after taxonomy term delete. + if (!empty($tag)) { + // Add to taxonomy if it doesn't exist. + _news_client_add_taxonomy_term($tag, 'news_client_tags'); + + // Look up tid. + $terms = taxonomy_get_term_by_name($tag, 'news_client_tags'); + + if (count($terms)) { + $term = array_shift($terms); + $tag_tids[] = $term->tid; + } + } + } + } + + try { + $wrapper->news_client_tags = $tag_tids; + } + catch (Exception $e) { + _news_client_entitymetadatawrapper_exception($e); + } + + // --Featured Images. + $images_json = NULL; + + if (!empty($article_data['images'])) { + $images_json = json_encode($article_data['images']); + } + + try { + $wrapper->news_client_image_json = $images_json; + } + catch (Exception $e) { + _news_client_entitymetadatawrapper_exception($e); + } + + try { + $wrapper->save(); + $entity_id = $wrapper->nid->value(); + + // Set alias. + if (module_exists('path') && !empty($article_data->alias)) { + $alias = $article_data['alias']; + $path = array( + 'source' => 'node/' . $entity_id, + 'alias' => $alias, + ); + path_save($path); + } + } + catch (Exception $e) { + _news_client_entitymetadatawrapper_exception($e); + } + + return $entity; +} + +/** + * Adds news_client taxonomy term. + */ +function _news_client_add_taxonomy_term($name, $vocabulary_machine_name) { + $terms = taxonomy_get_term_by_name($name, $vocabulary_machine_name); + + if (!count($terms)) { + // Term does not exist in vocabulary. + $vocabulary = taxonomy_vocabulary_machine_name_load($vocabulary_machine_name); + + if ($vocabulary !== FALSE) { + $vid = $vocabulary->vid; + + $term = new stdClass(); + $term->vid = $vid; + $term->name = $name; + $term->parent = 0; + + $status = taxonomy_term_save($term); + } + } +} + +/** + * Exception handling for EntityMetadataWrapper. + * + * @param Exception $e + */ +function _news_client_entitymetadatawrapper_exception($e) { + watchdog( + 'news_service', + 'EntityMetadataWrapper exception in %function() <pre>@trace</pre>', + array('%function' => __FUNCTION__, '@trace' => $e->getTraceAsString()), + WATCHDOG_ERROR + ); +} + +/** + * Utility function for getting the configuration file path. + * + * @return string The OAuth2 configuration file path for news_client. + */ +function _news_client_get_config_file_path() { + $pantheon_support_enabled = variable_get('news_client_pantheon_support_enabled', 0); + $config_file_path = variable_get('news_client_config_file_path', '/tmp/news_client_config.txt'); + + if ($pantheon_support_enabled && isset($_SERVER['PRESSFLOW_SETTINGS'])) { + // Modify config file path to reflect Pantheon server root. + $pressflow_settings = json_decode($_SERVER['PRESSFLOW_SETTINGS'], TRUE); + $pantheon_binding = $pressflow_settings['conf']['pantheon_binding']; + + $config_file_path = '/srv/bindings/' . $pantheon_binding . '/' . $config_file_path; + } + + return $config_file_path; +} diff --git a/profiles/wcm_base/modules/custom/news_client/templates/field--news-client-image-json.tpl.php b/profiles/wcm_base/modules/custom/news_client/templates/field--news-client-image-json.tpl.php new file mode 100644 index 0000000000000000000000000000000000000000..f25d55c8b920d5362eebf8ec01c25abbcc23a41f --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/templates/field--news-client-image-json.tpl.php @@ -0,0 +1,54 @@ +<?php + +/** + * @file field.tpl.php + * Default template implementation to display the value of a field. + * + * This file is not used and is here as a starting point for customization only. + * @see theme_field() + * + * Available variables: + * - $items: An array of field values. Use render() to output them. + * - $label: The item label. + * - $label_hidden: Whether the label display is set to 'hidden'. + * - $classes: String of classes that can be used to style contextually through + * CSS. It can be manipulated through the variable $classes_array from + * preprocess functions. The default values can be one or more of the + * following: + * - field: The current template type, i.e., "theming hook". + * - field-name-[field_name]: The current field name. For example, if the + * field name is "field_description" it would result in + * "field-name-field-description". + * - field-type-[field_type]: The current field type. For example, if the + * field type is "text" it would result in "field-type-text". + * - field-label-[label_display]: The current label position. For example, if + * the label position is "above" it would result in "field-label-above". + * + * Other variables: + * - $element['#object']: The entity to which the field is attached. + * - $element['#view_mode']: View mode, e.g. 'full', 'teaser'... + * - $element['#field_name']: The field name. + * - $element['#field_type']: The field type. + * - $element['#field_language']: The field language. + * - $element['#field_translatable']: Whether the field is translatable or not. + * - $element['#label_display']: Position of label display, inline, above, or + * hidden. + * - $field_name_css: The css-compatible field name. + * - $field_type_css: The css-compatible field type. + * - $classes_array: Array of html class attribute values. It is flattened + * into a string within the variable $classes. + * + * @see template_preprocess_field() + * @see theme_field() + * + * @ingroup themeable + */ +?> +<div class="<?php print $classes; ?>"<?php print $attributes; ?>> + <?php if (!$label_hidden): ?> + <div class="field-label"<?php print $title_attributes; ?>><?php print $label ?>: </div> + <?php endif; ?> + <div class="field-items"<?php print $content_attributes; ?>> + <?php print $image_markup; ?> + </div> +</div> diff --git a/profiles/wcm_base/modules/custom/news_client/views/handlers/news_client_views_handler_field_news_client_image_json.inc b/profiles/wcm_base/modules/custom/news_client/views/handlers/news_client_views_handler_field_news_client_image_json.inc new file mode 100644 index 0000000000000000000000000000000000000000..82d0e0728f3f68f0a937e309a13ce223c30ece94 --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/views/handlers/news_client_views_handler_field_news_client_image_json.inc @@ -0,0 +1,66 @@ +<?php +/** + * Custom views handler for news_client_image_json field. + */ + +class news_client_views_handler_field_news_client_image_json extends views_handler_field { + /** + * Render the field. + * + * @param $values + * The values retrieved from the database. + */ + function render($values) { + $nid = $this->get_value($values); + + $query = new EntityFieldQuery(); + $query->entityCondition('entity_type', 'node'); + $query->entityCondition('bundle', 'news_client_cached_article'); + $query->propertyCondition('nid', $nid, '='); + + $result = $query->execute(); + + if (isset($result['node'])) { + $cached_article_nids = array_keys($result['node']); + $cached_article_nid = array_shift($cached_article_nids); + + $cached_article = entity_load_single('node', $cached_article_nid); + + $ca_wrapper = NULL; + + try { + $ca_wrapper = entity_metadata_wrapper('node', $cached_article); + } + catch (Exception $e) { + _news_client_entitymetadatawrapper_exception($e); + } + + $image_json = ''; + + try { + $image_json = $ca_wrapper->news_client_image_json->value(); + } + catch (Exception $e) { + _news_client_entitymetadatawrapper_exception($e); + } + + $image_data = json_decode($image_json); + + $image_markup = ''; + + foreach ($image_data as $image) { + $data = array( + 'path' => $image->url, + 'alt' => $image->alt, + 'title' => $image->title, + 'attributes' => array( + 'class' => array('news_client_image_json'), + ), + ); + $image_markup .= theme_image($data); + } + } + + return $image_markup; + } +} diff --git a/profiles/wcm_base/modules/custom/news_client/views/handlers/news_client_views_handler_field_news_client_operations.inc b/profiles/wcm_base/modules/custom/news_client/views/handlers/news_client_views_handler_field_news_client_operations.inc new file mode 100644 index 0000000000000000000000000000000000000000..83f9e1737471bc30518cc97f2d5bec184199b86f --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/views/handlers/news_client_views_handler_field_news_client_operations.inc @@ -0,0 +1,35 @@ +<?php +/** + * Custom views handler for news_client_operations field. + */ + +class news_client_views_handler_field_news_client_operations extends views_handler_field { + /** + * Render the field. + * + * @param $values + * The values retrieved from the database. + */ + function render($values) { + $nid = $this->get_value($values); + + $links = array( + array( + 'title' => t('Sync'), + 'href' => 'admin/config/services/news_client/sync/' . $nid, + ) + ); + + $markup = theme_links( + array( + 'links' => $links, + 'attributes' => array( + 'class' => array('links', 'inline', 'button'), + ), + 'heading' => array(), + ) + ); + + return $markup; + } +} diff --git a/profiles/wcm_base/modules/custom/news_client/views/news_client.views_default.inc b/profiles/wcm_base/modules/custom/news_client/views/news_client.views_default.inc new file mode 100644 index 0000000000000000000000000000000000000000..5ca8c0186c4f022a36cdbf0aae611da14a2ad2bd --- /dev/null +++ b/profiles/wcm_base/modules/custom/news_client/views/news_client.views_default.inc @@ -0,0 +1,198 @@ +<?php +/** + * Implements hook_views_default_views(). + */ +function news_client_views_default_views() { + $views = array(); + + $view = new view(); + $view->name = 'news_client_cache_view'; + $view->description = ''; + $view->tag = 'default'; + $view->base_table = 'node'; + $view->human_name = 'News Client Cache'; + $view->core = 7; + $view->api_version = '3.0'; + $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */ + + /* Display: Master */ + $handler = $view->new_display('default', 'Master', 'default'); + $handler->display->display_options['use_more_always'] = FALSE; + $handler->display->display_options['access']['type'] = 'role'; + $handler->display->display_options['access']['role'] = array( + 3 => '3', + 8 => '8', + ); + $handler->display->display_options['cache']['type'] = 'none'; + $handler->display->display_options['query']['type'] = 'views_query'; + $handler->display->display_options['exposed_form']['type'] = 'better_exposed_filters'; + $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search'; + $handler->display->display_options['exposed_form']['options']['reset_button'] = TRUE; + $handler->display->display_options['exposed_form']['options']['expose_sort_order'] = FALSE; + $handler->display->display_options['exposed_form']['options']['bef'] = array( + 'general' => array( + 'input_required' => 0, + 'text_input_required' => array( + 'text_input_required' => array( + 'value' => 'Select any filter and click on Apply to see results', + 'format' => 'filtered_html', + ), + ), + 'allow_secondary' => 0, + 'secondary_label' => 'Advanced options', + 'secondary_collapse_override' => '0', + ), + 'title' => array( + 'bef_format' => 'default', + 'more_options' => array( + 'autosubmit' => 0, + 'is_secondary' => 0, + 'any_label' => '', + 'bef_filter_description' => '', + 'placeholder' => 'disable', + 'placeholder_text' => '', + 'tokens' => array( + 'available' => array( + 0 => 'global_types', + ), + ), + 'rewrite' => array( + 'filter_rewrite_values' => '', + ), + ), + ), + ); + $handler->display->display_options['pager']['type'] = 'full'; + $handler->display->display_options['style_plugin'] = 'table'; + $handler->display->display_options['style_options']['columns'] = array( + 'title' => 'title', + 'news_client_news_service_nid' => 'news_client_news_service_nid', + 'news_client_last_retrieve' => 'news_client_last_retrieve', + 'news_client_operations' => 'news_client_operations', + ); + $handler->display->display_options['style_options']['default'] = 'news_client_last_retrieve'; + $handler->display->display_options['style_options']['info'] = array( + 'title' => array( + 'sortable' => 1, + 'default_sort_order' => 'asc', + 'align' => '', + 'separator' => '', + 'empty_column' => 0, + ), + 'news_client_news_service_nid' => array( + 'sortable' => 1, + 'default_sort_order' => 'desc', + 'align' => '', + 'separator' => '', + 'empty_column' => 0, + ), + 'news_client_last_retrieve' => array( + 'sortable' => 1, + 'default_sort_order' => 'desc', + 'align' => '', + 'separator' => '', + 'empty_column' => 0, + ), + 'news_client_operations' => array( + 'align' => '', + 'separator' => '', + 'empty_column' => 0, + ), + ); + $handler->display->display_options['style_options']['empty_table'] = TRUE; + /* No results behavior: Global: Text area */ + $handler->display->display_options['empty']['area']['id'] = 'area'; + $handler->display->display_options['empty']['area']['table'] = 'views'; + $handler->display->display_options['empty']['area']['field'] = 'area'; + $handler->display->display_options['empty']['area']['empty'] = TRUE; + $handler->display->display_options['empty']['area']['content'] = 'No cached articles.'; + $handler->display->display_options['empty']['area']['format'] = 'filtered_html'; + /* Field: Content: Title */ + $handler->display->display_options['fields']['title']['id'] = 'title'; + $handler->display->display_options['fields']['title']['table'] = 'node'; + $handler->display->display_options['fields']['title']['field'] = 'title'; + $handler->display->display_options['fields']['title']['alter']['word_boundary'] = FALSE; + $handler->display->display_options['fields']['title']['alter']['ellipsis'] = FALSE; + /* Field: Content: News Service Identifier */ + $handler->display->display_options['fields']['news_client_news_service_nid']['id'] = 'news_client_news_service_nid'; + $handler->display->display_options['fields']['news_client_news_service_nid']['table'] = 'field_data_news_client_news_service_nid'; + $handler->display->display_options['fields']['news_client_news_service_nid']['field'] = 'news_client_news_service_nid'; + $handler->display->display_options['fields']['news_client_news_service_nid']['label'] = 'News Service ID'; + $handler->display->display_options['fields']['news_client_news_service_nid']['settings'] = array( + 'thousand_separator' => '', + 'prefix_suffix' => 1, + ); + /* Field: Content: Most Recent Retrieval Date */ + $handler->display->display_options['fields']['news_client_last_retrieve']['id'] = 'news_client_last_retrieve'; + $handler->display->display_options['fields']['news_client_last_retrieve']['table'] = 'field_data_news_client_last_retrieve'; + $handler->display->display_options['fields']['news_client_last_retrieve']['field'] = 'news_client_last_retrieve'; + $handler->display->display_options['fields']['news_client_last_retrieve']['label'] = 'Most Recent Fetch'; + $handler->display->display_options['fields']['news_client_last_retrieve']['settings'] = array( + 'format_type' => 'medium', + 'fromto' => 'both', + 'multiple_number' => '', + 'multiple_from' => '', + 'multiple_to' => '', + 'show_remaining_days' => 0, + ); + /* Field: Content: Sites */ + $handler->display->display_options['fields']['news_client_sites']['id'] = 'news_client_sites'; + $handler->display->display_options['fields']['news_client_sites']['table'] = 'field_data_news_client_sites'; + $handler->display->display_options['fields']['news_client_sites']['field'] = 'news_client_sites'; + $handler->display->display_options['fields']['news_client_sites']['type'] = 'taxonomy_term_reference_plain'; + $handler->display->display_options['fields']['news_client_sites']['delta_offset'] = '0'; + /* Field: Content: News Client Operations */ + $handler->display->display_options['fields']['news_client_operations']['id'] = 'news_client_operations'; + $handler->display->display_options['fields']['news_client_operations']['table'] = 'node'; + $handler->display->display_options['fields']['news_client_operations']['field'] = 'news_client_operations'; + $handler->display->display_options['fields']['news_client_operations']['label'] = 'Operations'; + /* Sort criterion: Content: Post date */ + $handler->display->display_options['sorts']['created']['id'] = 'created'; + $handler->display->display_options['sorts']['created']['table'] = 'node'; + $handler->display->display_options['sorts']['created']['field'] = 'created'; + $handler->display->display_options['sorts']['created']['order'] = 'DESC'; + /* Filter criterion: Content: Published */ + $handler->display->display_options['filters']['status']['id'] = 'status'; + $handler->display->display_options['filters']['status']['table'] = 'node'; + $handler->display->display_options['filters']['status']['field'] = 'status'; + $handler->display->display_options['filters']['status']['value'] = 1; + $handler->display->display_options['filters']['status']['group'] = 1; + $handler->display->display_options['filters']['status']['expose']['operator'] = FALSE; + /* Filter criterion: Content: Type */ + $handler->display->display_options['filters']['type']['id'] = 'type'; + $handler->display->display_options['filters']['type']['table'] = 'node'; + $handler->display->display_options['filters']['type']['field'] = 'type'; + $handler->display->display_options['filters']['type']['value'] = array( + 'news_client_cached_article' => 'news_client_cached_article', + ); + /* Filter criterion: Content: Title */ + $handler->display->display_options['filters']['title']['id'] = 'title'; + $handler->display->display_options['filters']['title']['table'] = 'node'; + $handler->display->display_options['filters']['title']['field'] = 'title'; + $handler->display->display_options['filters']['title']['operator'] = 'contains'; + $handler->display->display_options['filters']['title']['exposed'] = TRUE; + $handler->display->display_options['filters']['title']['expose']['operator_id'] = 'title_op'; + $handler->display->display_options['filters']['title']['expose']['label'] = 'Title'; + $handler->display->display_options['filters']['title']['expose']['operator'] = 'title_op'; + $handler->display->display_options['filters']['title']['expose']['identifier'] = 'title'; + $handler->display->display_options['filters']['title']['expose']['remember_roles'] = array( + 2 => '2', + 1 => 0, + 6 => 0, + 5 => 0, + 4 => 0, + 7 => 0, + 8 => 0, + 3 => 0, + ); + $handler->display->display_options['filters']['title']['expose']['autocomplete_items'] = '10'; + $handler->display->display_options['filters']['title']['expose']['autocomplete_min_chars'] = '0'; + $handler->display->display_options['filters']['title']['expose']['autocomplete_field'] = 'title'; + $handler->display->display_options['filters']['title']['expose']['autocomplete_raw_suggestion'] = 1; + $handler->display->display_options['filters']['title']['expose']['autocomplete_raw_dropdown'] = 1; + $handler->display->display_options['filters']['title']['expose']['autocomplete_dependent'] = 0; + + $views[$view->name] = $view; + + return $views; +} diff --git a/profiles/wcm_base/modules/custom/ocio_news/ocio_news.ds.inc b/profiles/wcm_base/modules/custom/ocio_news/ocio_news.ds.inc index ae5ad2a2fbb831b2ec579f5031521ae7dd39c923..9031bc138b1e0232a5b53a1186e23798c3d5d659 100644 --- a/profiles/wcm_base/modules/custom/ocio_news/ocio_news.ds.inc +++ b/profiles/wcm_base/modules/custom/ocio_news/ocio_news.ds.inc @@ -21,6 +21,9 @@ function ocio_news_ds_field_settings_info() { 'weight' => '2', 'label' => 'hidden', 'format' => 'default', + 'formatter_settings' => array( + 'ft' => array(), + ), ), 'title' => array( 'weight' => '1', @@ -33,8 +36,16 @@ function ocio_news_ds_field_settings_info() { 'ft' => array(), ), ), - 'changed_date' => array( + 'post_date' => array( 'weight' => '8', + 'label' => 'hidden', + 'format' => 'ds_post_date_panopoly_day', + 'formatter_settings' => array( + 'ft' => array(), + ), + ), + 'changed_date' => array( + 'weight' => '9', 'label' => 'inline', 'format' => 'ds_post_date_panopoly_day', 'formatter_settings' => array( @@ -176,7 +187,8 @@ function ocio_news_ds_layout_settings_info() { 7 => 'field_tags', ), 'ds_hidden' => array( - 8 => 'changed_date', + 8 => 'post_date', + 9 => 'changed_date', ), ), 'fields' => array( @@ -188,6 +200,7 @@ function ocio_news_ds_layout_settings_info() { 'field_sidebar' => 'right', 'field_learn_more' => 'footer', 'field_tags' => 'footer', + 'post_date' => 'ds_hidden', 'changed_date' => 'ds_hidden', ), 'classes' => array(), diff --git a/profiles/wcm_base/modules/custom/ocio_news/ocio_news.features.field_instance.inc b/profiles/wcm_base/modules/custom/ocio_news/ocio_news.features.field_instance.inc index f6470f7e748e681d0a28d84588acc3631c94dea4..db786c37feb474fb6d1f877a289d2ab202e449a0 100644 --- a/profiles/wcm_base/modules/custom/ocio_news/ocio_news.features.field_instance.inc +++ b/profiles/wcm_base/modules/custom/ocio_news/ocio_news.features.field_instance.inc @@ -15,7 +15,7 @@ function ocio_news_field_default_field_instances() { 'bundle' => 'article', 'default_value' => NULL, 'deleted' => 0, - 'description' => 'Leave blank to use node author. ', + 'description' => 'Name to display in place of the original author. Enter <em><none></em> to hide attribution completely.', 'display' => array( 'default' => array( 'label' => 'hidden', @@ -579,7 +579,7 @@ function ocio_news_field_default_field_instances() { t('Image'); t('Kicker'); t('Learn More'); - t('Leave blank to use node author. '); + t('Name to display in place of the original author. Enter <em><none></em> to hide attribution completely.'); t('Sidebar'); t('Use for supplemental information such as data or related facts. '); t('Use this field to link to other stories (internal or external). All items will be displayed as a list below the body of the story. '); diff --git a/profiles/wcm_base/modules/custom/ocio_news/ocio_news.info b/profiles/wcm_base/modules/custom/ocio_news/ocio_news.info index 7ddcffde48f0f6f82df2df7a3c8e1ad1dea326c0..41c8f2f7f552ecee08c90735477b12f8bee976f3 100644 --- a/profiles/wcm_base/modules/custom/ocio_news/ocio_news.info +++ b/profiles/wcm_base/modules/custom/ocio_news/ocio_news.info @@ -5,6 +5,9 @@ package = OCIO Features version = 7.x-1.0 project = ocio_news dependencies[] = context +dependencies[] = custom_breadcrumbs_features +dependencies[] = custom_breadcrumbs_paths +dependencies[] = ds dependencies[] = media dependencies[] = ocio_field_bases dependencies[] = ocio_taxonomy @@ -56,8 +59,8 @@ features[variable][] = node_submitted_article features[variable][] = private_article features[variable][] = workbench_moderation_default_state_article features[views_view][] = ocio_news_archive -features_exclude[field_instance][node-article-field_tags] = node-article-field_tags -features_exclude[field_instance][node-article-field_news_service_sites] = node-article-field_news_service_sites features_exclude[dependencies][views_content] = views_content features_exclude[field_base][field_news_service_sites] = field_news_service_sites +features_exclude[field_instance][node-article-field_tags] = node-article-field_tags +features_exclude[field_instance][node-article-field_news_service_sites] = node-article-field_news_service_sites features_exclude[taxonomy][news_service_sites] = news_service_sites diff --git a/profiles/wcm_base/modules/custom/ocio_news/ocio_news.module b/profiles/wcm_base/modules/custom/ocio_news/ocio_news.module index 43324cda30e987876e3398e879052670db7751a3..0f96f9fb993c6640c40b62066c35467918b16417 100644 --- a/profiles/wcm_base/modules/custom/ocio_news/ocio_news.module +++ b/profiles/wcm_base/modules/custom/ocio_news/ocio_news.module @@ -6,6 +6,32 @@ include_once 'ocio_news.features.inc'; +/** + * Implements hook_preprocess_node(). + * + * Hide author from byline DisplaySuite field if value of the byline node field is '<none>' + */ +function ocio_news_preprocess_node(&$vars) { + if ($vars['type'] == 'article' && !empty($vars['field_byline']) && $vars['field_byline']['und'][0]['value'] == '<none>') { + $vars['content']['byline'][0] = $vars['content']['post_date'][0]; + } +} + +/** + * Implements hook_tokens_alter(). + * + * Use byline node field value as author token if it exists. + */ +function ocio_news_tokens_alter(&$replacements, $context) { + if (isset($context['tokens']['author']) && $context['type'] == 'node'){ + $node = $context['data']['node']; + + if ($node->type == 'article' && !empty($node->field_byline)) { + $replacements['[node:author]'] = $node->field_byline['und'][0]['value']; + } + } +} + /** * Implements hook_preprocess_views_view(). */ diff --git a/profiles/wcm_base/modules/contrib/search_api/PATCHES.txt b/profiles/wcm_base/modules/panopoly/panopoly_search/PATCHES.txt similarity index 62% rename from profiles/wcm_base/modules/contrib/search_api/PATCHES.txt rename to profiles/wcm_base/modules/panopoly/panopoly_search/PATCHES.txt index eb1be12e08ac3f18dea627aa371543f59ab46dbc..ba22731d3509d96bb14574d7b4ddc13dabd1abf3 100644 --- a/profiles/wcm_base/modules/contrib/search_api/PATCHES.txt +++ b/profiles/wcm_base/modules/panopoly/panopoly_search/PATCHES.txt @@ -1,4 +1,4 @@ The following patches have been applied to this project: -- https://www.drupal.org/files/issues/search_api-missing-module-2838075-2.patch +- https://www.drupal.org/files/issues/panopoly_search-update-search-api-2863077-2.patch This file was automatically generated by Drush Make (http://drupal.org/project/drush). diff --git a/profiles/wcm_base/modules/panopoly/panopoly_search/panopoly_search.make b/profiles/wcm_base/modules/panopoly/panopoly_search/panopoly_search.make index dac0834b0cc02082070ffaa63949939891424135..c5009dc525fa450c56bd93012684f1a24ebe6c88 100644 --- a/profiles/wcm_base/modules/panopoly/panopoly_search/panopoly_search.make +++ b/profiles/wcm_base/modules/panopoly/panopoly_search/panopoly_search.make @@ -8,14 +8,13 @@ core = 7.x projects[facetapi][version] = 1.5 projects[facetapi][subdir] = contrib -projects[search_api][version] = 1.18 +projects[search_api][version] = 1.21 projects[search_api][subdir] = contrib -projects[search_api][patch][2838075] = https://www.drupal.org/files/issues/search_api-missing-module-2838075-2.patch -projects[search_api_solr][version] = 1.10 +projects[search_api_solr][version] = 1.12 projects[search_api_solr][subdir] = contrib -projects[search_api_db][version] = 1.5 +projects[search_api_db][version] = 1.6 projects[search_api_db][subdir] = contrib ; Solr PHP Client Library diff --git a/profiles/wcm_base/themes/ocio_omega_base/css/layouts/ocio-default/ocio-default.layout.css b/profiles/wcm_base/themes/ocio_omega_base/css/layouts/ocio-default/ocio-default.layout.css index 249096a54954ba45c8d5b04d4bdeb766bfeebdbf..e19011d5e9189876d460b07306037687c0a77307 100644 --- a/profiles/wcm_base/themes/ocio_omega_base/css/layouts/ocio-default/ocio-default.layout.css +++ b/profiles/wcm_base/themes/ocio_omega_base/css/layouts/ocio-default/ocio-default.layout.css @@ -774,15 +774,18 @@ ol ol ol { float: left; clear: left; margin: 0 2em 1em 0; + max-width: 30%; } .media-element.file-image-right { float: right; clear: right; margin: 0 0 1em 2em; + max-width: 30%; } .media-element.file-image-center { float: none; margin: 0 auto; + max-width: 50%; } .media-element.file-image-max { margin: 0 0 1em 0; @@ -840,15 +843,18 @@ ol ol ol { float: left; clear: left; margin: 0 2em 1em 0; + max-width: 30%; } .media-element-container.media-image_right { float: right; clear: right; margin: 0 0 1em 2em; + max-width: 30%; } .media-element-container.media-image_center { float: none; margin: 0 auto; + max-width: 50%; } .media-element-container.media-image_max { margin: 0 0 1em 0; @@ -921,6 +927,7 @@ img, media { margin: 0 auto; float: none; display: block; + max-width: 100%; } } /** diff --git a/profiles/wcm_base/themes/ocio_omega_base/css/layouts/ocio-default/ocio-default.layout.no-query.css b/profiles/wcm_base/themes/ocio_omega_base/css/layouts/ocio-default/ocio-default.layout.no-query.css index aea11e7cf403f42cf02b03abd8349eed7d1fce41..96f0dbda2e0fa40246e986295328dadba45d33ff 100644 --- a/profiles/wcm_base/themes/ocio_omega_base/css/layouts/ocio-default/ocio-default.layout.no-query.css +++ b/profiles/wcm_base/themes/ocio_omega_base/css/layouts/ocio-default/ocio-default.layout.no-query.css @@ -773,15 +773,18 @@ ol ol ol { float: left; clear: left; margin: 0 2em 1em 0; + max-width: 30%; } .media-element.file-image-right { float: right; clear: right; margin: 0 0 1em 2em; + max-width: 30%; } .media-element.file-image-center { float: none; margin: 0 auto; + max-width: 50%; } .media-element.file-image-max { margin: 0 0 1em 0; @@ -839,15 +842,18 @@ ol ol ol { float: left; clear: left; margin: 0 2em 1em 0; + max-width: 30%; } .media-element-container.media-image_right { float: right; clear: right; margin: 0 0 1em 2em; + max-width: 30%; } .media-element-container.media-image_center { float: none; margin: 0 auto; + max-width: 50%; } .media-element-container.media-image_max { margin: 0 0 1em 0; @@ -919,6 +925,7 @@ img, media { margin: 0 auto; float: none; display: block; + max-width: 100%; } /** diff --git a/profiles/wcm_base/themes/ocio_omega_base/css/ocio-omega-base.no-query.css b/profiles/wcm_base/themes/ocio_omega_base/css/ocio-omega-base.no-query.css index 8fc76e5bde25dada248084d6e6ae260a654fc8d2..f3c5e12cffda2750bfd93533dc82bf647b8328bd 100644 --- a/profiles/wcm_base/themes/ocio_omega_base/css/ocio-omega-base.no-query.css +++ b/profiles/wcm_base/themes/ocio_omega_base/css/ocio-omega-base.no-query.css @@ -769,15 +769,18 @@ ol ol ol { float: left; clear: left; margin: 0 2em 1em 0; + max-width: 30%; } .media-element.file-image-right { float: right; clear: right; margin: 0 0 1em 2em; + max-width: 30%; } .media-element.file-image-center { float: none; margin: 0 auto; + max-width: 50%; } .media-element.file-image-max { margin: 0 0 1em 0; @@ -835,15 +838,18 @@ ol ol ol { float: left; clear: left; margin: 0 2em 1em 0; + max-width: 30%; } .media-element-container.media-image_right { float: right; clear: right; margin: 0 0 1em 2em; + max-width: 30%; } .media-element-container.media-image_center { float: none; margin: 0 auto; + max-width: 50%; } .media-element-container.media-image_max { margin: 0 0 1em 0; @@ -915,6 +921,7 @@ img, media { margin: 0 auto; float: none; display: block; + max-width: 100%; } /** diff --git a/profiles/wcm_base/themes/ocio_omega_base/css/ocio-omega-base.styles.css b/profiles/wcm_base/themes/ocio_omega_base/css/ocio-omega-base.styles.css index dada2f3dd405b5b443dfe7ee9fb15ee13c2877f5..0d3f5f927660cebfe82b5876713d41552a876d99 100644 --- a/profiles/wcm_base/themes/ocio_omega_base/css/ocio-omega-base.styles.css +++ b/profiles/wcm_base/themes/ocio_omega_base/css/ocio-omega-base.styles.css @@ -770,15 +770,18 @@ ol ol ol { float: left; clear: left; margin: 0 2em 1em 0; + max-width: 30%; } .media-element.file-image-right { float: right; clear: right; margin: 0 0 1em 2em; + max-width: 30%; } .media-element.file-image-center { float: none; margin: 0 auto; + max-width: 50%; } .media-element.file-image-max { margin: 0 0 1em 0; @@ -836,15 +839,18 @@ ol ol ol { float: left; clear: left; margin: 0 2em 1em 0; + max-width: 30%; } .media-element-container.media-image_right { float: right; clear: right; margin: 0 0 1em 2em; + max-width: 30%; } .media-element-container.media-image_center { float: none; margin: 0 auto; + max-width: 50%; } .media-element-container.media-image_max { margin: 0 0 1em 0; @@ -917,6 +923,7 @@ img, media { margin: 0 auto; float: none; display: block; + max-width: 100%; } } /** diff --git a/profiles/wcm_base/themes/ocio_omega_base/sass/base/_media.scss b/profiles/wcm_base/themes/ocio_omega_base/sass/base/_media.scss index fb4f4834b55da60eb547a8c4a3ac5ff598a19147..192f086c0e04e88ced1f900b55f6711256e918a2 100644 --- a/profiles/wcm_base/themes/ocio_omega_base/sass/base/_media.scss +++ b/profiles/wcm_base/themes/ocio_omega_base/sass/base/_media.scss @@ -41,6 +41,9 @@ @if $type == "video" { width: 50%; } + @else { + max-width: 30%; + } } &.#{$prefix}-#{$type}#{$separator}right { @@ -51,6 +54,9 @@ @if $type == "video" { width: 50%; } + @else { + max-width: 30%; + } } &.#{$prefix}-#{$type}#{$separator}center { @@ -60,6 +66,10 @@ @if $type == "video" { width: 75%; } + @else { + max-width: 50%; + } + } &.#{$prefix}-#{$type}#{$separator}max { @@ -123,6 +133,7 @@ img, media { margin: 0 auto; float: none; display: block; + max-width: 100%; } } } diff --git a/profiles/wcm_base/themes/wcm_omega/css/wcm-omega.styles.css b/profiles/wcm_base/themes/wcm_omega/css/wcm-omega.styles.css index 020ba4173e8be150716adfe83e7ee3fe4fe84c5b..65f4bb7fd15324685f05174f5f21276452e887ea 100644 --- a/profiles/wcm_base/themes/wcm_omega/css/wcm-omega.styles.css +++ b/profiles/wcm_base/themes/wcm_omega/css/wcm-omega.styles.css @@ -1 +1 @@ -@charset "UTF-8";.align-left,table caption{text-align:left}.visuallyhidden{position:absolute;overflow:hidden;clip:rect(0 0 0 0);height:1px;width:1px;margin:-1px;padding:0;border:0}.ui-accordion .ui-accordion-header{background:#ebebeb!important}.ui-accordion .ui-accordion-header-active,.ui-accordion .ui-accordion-header:hover{background:#d2d2d2!important}.ui-accordion .ui-accordion-header p{margin:0}.ui-accordion .ui-accordion-content{background:#fff;border:1px solid #d2d2d2}.ui-accordion .ui-accordion-content h2:first-child,.ui-accordion .ui-accordion-content h3:first-child{margin-top:10px}.ui-accordion .ui-accordion-content ol{padding-left:.6em}.l-main.lt-gray .ui-accordion .ui-accordion-header{background:#e1e1e1!important}.l-main.lt-gray .ui-accordion .ui-accordion-header:hover{background:#d7d7d7!important}.l-main.lt-gray .ui-accordion .ui-accordion-header-active{background:#e1e1e1!important}.l-main.lt-gray .ui-accordion .ui-accordion-content{background:#fff;border:1px solid #e1e1e1}.ui-accordion-header{overflow:auto}body .panels-row.odd .ui-accordion .ui-accordion-header{background:#d7d7d7}body .panels-row.odd .ui-accordion .ui-accordion-content{border-color:#d7d7d7}.ctools-collapsible-container .ctools-toggle{background-image:url(../images/jquery-images/ui-icons_222222_256x240.png);background-position:-64px -15px}.ctools-collapsible-container .ctools-toggle-collapsed{background-position:-32px -15px;background-image:url(../images/jquery-images/ui-icons_222222_256x240.png)}.ctools-collapsible-container .ctools-toggle-collapsed:hover,.nested-accordion:before,.view-grouping-header:before{background-image:url(../images/jquery-images/ui-icons_222222_256x240.png)}ul.breadcrumb{padding:20px 0;margin:0}ul.breadcrumb li{display:inline-block;margin-right:.45em;font-weight:600}ul.breadcrumb li:after{content:"|";color:#b00;font-weight:700;margin-left:.45em}ul.breadcrumb li a{color:#666;text-decoration:none}ul.breadcrumb li a:visited{color:#666}ul.breadcrumb li a:focus{color:#dcaa38}ul.breadcrumb li a:hover{color:#666;text-decoration:underline}ul.breadcrumb li a:active{color:#028da9}ul.breadcrumb li:last-child{margin-right:0}ul.breadcrumb li:last-child:after{content:" "}#edit-preview,#edit-submit,#edit-submit--2,#edit-submit--3,.button-primary,.form-submit,.page-user-login .login-box.osu a,.red-button,.webform-previous,.webform-submit,html body .button,input[type=button]{font-size:14px;padding:.7em 1.3em .4em;display:inline-block;cursor:pointer;background-color:#b00;border:0;color:#fff;text-transform:uppercase;font-family:proximanova,Helvetica,Arial,sans-serif;letter-spacing:.05em;border-radius:2px;box-shadow:0 3px 0 0 #920000;font-weight:400;margin-right:1.5em}#edit-preview:hover,#edit-submit--2:hover,#edit-submit--3:hover,#edit-submit:hover,.button-primary:hover,.form-submit:hover,.page-user-login .login-box.osu a:hover,.red-button:hover,.webform-previous:hover,.webform-submit:hover,html body .button:hover,input[type=button]:hover{text-decoration:none;background-color:#a20000}#edit-preview:active,#edit-submit--2:active,#edit-submit--3:active,#edit-submit:active,.button-primary:active,.form-submit:active,.page-user-login .login-box.osu a:active,.red-button:active,.webform-previous:active,.webform-submit:active,html body .button:active,input[type=button]:active{background-color:#920000}.disabled#edit-preview,.disabled#edit-submit,.disabled#edit-submit--2,.disabled#edit-submit--3,.disabled.button-primary,.disabled.form-submit,.disabled.webform-previous,.disabled.webform-submit,.page-user-login .login-box.osu a.disabled,.page-user-login .login-box.osu a[disabled],.red-button.disabled,.red-button[disabled],[disabled]#edit-preview,[disabled]#edit-submit,[disabled]#edit-submit--2,[disabled]#edit-submit--3,[disabled].button-primary,[disabled].form-submit,[disabled].webform-previous,[disabled].webform-submit,html body .disabled.button,html body [disabled].button,input.disabled[type=button],input[disabled][type=button]{opacity:.6;background:false;cursor:default;box-shadow:none}#edit-preview.ext .ext,#edit-submit--2.ext .ext,#edit-submit--3.ext .ext,#edit-submit.ext .ext,.button-primary.ext .ext,.form-submit.ext .ext,.webform-previous.ext .ext,.webform-submit.ext .ext,html body .button.ext .ext,input[type=button].ext .ext{background-image:none;padding:0;width:0}a.button{margin-top:20px}#colorbox #cboxWrapper{border-radius:0;font-size:1.1em}#colorbox #cboxWrapper #cboxClose,#colorbox #cboxWrapper #cboxNext,#colorbox #cboxWrapper #cboxPrevious{background-image:none;text-indent:0;color:transparent;overflow:hidden}#colorbox #cboxWrapper #cboxClose:before,#colorbox #cboxWrapper #cboxNext:before,#colorbox #cboxWrapper #cboxPrevious:before{font-family:FontAwesome;bottom:-3px;position:absolute;color:#000}#colorbox #cboxWrapper #cboxClose:before{content:"\f00d";right:0;font-size:1.2em}#colorbox #cboxWrapper #cboxPrevious:before{content:"\f053"}#colorbox #cboxWrapper #cboxNext:before{content:"\f054"}#colorbox #cboxWrapper #cboxCurrent{bottom:-3px}span.ext{margin-left:2px;margin-right:2px}img.file-icon{height:40px;width:auto;padding-bottom:7px;margin:0 3px}.views-exposed-form,.webform-component .description{margin-bottom:30px}input{max-width:100%}input:focus{outline:#999 solid 1px}textarea{resize:none}.webform-component label{text-transform:uppercase;font-weight:600;font-size:14px}.webform-component table .form-text{width:100%}.views-exposed-form label{font-weight:400;font-size:14px;text-transform:uppercase}.views-exposed-form .form-text{height:32px}.webform-component-fieldset .webform-component label{text-transform:uppercase;font-weight:400;font-size:13px}.webform-component-fieldset,.webform-component-file,.webform-component-grid{margin-bottom:40px}.webform-component-file #edit-submitted-file-upload{max-width:240px}@media (max-width:47.4em){.l-main input:not([type=checkbox]):not([type=radio]),.l-main select,.l-main textarea{width:100%}}form .chosen-container .chosen-choices,form .form-text{padding:4px 6px 2px;border:1px solid #bbb;background-image:none;box-shadow:none;font-size:.9em}form .chosen-container{font-size:1em}form .chosen-container .result-selected{display:none!important}form .chosen-container .chosen-results{font-size:.9em}form .chosen-container .search-field input{width:.1px!important;height:.1px!important}form .chosen-container .chosen-results li{padding:7px 6px 4px;line-height:1em}form .chosen-container .chosen-results li.highlighted{background-image:none}form .chosen-container.chosen-container-active.chosen-with-drop .chosen-single,form .chosen-container.chosen-container-multi .chosen-choices li.search-choice,form .chosen-container.chosen-container-single .chosen-single{border-radius:0;background:#eee;box-shadow:none}form .chosen-container.chosen-container .search-field:after,form .chosen-container.chosen-container-active.chosen-with-drop .chosen-choices li.search-choice+.search-field:after{content:"- Select -";color:#666;cursor:default}form .chosen-container.chosen-container-active .search-field,form .chosen-container.chosen-container-multi .chosen-choices li.search-choice+.search-field{float:none}form .chosen-container.chosen-container-single .chosen-results{margin:0;padding:0}form .chosen-container.chosen-container-single .chosen-drop{border-radius:0}form .chosen-container.chosen-container-single .chosen-single{padding:0 0 0 6px;height:27px}form .chosen-container.chosen-container-single .chosen-single div b{background-size:52px 40px!important}form .chosen-container.chosen-container-multi .chosen-choices{padding:1px 3px 0;cursor:default}form .chosen-container.chosen-container-multi .chosen-choices li.search-choice{display:inline-block;float:none;line-height:1em;margin:2px 4px 2px 0;padding:4px 20px 2px 4px}form .chosen-container.chosen-container-multi .chosen-choices li.search-choice .search-choice-close{top:4px}form .chosen-container.chosen-container-multi .chosen-choices li.search-choice+.search-field:after{content:"+ Add";cursor:pointer}.l-constrained:after,.l-main:after,.l-region--sidebar-1:after,.l-region--sidebar-2:after{content:"";display:table;clear:both}form .chosen-container.chosen-container-multi .chosen-choices li.search-field input[type=text]{margin:1px 0 0 2px;cursor:default}.type-group1 h1,.type-group1 h2,.type-group1 h3,.type-group1 h4,.type-group1 h5,.type-group1 h6,.type-group1-sample h1,.type-group1-sample h2,.type-group1-sample h3,.type-group1-sample h4,.type-group1-sample h5,.type-group1-sample h6{font-family:proximanova,Helvetica,Arial,sans-serif;font-weight:400}.type-group1 h1,.type-group1-sample h1{color:#b00}.type-group1 h2.block__title,.type-group1 h2.pane-title,.type-group1-sample h2.block__title,.type-group1-sample h2.pane-title{margin-bottom:.6em;text-transform:uppercase;color:#2d2d2d;font-weight:400;line-height:120%}.type-group2 h1,.type-group2 h2,.type-group2 h3,.type-group2 h4,.type-group2 h5,.type-group2 h6,.type-group2-sample h1,.type-group2-sample h2,.type-group2-sample h3,.type-group2-sample h4,.type-group2-sample h5,.type-group2-sample h6{font-family:proximanova,Helvetica,Arial,sans-serif;font-weight:300}.type-group2 h1,.type-group2-sample h1{font-weight:600}.type-group2 h2,.type-group2 h3,.type-group2-sample h2,.type-group2-sample h3{font-family:capita,Georgia,serif;font-weight:100}.type-group2 h3,.type-group2-sample h3{font-style:italic}.type-group2 h4,.type-group2-sample h4{font-weight:400}.type-group2 h2.block__title,.type-group2 h2.pane-title,.type-group2-sample h2.block__title,.type-group2-sample h2.pane-title{font-weight:400;font-family:proximanova,Helvetica,Arial,sans-serif}.type-group3 h1,.type-group3 h2,.type-group3 h3,.type-group3 h4,.type-group3 h5,.type-group3 h6,.type-group3-sample h1,.type-group3-sample h2,.type-group3-sample h3,.type-group3-sample h4,.type-group3-sample h5,.type-group3-sample h6{font-family:capita,Georgia,serif;font-weight:400}.type-group3 h2,.type-group3-sample h2{font-weight:100;font-style:italic}.type-group3 h3,.type-group3 h4,.type-group3-sample h3,.type-group3-sample h4{font-family:proximanova,Helvetica,Arial,sans-serif;font-weight:400}.type-group3 h2.block__title,.type-group3 h2.pane-title,.type-group3-sample h2.block__title,.type-group3-sample h2.pane-title{font-weight:400;font-style:normal}.l-page img{width:inherit}.image-border,.panopoly-image-featured,.panopoly-image-full,.panopoly-image-half,.panopoly-image-original,.panopoly-image-quarter,.panopoly-image-square,.panopoly-image-thumbnail{border:1px solid #666}.node__content .panopoly-image-featured,.node__content .panopoly-image-full,.node__content .panopoly-image-half,.node__content .panopoly-image-original,.node__content .panopoly-image-quarter,.node__content .panopoly-image-square,.node__content .panopoly-image-thumbnail{float:right;margin:0 0 20px 1.5em}.ui-widget table,.ui-widget td,.ui-widget th,.ui-widget tr{border:0}.ui-widget{font-family:proximanova,Helvetica,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget button,.ui-widget input,.ui-widget select,.ui-widget textarea{font-family:proximanova,Helvetica,Arial,sans-serif;font-size:1em}.ui-widget-content{border:0;background:#ebebeb;color:#2d2d2d}.ui-widget-content a{color:#2d2d2d}.ui-widget-header{border:0;background:#666;color:#fff;font-weight:700}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:0;background:#fff;font-weight:400;color:#2d2d2d}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#2d2d2d;text-decoration:none}.ui-state-focus,.ui-state-hover,.ui-widget-content .ui-state-focus,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-focus,.ui-widget-header .ui-state-hover{border:0;background:#d2d2d2;font-weight:400;color:#2d2d2d}.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited{color:#fff;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:0;background:url(../images/jquery-images/ui-bg_flat_65_ffffff_40x100.png) 50% 50% repeat-x #fff;font-weight:400;color:#2d2d2d}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#2d2d2d;text-decoration:none}.ui-icon{background-image:url(../images/jquery-images/ui-icons_222222_256x240.png)!important}.ui-corner-all,.ui-corner-left,.ui-corner-tl,.ui-corner-top{border-top-left-radius:0}.ui-corner-all,.ui-corner-right,.ui-corner-top,.ui-corner-tr{border-top-right-radius:0}.ui-corner-all,.ui-corner-bl,.ui-corner-bottom,.ui-corner-left{border-bottom-left-radius:0}.ui-corner-all,.ui-corner-bottom,.ui-corner-br,.ui-corner-right{border-bottom-right-radius:0}#modalBackdrop,.cke_dialog_background_cover,.ui-widget-overlay{background-image:none!important;background-color:#000!important;opacity:.5!important}.ui-dialog .ui-dialog-titlebar{height:auto;line-height:unset;font-weight:700;font-size:13px;color:#474747;text-shadow:0 1px 0 rgba(255,255,255,.75);border-bottom:1px solid #999;padding:6px 10px;border-radius:2px 2px 0 0;box-shadow:0 1px 0 #fff inset;background:#cfd1cf;background-image:linear-gradient(top,#f5f5f5,#cfd1cf);filter:progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#fff5f5f5', endColorstr='#ffcfd1cf')}.messages,.pager>li{background-image:none}.ui-front{z-index:1050}.l-constrained{margin:0 auto;padding:0 6%}@media (min-width:47.5em){.l-constrained{padding:0 8%}}@media (min-width:82em){.max-width{max-width:70em;margin:0 auto;padding:0}}ol ol,ol ol ol,ul ul,ul ul ul{margin-top:8px}ul.menu{padding:0}ol,ul{padding-left:3em}ul{list-style-type:square;list-style-position:outside}ul ul,ul ul ul{margin-left:20px}ol{list-style-type:decimal}ol ol{list-style-type:lower-alpha}ol ol ol{list-style-type:lower-roman}.no-list-style,ul.breadcrumb,ul.menu{list-style:none}.field--name-field-basic-text-text li,.field--name-field-ocio-body li,.ui-accordion-content li{margin-bottom:.6em}.ui-accordion-content ul{padding-left:.6em}.caret-list-type ul,.dot-list-type ul,.page-newsletter-archive .l-region--content ul,.pane-bundle-quick-links ul,.pane-wcm-mailchimp-pane ul{padding-left:0;list-style-image:none;list-style-type:none}.caret-list-type li,.page-newsletter-archive .l-region--content li,.pane-bundle-quick-links li,.pane-wcm-mailchimp-pane li{margin-bottom:10px}.caret-list-type li:before,.page-newsletter-archive .l-region--content li:before,.pane-bundle-quick-links li:before,.pane-wcm-mailchimp-pane li:before{content:"\f0da";font-family:FontAwesome;color:gray;margin-right:10px;margin-left:4px;font-size:85%}.dot-list-type li{margin-bottom:40px}.dot-list-type li:before{content:"\f111";font-family:FontAwesome;color:gray;margin-right:10px;font-size:40%}.media-element{display:block}.media-element img{display:block;width:100%;margin:0}.media-element.file-default,.media-element.file-image-full,.media-element.file-image-large,.media-element.file-image-medium,.media-element.file-image-small{margin:0 0 1em}.media-element.file-image-left{float:left;clear:left;margin:0 2em 1em 0}.media-element.file-image-right{float:right;clear:right;margin:0 0 1em 2em}.media-element.file-image-center{float:none;margin:0 auto}.media-element.file-image-max{margin:0 0 1em;width:100%}.media-element.file-image-max .content{width:100%}.media-element.file-video-full,.media-element.file-video-large,.media-element.file-video-medium,.media-element.file-video-small{margin:0 0 1em}.media-element.file-video-left{float:left;clear:left;margin:0 2em 1em 0;width:50%}.media-element.file-video-right{float:right;clear:right;margin:0 0 1em 2em;width:50%}.media-element.file-video-center{float:none;margin:0 auto;width:75%}.media-element.file-video-max{margin:0 0 1em;width:100%}.media-element.file-video-max .content{width:100%}.media-element-container{display:block;display:table;table-layout:fixed;max-width:100%}.media-element-container img{display:block;width:100%;margin:0}.media-element-container.media-default,.media-element-container.media-image_full,.media-element-container.media-image_large,.media-element-container.media-image_medium,.media-element-container.media-image_small{margin:0 0 1em}.media-element-container.media-image_left{float:left;clear:left;margin:0 2em 1em 0}.media-element-container.media-image_right{float:right;clear:right;margin:0 0 1em 2em}.media-element-container.media-image_center{float:none;margin:0 auto}.media-element-container.media-image_max{margin:0 0 1em;width:100%}.media-element-container.media-image_max .content{width:100%}.media-element-container.media-video_full,.media-element-container.media-video_large,.media-element-container.media-video_medium,.media-element-container.media-video_small{margin:0 0 1em}.media-element-container.media-video_left{float:left;clear:left;margin:0 2em 1em 0;width:50%}.media-element-container.media-video_right{float:right;clear:right;margin:0 0 1em 2em;width:50%}.media-element-container.media-video_center{float:none;margin:0 auto;width:75%}.media-element-container.media-video_max .content,.pane-bundle-table table,table{width:100%}.media-element-container.media-video_max{margin:0 0 1em;width:100%}.media-element-container .field--name-field-basic-image-caption,.media-element-container .field-name-field-basic-image-caption{display:table-caption;caption-side:bottom;font-family:capita,Georgia,serif;font-size:.9em;font-weight:300;font-style:italic;line-height:1.3em;color:#606060}.error,.error .error,.messages--error,.messages--status,.messages--warning,.ok,.warning{color:#2d2d2d}.align-center .media-element.file-default{margin-left:auto;margin-right:auto}.align-right .media-element.file-default{margin-left:auto}img,media{max-width:100%}@media (max-width:47.4em){.field .media-element.media-vimeo-video,.field .media-element.media-youtube-video{width:100%;margin:0;float:none;display:block}.field img.media-element{margin:0 auto;float:none;display:block}}.messages{margin:1.8em 0;padding:1.2em 1.6em;border:0;background-color:#d9d9d9}.messages ul{margin:0 0 0 1em;padding:0}.messages li{list-style-image:none}.messages--status,tr.ok{border-left:8px solid #d4df48}.messages--warning,tr.warning{border-left:8px solid #dcaa38}.messages--error,tr.error{border-left:8px solid #b00}.pager>li{display:inline;padding:.5em;list-style-type:none}table{margin-bottom:20px;line-height:140%}.ui-accordion-content table a,.ui-tabs-content table a,table .ui-accordion-content a,table .ui-tabs-content a,table a,table li,table p{font-size:15px;font-size:1.5rem;line-height:120%!important}table th{background:#dedede;font-weight:600;border:1px solid #c7c7c7!important;text-transform:uppercase}.ui-accordion-content table td,table tbody,table td,table th{border:1px solid #c7c7c7}.ui-accordion-content table th a,.ui-tabs-content table th a,table th .ui-accordion-content a,table th .ui-tabs-content a,table th a{text-decoration:none}table tbody tr{border-bottom:1px solid #c7c7c7}table tbody tr.odd,table tbody tr:nth-child(odd){background:#f0f0f0}table tbody tr.even,table tbody tr:nth-child(even){background:#fff}table thead+tbody tr.odd,table thead+tbody tr:nth-child(odd){background:#f0f0f0}.panels-row.odd table tbody tr.odd,.panels-row.odd table tbody tr:nth-child(odd),table thead+tbody tr.even,table thead+tbody tr:nth-child(even){background:#fff}table td,table th{padding:.6em 1em}table caption{color:#666;margin-bottom:5px}.panels-row.odd table tbody tr.even,.panels-row.odd table tbody tr:nth-child(even),.panels-row.odd table thead+tbody tr.odd,.panels-row.odd table thead+tbody tr:nth-child(odd){background:#f3f3f3}.panels-row.odd table thead+tbody tr.even,.panels-row.odd table thead+tbody tr:nth-child(even){background:#fff}table ul{padding-left:3px;list-style-position:inside}.tabs--primary{padding-top:2em}.tabs--primary li{font-weight:400;background:#ebebeb}.tabs--primary li a{text-decoration:none;color:#b00}.tabs--primary li a:visited{color:#b00}.tabs--primary li a:focus{color:#dcaa38}.tabs--primary li a:hover{color:#2d2d2d;background:#d2d2d2}.tabs--primary li a:active{color:#028da9}.tabs--primary li .active{background:#c5c5c5}body,html{font-family:proximanova,Helvetica,Arial,sans-serif;color:#2d2d2d;font-weight:300}p{margin-bottom:14px}em{font-style:italic}@media (max-width:47.4em){html{font-size:58%}.body,.ui-accordion .ui-accordion-content li,.ui-accordion .ui-accordion-content p,body{font-size:18px;font-size:1.8rem;line-height:150%}}@media (min-width:47.5em){html{font-size:60%}.body,.ui-accordion .ui-accordion-content li,.ui-accordion .ui-accordion-content p,body{font-size:17px;font-size:1.7rem;line-height:150%}.width-70{width:85%}}@media (min-width:60em){html{font-size:62.5%}.body,.ui-accordion .ui-accordion-content li,.ui-accordion .ui-accordion-content p,body{font-size:17px;font-size:1.7rem;line-height:150%}}@media (min-width:82em){html{font-size:66%}.body,.ui-accordion .ui-accordion-content li,.ui-accordion .ui-accordion-content p,body{font-size:16px;font-size:1.6rem;line-height:150%}}h1,h2,h3,h4{margin-bottom:10px;line-height:120%}.pane-bundle-text h2,body h2,body h3,body h4,h2.block__title{margin-top:0}h1{font-size:42px;font-size:4.2rem}h2{font-size:32px;font-size:3.2rem}h2.block__title,h2.pane-title{font-size:27px;font-size:2.7rem}h3{font-size:24px;font-size:2.4rem}h4{font-size:20px;font-size:2rem}.block-title-style,.section-tags h1,.views-page h1{text-transform:uppercase;color:#2d2d2d;font-size:27px;font-size:2.7rem}.ui-accordion-content a,.ui-tabs-content a,a{color:#b00;font-weight:500;text-decoration:none}a:visited{color:#b00}a:focus{color:#d4df48}a:hover{color:#028da9;text-decoration:underline}a:active{color:#d65828}.ui-accordion-content strong a,.ui-tabs-content strong a,strong .ui-accordion-content a,strong .ui-tabs-content a,strong a{font-weight:700}.header-links,.pane-node-title a{color:#b00;text-decoration:none}.header-links:visited,.pane-node-title a:visited{color:#b00}.header-links:focus,.pane-node-title a:focus{color:#d4df48}.header-links:hover,.pane-node-title a:hover{color:#2d2d2d;text-decoration:none}.header-links:active,.pane-node-title a:active{color:#d65828}.reverse-links,.reverse-links:visited{color:#ebebeb}.reverse-links:focus{color:#d4df48}.reverse-links:hover{color:#fff}.pipe,.reverse-links:active{color:#b00}.more-link,.more-link a{text-transform:uppercase;font-weight:600;text-decoration:none;margin-top:2em}.pipe{font-weight:600}body .ui-accordion .ui-accordion-header,body .ui-accordion .ui-accordion-header a,body .ui-accordion .ui-accordion-header.ui-state-active,body .ui-accordion .ui-accordion-header.ui-state-active a,body .ui-accordion .ui-accordion-header.ui-state-default,body .ui-accordion .ui-accordion-header.ui-state-default a,body .ui-accordion .ui-accordion-header.ui-state-hover,body .ui-accordion .ui-accordion-header.ui-state-hover a,body .ui-tabs .ui-tabs-nav,body .ui-tabs .ui-tabs-nav a{font-weight:400;color:#2d2d2d}.fine-print,table caption{font-size:12px;font-size:1.2rem;line-height:135%}.labels{font-size:13px;font-size:1.3rem;text-transform:uppercase;font-weight:400}.align-right{text-align:right}.align-center{text-align:center}blockquote{background:#f5f5f5;border-left:4px solid #ddd;padding:1.9em 2em;overflow:hidden}blockquote li,blockquote ol,blockquote p,blockquote ul{margin:.4em 0 0}blockquote div,blockquote h2,blockquote h3,blockquote h4,blockquote h5{margin:0 0 .4em}blockquote.pull-quote{font-size:26px;font-size:2.6rem;background:0 0;border-left:0 none;font-family:capita,Georgia,serif;font-style:italic;line-height:130%;padding:0;margin:1.5em 1.5em 1.5em 2em}blockquote.pull-quote :first-child{margin-top:.3em}blockquote.pull-quote::before{font-size:35px;font-size:3.5rem;color:rgba(0,0,0,.6);content:"\f10d";font-family:FontAwesome;font-style:normal;margin-left:-1.5em;float:left}blockquote.pull-quote cite,body .ui-tabs .ui-tabs-nav{font-family:proximanova,Helvetica,Arial,sans-serif}blockquote.pull-quote cite{font-size:16px;font-size:1.6rem;font-style:normal;display:block;padding-top:.6em}blockquote.pull-quote cite::before{content:"―";margin-right:3px}body .ui-accordion{margin:1em 0;position:relative}body .ui-accordion .accordion-item,body .ui-accordion .views-row{margin:.5em 0}body .ui-accordion .ui-accordion-header{font-size:.9em;padding:.5em 1em .4em 1.9em}body .ui-accordion .ui-accordion-header.cke_widget_editable{padding:.5em 3em .3em 1.9em}body .ui-accordion .ui-accordion-header p{margin:0;color:#2d2d2d}body .ui-accordion .ui-accordion-header,body .ui-accordion .ui-accordion-header.ui-state-active,body .ui-accordion .ui-accordion-header.ui-state-default,body .ui-accordion .ui-accordion-header.ui-state-hover{border:0;background-color:#dedede}body .ui-accordion .ui-accordion-header a,body .ui-accordion .ui-accordion-header.ui-state-active a,body .ui-accordion .ui-accordion-header.ui-state-default a,body .ui-accordion .ui-accordion-header.ui-state-hover a{padding:0}body .ui-accordion .ui-accordion-header.ui-state-active{background-image:none}body .ui-accordion .ui-accordion-content{box-sizing:content-box;background-color:#fff;padding:1.2em 1.9em .5em;border:1px solid #dedede}body .ui-tabs{background-color:transparent;margin:1em 0;position:relative;padding:0;clear:both}body .ui-tabs .ui-tabs-nav{font-size:.9em;padding:.5em 1em 0 0;background-color:transparent}.callout,.intro-text,.tagline{font-family:capita,Georgia,serif}body .ui-tabs .ui-tabs-nav.cke_widget_editable{background-color:#dedede;padding:.5em 3em .3em 1.9em}body .ui-tabs .ui-tabs-nav li,body .ui-tabs .ui-tabs-nav li.ui-state-active,body .ui-tabs .ui-tabs-nav li.ui-state-default,body .ui-tabs .ui-tabs-nav li.ui-state-hover{border-width:1px 1px 0;border-style:solid;border-color:#dedede}body .ui-tabs .ui-tabs-nav li.ui-state-default,body .ui-tabs .ui-tabs-nav li.ui-state-hover{background-color:#dedede;background-image:none}body .ui-tabs .ui-tabs-nav li.ui-tabs-active{background-color:#fff}body .ui-tabs .ui-tabs-content{box-sizing:content-box;background-color:#fff;padding:1.2em 1.9em .5em;border:1px solid #dedede}body .ui-tabs .ui-tabs-content:after{content:"";display:table;clear:both}body .drulog-panels-accordion .accordion-title{margin-bottom:.5em}body .drulog-panels-accordion .accordion-content{margin-top:-.8em;margin-bottom:.8em}.tagline,h2.underlined,h3.underlined{margin-bottom:20px}.tagline{font-size:32px;font-size:3.2rem;font-weight:100;line-height:130%}.subhead{font-size:22px;font-size:2.2rem;color:#b00;line-height:130%}.underlined{border-bottom:1px solid #c7c7c7;padding-bottom:4px;font-weight:300!important;margin-top:0}h2.underlined{font-size:30px;font-size:3rem}h3.underlined{font-size:26px;font-size:2.6rem}.field--name-field-ocio-body .underlined{padding-top:20px}.field--name-field-ocio-body .underlined:first-child{padding-top:0}.row-tiles .underlined{margin-bottom:30px!important;padding-top:20px!important}.intro-text{font-size:22px;font-size:2.2rem;font-style:italic;font-weight:100;line-height:160%;padding-bottom:20px}.intro-text:last-child{padding-bottom:0}.intro-text-alt{font-size:20px;font-size:2rem;font-weight:300;line-height:160%;padding-bottom:10px}.intro-text-alt:last-child{padding-bottom:0}.callout{font-size:36px;font-size:3.6rem;color:#b00;font-weight:300;margin:1em 0 .4em}hr{background-color:#d2d2d2;border:0;height:1px;margin:2em 0}.width-70{margin:10px auto}@media (min-width:60em){.width-70{width:75%}}@media (min-width:82em){.width-70{width:70%}}#block-views-featured-slideshow-block .flexslider{background:#2d2d2d;border:0;border-radius:0;box-shadow:none;margin:0}#block-views-featured-slideshow-block .flexslider .flex-meta{display:block;width:100%;position:absolute;color:#fff;text-align:center;bottom:.6em;padding:.4em 8%;font-size:24px;font-size:2.4rem}#block-views-featured-slideshow-block .flexslider .flex-meta .flex-title{display:block;font-weight:400;line-height:1.1em}#block-views-featured-slideshow-block .flexslider .flex-meta .flex-summary{font-weight:300;font-size:.6em;line-height:1.2em;display:none}@media (min-width:47.5em){#block-views-featured-slideshow-block .flexslider .flex-meta .flex-summary{display:block}#block-views-featured-slideshow-block .flexslider .flex-meta{bottom:.3em;padding:.5em 6%;font-size:32px;font-size:3.2rem}#block-views-featured-slideshow-block .flexslider .flex-meta .flex-title{margin-bottom:.1em}}@media (min-width:60em){#block-views-featured-slideshow-block .flexslider .flex-meta{font-size:34px;font-size:3.4rem}}@media (min-width:82em){#block-views-featured-slideshow-block .flexslider .flex-meta{font-size:40px;font-size:4rem}}#block-views-featured-slideshow-block .flexslider .flex-meta.white{color:#fff}#block-views-featured-slideshow-block .flexslider .flex-meta.white.translucent{bottom:0;background-color:rgba(20,20,20,.6)}#block-views-featured-slideshow-block .flexslider .flex-meta.black.translucent,#block-views-featured-slideshow-block .flexslider .flex-meta.dk-gray.translucent{background-color:rgba(200,200,200,.7);bottom:0}#block-views-featured-slideshow-block .flexslider .flex-meta.dk-gray{color:#2d2d2d}#block-views-featured-slideshow-block .flexslider .flex-meta.black{color:#000}#block-views-featured-slideshow-block .flexslider .flex-direction-nav a{color:rgba(0,0,0,.8);text-decoration:none}#block-views-featured-slideshow-block .flexslider .flex-direction-nav a:before{line-height:1em}#block-views-featured-slideshow-block .lt-ie9 .flexslider a .flex-meta{background-color:transparent;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#AA000000, endColorstr=#AA000000)"}#block-views-featured-slideshow-block .lt-ie9 .flexslider .flex-direction-nav a{color:#000;filter:alpha(opacity="60")}#block-views-featured-slideshow-block .lt-ie9 .flexslider .flex-direction-nav a:hover{filter:alpha(opacity="80")}#block-views-featured-slideshow-block ul.flex-direction-nav,#block-views-featured-slideshow-block ul.flex-direction-nav:hover{display:none}#block-views-featured-slideshow-block .flex-control-nav{text-align:right;padding-right:1.8em;top:20px;z-index:99;width:100%;height:30px}#block-views-featured-slideshow-block .flex-control-paging li a{background-color:#2d2d2d;text-align:left;width:15px;height:15px;margin-bottom:1em}#block-views-featured-slideshow-block .flex-control-paging li a.flex-active{background-color:#fff}@media (max-width:47.4em){#block-views-featured-slideshow-block .flex-control-paging li a{display:none}}.l-region--hero-wrapper{position:relative;max-height:500px}.l-region--hero-wrapper .views-field-field-basic-image-image{position:relative;top:0;z-index:9;max-height:500px;overflow:hidden}.page-newsletter-archive h1{margin-bottom:25px}.page-newsletter-archive .l-region--content{padding-bottom:20px}.page-newsletter-archive .l-region--content li{margin-bottom:15px}.block--mm-widgets .item,.pane-mm-widgets-live-pane .item{margin:1.8em 0}.block--mm-widgets .item .content,.pane-mm-widgets-live-pane .item .content{margin-bottom:.3em}.block--mm-widgets .item .network .fa,.pane-mm-widgets-live-pane .item .network .fa{margin-right:.6em;position:relative;top:1px;padding:.3em 0 .25em;width:1.6em}.block--mm-widgets .fa,.pane-mm-widgets-live-pane .fa{color:#fff;padding:.55em 0 .5em;text-align:center;width:1.8em}.block--mm-widgets .fa.fa-twitter,.pane-mm-widgets-live-pane .fa.fa-twitter{background-color:#00aced}.block--mm-widgets .fa.fa-facebook-page,.pane-mm-widgets-live-pane .fa.fa-facebook-page{background-color:#3b5998}.block--mm-widgets .fa.fa-facebook-page:before,.pane-mm-widgets-live-pane .fa.fa-facebook-page:before{content:'\f09a'}.block--mm-widgets .fa.fa-instagram,.pane-mm-widgets-live-pane .fa.fa-instagram{background-color:#517fa4;top:2px}.block--mm-widgets .fa.fa-rss,.pane-mm-widgets-live-pane .fa.fa-rss{background-color:#f60}.block--mm-widgets .fa.fa-youtube-playlist,.pane-mm-widgets-live-pane .fa.fa-youtube-playlist{background-color:#b00}.block--mm-widgets .fa.fa-youtube-playlist:before,.pane-mm-widgets-live-pane .fa.fa-youtube-playlist:before{content:'\f16a'}.block--mm-widgets.mm-single-channel .fa.mm-channel,.pane-mm-widgets-live-pane.mm-single-channel .fa.mm-channel{float:left;margin-right:.6em}.block--mm-widgets.mm-single-channel .fa.mm-channel+.pane-title,.pane-mm-widgets-live-pane.mm-single-channel .fa.mm-channel+.pane-title{line-height:1.6em}body.html.footer-dk-gray{background-color:#2d2d2d}body.html.footer-md-gray{background-color:#666}body.html.footer-lt-gray{background-color:#f5f5f5}body.html.footer-white{background-color:#fff}form.search-form{margin-top:1em}fieldset.search-advanced{border:0;background-color:#ebebeb;margin-left:0;margin-right:0;padding:.5em 0 0}fieldset.search-advanced legend{margin-top:2.5em}fieldset.search-advanced .criterion{margin-top:1em}fieldset.search-advanced input.form-submit{margin-bottom:1em}p.search-result__snippet{padding-left:0;margin-bottom:.4em}.l-page .l-region--main-menu:hover #search-block-toggle{outline:0!important}.l-page .l-region--main-menu #search-block-toggle{cursor:pointer}.l-page .l-region--main-menu #search-block-toggle:focus{outline:red dotted 1px}.l-page .l-region--main-menu #wcm-search{position:relative}.l-page .l-region--main-menu #wcm-search #block-search-form{z-index:498;position:absolute;right:0;top:100%;background-color:rgba(0,0,0,.8);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#333333, endColorstr=#333333);height:auto;display:none}.l-page .l-region--main-menu #wcm-search #block-search-form *{height:100%}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline{display:table;padding:1em}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline .form-item{display:table-cell;vertical-align:middle}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline .form-item .form-text{border:0;padding:0 6px;font-size:1em}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline .form-actions{display:table-cell;text-align:center;width:1.9em}.book_printer,.node-type-news-client-cached-article .tabs--primary,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text span.ext{display:none}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline .form-actions .form-submit{border-radius:0;-webkit-box-sizing:content-box;box-shadow:none;padding:.6em 1.3em .4em;margin:0;height:auto}@media (max-width:47.4em){.l-page .l-region--main-menu #wcm-search #search-block-toggle{position:absolute;right:0;padding:1em;font-size:1.2em;z-index:500;width:auto;margin-top:.25em}.l-page .l-region--main-menu #wcm-search #block-search-form{display:none;height:auto;width:100%;top:4em;z-index:499}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline{width:100%;clear:both;padding:4%}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline .form-text{width:100%}}.field--name-field-ocio-body .block--webform{font-size:14px;font-size:1.4rem;margin-bottom:20px}.field--name-field-ocio-body .block--webform .block__title{font-size:22px;font-size:2.2rem;font-weight:400!important;color:#b00!important;padding-top:20px}.field--name-field-ocio-body .block--webform label{font-size:13px;font-size:1.3rem}.field--name-field-ocio-body .block--webform .button-primary{margin-top:10px}div.workbench-info-block{background-color:#d9d9d9;padding:1em 1.5em;margin:1em 0 3em;border:none;color:#2d2d2d;font-size:14px;font-size:1.4rem;border-left:8px solid #d65828}div.workbench-info-block #edit-submit{margin-left:1em;font-size:13px!important;padding:.4em .8em!important}.ds-2col-stacked-fluid.node--article--full .group-left,.ds-2col-stacked-fluid.node--article--full .group-right,.ds-2col-stacked-fluid.node--news-client-cached-article--full .group-left,.ds-2col-stacked-fluid.node--news-client-cached-article--full .group-right{width:100%;float:none}.ds-2col-stacked-fluid.node--article--full .group-right,.ds-2col-stacked-fluid.node--news-client-cached-article--full .group-right{margin-top:30px;margin-bottom:30px}@media (min-width:60em){.ds-2col-stacked-fluid.node--article--full.has-sidebar .group-left,.ds-2col-stacked-fluid.node--news-client-cached-article--full.has-sidebar .group-left{width:70%;float:left;margin-bottom:30px}.ds-2col-stacked-fluid.node--article--full.has-sidebar .group-right,.ds-2col-stacked-fluid.node--news-client-cached-article--full.has-sidebar .group-right{width:27%;float:right;margin-top:10px}}.node--article,.node--news-client-cached-article{position:relative}.node--article .field--name-field-kicker,.node--news-client-cached-article .field--name-field-kicker{text-transform:uppercase;color:#666;font-weight:600;font-size:22px;font-size:2.2rem;margin-bottom:10px}.node--article .field--name-byline,.node--article .field--name-byline-with-date,.node--news-client-cached-article .field--name-byline,.node--news-client-cached-article .field--name-byline-with-date{font-weight:600;padding-top:6px;margin-bottom:12px}.node--article .field--name-field-featured-image,.node--article .field--name-news-client-image-json,.node--news-client-cached-article .field--name-field-featured-image,.node--news-client-cached-article .field--name-news-client-image-json{float:right;max-width:50%;margin:10px 0 40px 40px}.node--article .field--name-field-sidebar,.node--article .field--name-news-client-sidebar,.node--news-client-cached-article .field--name-field-sidebar,.node--news-client-cached-article .field--name-news-client-sidebar{background:#ebebeb;padding:30px 1.8em 20px}.node--article .field--name-field-sidebar h2,.node--article .field--name-field-sidebar h3,.node--article .field--name-field-sidebar h4,.node--article .field--name-news-client-sidebar h2,.node--article .field--name-news-client-sidebar h3,.node--article .field--name-news-client-sidebar h4,.node--news-client-cached-article .field--name-field-sidebar h2,.node--news-client-cached-article .field--name-field-sidebar h3,.node--news-client-cached-article .field--name-field-sidebar h4,.node--news-client-cached-article .field--name-news-client-sidebar h2,.node--news-client-cached-article .field--name-news-client-sidebar h3,.node--news-client-cached-article .field--name-news-client-sidebar h4{margin-top:20px;margin-bottom:20px}.node--article .field--name-field-sidebar h2:first-child,.node--article .field--name-field-sidebar h3:first-child,.node--article .field--name-field-sidebar h4:first-child,.node--article .field--name-news-client-sidebar h2:first-child,.node--article .field--name-news-client-sidebar h3:first-child,.node--article .field--name-news-client-sidebar h4:first-child,.node--news-client-cached-article .field--name-field-sidebar h2:first-child,.node--news-client-cached-article .field--name-field-sidebar h3:first-child,.node--news-client-cached-article .field--name-field-sidebar h4:first-child,.node--news-client-cached-article .field--name-news-client-sidebar h2:first-child,.node--news-client-cached-article .field--name-news-client-sidebar h3:first-child,.node--news-client-cached-article .field--name-news-client-sidebar h4:first-child{margin-top:0}.node--article .field--name-field-learn-more,.node--article .field--name-news-client-links,.node--news-client-cached-article .field--name-field-learn-more,.node--news-client-cached-article .field--name-news-client-links{background:#ebebeb;padding:1em 1.4em;clear:both}.node--article .field--name-field-learn-more .label-above,.node--article .field--name-news-client-links .label-above,.node--news-client-cached-article .field--name-field-learn-more .label-above,.node--news-client-cached-article .field--name-news-client-links .label-above{font-size:17px;font-size:1.7rem;font-weight:600;text-transform:uppercase;padding-bottom:.2em}.node--article .field--name-field-learn-more ul,.node--article .field--name-news-client-links ul,.node--news-client-cached-article .field--name-field-learn-more ul,.node--news-client-cached-article .field--name-news-client-links ul{padding-left:1.2em}.node--article .field--name-field-learn-more ul li,.node--article .field--name-news-client-links ul li,.node--news-client-cached-article .field--name-field-learn-more ul li,.node--news-client-cached-article .field--name-news-client-links ul li{margin:5px 0}.node--article .field--name-field-learn-more ul li.last,.node--article .field--name-news-client-links ul li.last,.node--news-client-cached-article .field--name-field-learn-more ul li.last,.node--news-client-cached-article .field--name-news-client-links ul li.last{margin-bottom:0}.node--article .field--name-field-tags,.node--article .field--name-news-client-tags,.node--news-client-cached-article .field--name-field-tags,.node--news-client-cached-article .field--name-news-client-tags{padding-top:30px}.node--article .field--name-field-tags .field__label,.node--article .field--name-news-client-tags .field__label,.node--news-client-cached-article .field--name-field-tags .field__label,.node--news-client-cached-article .field--name-news-client-tags .field__label{margin-right:5px}.node--article .article-modified,.node--news-client-cached-article .article-modified{margin-top:1em;font-size:13px;font-style:italic}.node--article .article-modified .label-inline,.node--news-client-cached-article .article-modified .label-inline{font-weight:600}.node-type-basic-page h1{margin-bottom:24px}.node-type-basic-page .field--name-field-ocio-body{margin-bottom:20px}.node--basic-page{padding-bottom:2em}.book-navigation{border-top:1px solid #ebebeb;border-bottom:1px solid #ebebeb;padding:.5em 0;margin:2em 0}.book-navigation__links a{color:#2d2d2d;text-transform:uppercase}.book-navigation__links a:hover,.book-navigation__links a:visited:hover{color:#b00;text-decoration:none}.book-navigation__links a:visited{color:#2d2d2d}.book-navigation__links a .fa{color:#b00}.book-navigation__links>.book-navigation__previous .fa{margin-right:10px}.book-navigation__links>.book-navigation__next .fa{margin-left:10px}.book_add_child a{color:#2d2d2d;text-transform:uppercase;min-width:180px}.book_add_child:before{content:"\f067";font-family:FontAwesome;color:#028da9;float:left;margin-right:5px}.node-type-ocio-landing-page .l-region--content{padding-top:20px}.node-type-ocio-landing-page h1{margin-bottom:0}.node-type-ocio-landing-page .l-region--hero-wrapper{position:relative;max-height:500px;overflow:hidden;line-height:0}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image{position:relative;z-index:9}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text{position:absolute;width:100%;padding:20px 12%;text-align:center;margin:0 auto;left:0;right:0;z-index:99;font-size:26px;font-size:2.6rem;line-height:120%}.panels-ipe .modal-content .change-layout-display .layout-icon .caption,.panels-ipe .modal-content .panels-choose-layout .layout-link>div{line-height:1.4em}@media (min-width:60em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text{font-size:30px;font-size:3rem}}@media (min-width:82em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text{padding:20px 14%;font-size:32px;font-size:3.2rem}}@media (min-width:100em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text{padding:20px 16%}}@media (min-width:112em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text{padding:20px 20%}}@media (min-width:125em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text{padding:20px 28%}}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text a:hover{text-decoration:none}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.white,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.white a{color:#fff}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.white a.translucent,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.white.translucent{background-color:rgba(20,20,20,.6)}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.white a.translucent:hover,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.white.translucent:hover{background-color:rgba(46,46,46,.6);color:#fff}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.dk-gray,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.dk-gray a{color:#2d2d2d}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.dk-gray a.translucent,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.dk-gray.translucent{background-color:rgba(220,220,220,.7)}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.dk-gray a.translucent:hover,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.dk-gray.translucent:hover{background-color:rgba(200,200,200,.7)}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.black,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.black a{color:#000}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.black a.translucent,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.black.translucent{background-color:rgba(220,220,220,.7)}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.black a.translucent:hover,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.black.translucent:hover{background-color:rgba(200,200,200,.7)}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.center-top{top:0}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.center-middle{top:24%}@media (min-width:47.5em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.center-middle{top:30%}}@media (min-width:60em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.center-middle{top:36%}}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.center-bottom{bottom:0;overflow:hidden}.l-region--main-menu.mean-container .mean-bar,.l-region--main-menu.mean-container .mean-nav{background:0 0}.l-region--main-menu.mean-container .mean-bar{z-index:499;padding:0}.l-region--main-menu.mean-container a.meanmenu-reveal{color:#fff;font-size:1.5em;padding:.9em 1em;text-indent:0;text-align:center;left:0!important;right:auto!important}.l-region--main-menu.mean-container .mean-nav{margin-top:4em}.l-region--main-menu.mean-container .mean-nav ul li{text-transform:uppercase}.l-region--main-menu.mean-container .mean-nav ul li li{display:block;float:left;width:100%;margin:0;text-align:left;font-weight:500;box-sizing:border-box;background:rgba(0,0,0,.1);color:rgba(0,0,0,.9)}.l-region--main-menu.mean-container .mean-nav ul li a,.l-region--main-menu.mean-container .mean-nav ul li span{color:#fff;text-decoration:none;padding:1em 1em .9em 1.2em;border:0;box-sizing:border-box;width:100%;display:block}.l-region--main-menu.mean-container .mean-nav ul li li a{padding-left:3em;box-sizing:border-box;width:100%;color:#222;opacity:1}.l-region--main-menu.mean-container .mean-nav ul li a.mean-expand{border:0!important;padding:.7em .9em 1.55em .8em!important;width:auto;margin:0;background-color:transparent}.l-region--main-menu.mean-container .mean-nav ul li a.mean-expand:hover{background:0 0}.l-region--main-menu.mean-container.white{background:#fff;border-bottom:1px solid #e6e6e6}.l-region--main-menu.mean-container.white .mean-nav a,.l-region--main-menu.mean-container.white .mean-nav span,.l-region--main-menu.mean-container.white a.meanmenu-reveal{color:#666}.l-region--main-menu.mean-container.white .mean-bar,.l-region--main-menu.mean-container.white .mean-nav{background:#fff}.l-region--main-menu.mean-container.white .mean-nav ul li li{background:#e6e6e6}.l-region--main-menu.mean-container.white .mean-nav ul li li a,.l-region--main-menu.mean-container.white .mean-nav ul li li span{color:#1a1a1a}.l-region--main-menu.mean-container.lt-gray{background:#ebebeb;border-bottom:1px solid #d2d2d2}.l-region--main-menu.mean-container.lt-gray .mean-nav a,.l-region--main-menu.mean-container.lt-gray .mean-nav span,.l-region--main-menu.mean-container.lt-gray a.meanmenu-reveal{color:#666}.l-region--main-menu.mean-container.lt-gray .mean-bar,.l-region--main-menu.mean-container.lt-gray .mean-nav{background:#ebebeb}.l-region--main-menu.mean-container.lt-gray .mean-nav ul li li{background:#d2d2d2}.l-region--main-menu.mean-container.lt-gray .mean-nav ul li li a,.l-region--main-menu.mean-container.lt-gray .mean-nav ul li li span{color:#1a1a1a}.l-region--main-menu.mean-container.black .mean-nav a,.l-region--main-menu.mean-container.black .mean-nav span,.l-region--main-menu.mean-container.black .mean-nav ul li li a,.l-region--main-menu.mean-container.black .mean-nav ul li li span,.l-region--main-menu.mean-container.black a.meanmenu-reveal,.l-region--main-menu.mean-container.dk-gray .mean-nav a,.l-region--main-menu.mean-container.dk-gray .mean-nav span,.l-region--main-menu.mean-container.dk-gray .mean-nav ul li li a,.l-region--main-menu.mean-container.dk-gray .mean-nav ul li li span,.l-region--main-menu.mean-container.dk-gray a.meanmenu-reveal,.l-region--main-menu.mean-container.md-gray .mean-nav a,.l-region--main-menu.mean-container.md-gray .mean-nav span,.l-region--main-menu.mean-container.md-gray .mean-nav ul li li a,.l-region--main-menu.mean-container.md-gray .mean-nav ul li li span,.l-region--main-menu.mean-container.md-gray a.meanmenu-reveal,.l-region--main-menu.mean-container.red .mean-nav a,.l-region--main-menu.mean-container.red .mean-nav span,.l-region--main-menu.mean-container.red .mean-nav ul li li a,.l-region--main-menu.mean-container.red .mean-nav ul li li span,.l-region--main-menu.mean-container.red a.meanmenu-reveal{color:#fff}.l-region--main-menu.mean-container.md-gray{background:#666;border-bottom:1px solid #4d4d4d}.l-region--main-menu.mean-container.md-gray .mean-bar,.l-region--main-menu.mean-container.md-gray .mean-nav{background:#666}.l-region--main-menu.mean-container.md-gray .mean-nav ul li li{background:#4d4d4d}.l-region--main-menu.mean-container.dk-gray{background:#2d2d2d;border-bottom:1px solid #141414}.l-region--main-menu.mean-container.dk-gray .mean-bar,.l-region--main-menu.mean-container.dk-gray .mean-nav{background:#2d2d2d}.l-region--main-menu.mean-container.dk-gray .mean-nav ul li li{background:#535353}.l-region--main-menu.mean-container.black{background:#000;border-bottom:1px solid #000}.l-region--main-menu.mean-container.black .mean-bar,.l-region--main-menu.mean-container.black .mean-nav{background:#000}.l-region--main-menu.mean-container.black .mean-nav ul li li{background:#262626}.l-region--main-menu.mean-container.red{background:#b00;border-bottom:1px solid #800}.l-region--main-menu.mean-container.red .mean-bar,.l-region--main-menu.mean-container.red .mean-nav{background:#b00}.l-region--main-menu.mean-container.red .mean-nav ul li li{background:#800}.l-page .l-constrained .mean-container #search-block-toggle,.l-page .l-constrained .mean-container .mean-nav ul li a,.l-page .l-constrained .mean-container .mean-nav ul li span,.l-page .l-constrained .mean-container a.meanmenu-reveal{padding-left:4%;padding-right:4%}.l-page .l-constrained .mean-container .mean-nav a.mean-expand{padding-left:4%!important;padding-right:4%!important;margin-right:-2px}.l-page .l-constrained .mean-container .mean-nav ul li li a{padding-left:8%;padding-right:8%}@media (min-width:47.5em){.l-region--main-menu>*{display:table-cell!important}}@media (max-width:47.4em){.l-region--main-menu-wrapper .l-constrained,.l-region--main-menu-wrapper .l-region--main-menu{padding:0}.l-region--main-menu-wrapper .l-region--main-menu>*{display:block}.l-region--main-menu-second-wrapper{display:none}}#superfish-1-toggle span,.l-region--main-menu h2.block__title,.l-region--main-menu span.ext,.l-region--main-menu-second h2.block__title,.l-region--main-menu-second span.ext,.l-region--sidebar-1 h2.block__title,.l-region--sidebar-1 span.ext{display:none}.l-region--main-menu .menu .collapsed,.l-region--main-menu .menu .expanded,.l-region--main-menu .menu .leaf,.l-region--main-menu-second .menu .collapsed,.l-region--main-menu-second .menu .expanded,.l-region--main-menu-second .menu .leaf,.l-region--sidebar-1 .menu .collapsed,.l-region--sidebar-1 .menu .expanded,.l-region--sidebar-1 .menu .leaf{list-style-image:none;list-style-type:none}.l-region--main-menu>*{display:table-cell;vertical-align:middle;width:100%}.l-region--main-menu ul.sf-menu{float:left;clear:left;margin:0}.l-region--main-menu ul.sf-menu li{float:left;margin:0;padding:.75em 1.6em .75em 0;text-transform:uppercase}.l-region--main-menu ul.sf-menu li a,.l-region--main-menu ul.sf-menu li span{font-weight:500;text-decoration:none}.l-region--main-menu ul.sf-menu li a:hover{text-decoration:none}.menu-style-1 .l-region--main-menu-second-wrapper{display:none}.menu-style-1 .l-region--main-menu ul.sf-menu ul{display:none;position:absolute;z-index:99;margin-top:.7em;margin-left:-.9em}.l-region--main-menu-second .main-menu-second-ul,.menu-style-2 .l-region--main-menu ul.sf-menu{margin-left:-1em}.menu-style-1 .l-region--main-menu ul.sf-menu ul li{padding:0}.menu-style-1 .l-region--main-menu ul.sf-menu ul li a{padding:.75em .9em .65em}.menu-style-1 .l-region--main-menu ul li:hover>ul{display:block}.menu-style-1 .l-region--main-menu ul ul.menu li{float:none;position:relative}.menu-style-1 .sf-menu ul:before{content:' ';height:0;position:absolute;width:0;border:10px solid transparent;top:-19px;left:10px;z-index:2}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:after,.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group:after,.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:after,.view-id-user_contact.view-display-id-panel_pane_1 .views-group:after,.view-id-wcm_media_gallery .views-group .views-row:after,.view-id-wcm_media_gallery .views-group:after{content:"";display:table;clear:both}.menu-style-1 .l-region--main-menu,.menu-style-1 .l-region--main-menu-wrapper,.menu-style-1.menu-white .l-region--main-menu,.menu-style-1.menu-white .l-region--main-menu-wrapper{background:#fff}.menu-style-1 .l-region--main-menu-second-wrapper,.menu-style-1 .main-menu-second-ul,.menu-style-1.menu-lt-gray .l-region--main-menu,.menu-style-1.menu-lt-gray .l-region--main-menu-wrapper,.menu-style-1.menu-white .l-region--main-menu-second-wrapper,.menu-style-1.menu-white .main-menu-second-ul{background:#ebebeb}.menu-style-1 #search-block-toggle,.menu-style-1.menu-white #search-block-toggle{color:#666}.menu-style-1 #search-block-toggle:hover,.menu-style-1.menu-white #search-block-toggle:hover{color:#d4df48}.menu-style-1 #search-block-toggle:active,.menu-style-1.menu-white #search-block-toggle:active{color:#028da9}.menu-style-1 #search-block-toggle:focus,.menu-style-1.menu-white #search-block-toggle:focus{color:#d4df48}.menu-style-1 .sf-menu ul:before,.menu-style-1.menu-white .sf-menu ul:before{border-bottom-color:#ebebeb}.menu-style-1 .main-menu-top-li a,.menu-style-1 .main-menu-top-li span,.menu-style-1.menu-white .main-menu-top-li a,.menu-style-1.menu-white .main-menu-top-li span{color:#666!important}.menu-style-1 .main-menu-top-li a:hover,.menu-style-1 .main-menu-top-li span:hover,.menu-style-1.menu-white .main-menu-top-li a:hover,.menu-style-1.menu-white .main-menu-top-li span:hover{color:#b00!important}.menu-style-1 .main-menu-top-li a:active,.menu-style-1 .main-menu-top-li span:active,.menu-style-1.menu-white .main-menu-top-li a:active,.menu-style-1.menu-white .main-menu-top-li span:active{color:#028da9!important}.menu-style-1 .main-menu-top-li a:focus,.menu-style-1 .main-menu-top-li span:focus,.menu-style-1.menu-white .main-menu-top-li a:focus,.menu-style-1.menu-white .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-1 .main-menu-second-ul a,.menu-style-1 .main-menu-second-ul span,.menu-style-1.menu-white .main-menu-second-ul a,.menu-style-1.menu-white .main-menu-second-ul span{color:#666!important}.menu-style-1 .main-menu-second-ul a:hover,.menu-style-1 .main-menu-second-ul span:hover,.menu-style-1.menu-white .main-menu-second-ul a:hover,.menu-style-1.menu-white .main-menu-second-ul span:hover{color:#b00!important}.menu-style-1 .main-menu-second-ul a:active,.menu-style-1 .main-menu-second-ul span:active,.menu-style-1.menu-white .main-menu-second-ul a:active,.menu-style-1.menu-white .main-menu-second-ul span:active{color:#028da9!important}.menu-style-1 .main-menu-second-ul a:focus,.menu-style-1 .main-menu-second-ul span:focus,.menu-style-1.menu-white .main-menu-second-ul a:focus,.menu-style-1.menu-white .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-1 .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1 .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1 .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1 .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover span:hover,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-1 .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1 .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover span:active,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-1 .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1 .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover span:focus,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-1.menu-lt-gray .l-region--main-menu-second-wrapper,.menu-style-1.menu-lt-gray .main-menu-second-ul{background:#d7d7d7}.menu-style-1.menu-lt-gray #search-block-toggle{color:#2d2d2d}.menu-style-1.menu-lt-gray #search-block-toggle:hover{color:#d4df48}.menu-style-1.menu-lt-gray #search-block-toggle:active{color:#028da9}.menu-style-1.menu-lt-gray #search-block-toggle:focus{color:#d4df48}.menu-style-1.menu-lt-gray .sf-menu ul:before{border-bottom-color:#d7d7d7}.menu-style-1.menu-lt-gray .main-menu-top-li a,.menu-style-1.menu-lt-gray .main-menu-top-li span{color:#2d2d2d!important}.menu-style-1.menu-lt-gray .main-menu-top-li a:hover,.menu-style-1.menu-lt-gray .main-menu-top-li span:hover{color:#b00!important}.menu-style-1.menu-lt-gray .main-menu-top-li a:active,.menu-style-1.menu-lt-gray .main-menu-top-li span:active{color:#028da9!important}.menu-style-1.menu-lt-gray .main-menu-top-li a:focus,.menu-style-1.menu-lt-gray .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-1.menu-lt-gray .main-menu-second-ul a,.menu-style-1.menu-lt-gray .main-menu-second-ul span{color:#4d4d4d!important}.menu-style-1.menu-lt-gray .main-menu-second-ul a:hover,.menu-style-1.menu-lt-gray .main-menu-second-ul span:hover{color:#b00!important}.menu-style-1.menu-lt-gray .main-menu-second-ul a:active,.menu-style-1.menu-lt-gray .main-menu-second-ul span:active{color:#028da9!important}.menu-style-1.menu-lt-gray .main-menu-second-ul a:focus,.menu-style-1.menu-lt-gray .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-1.menu-md-gray .l-region--main-menu,.menu-style-1.menu-md-gray .l-region--main-menu-wrapper{background:#666}.menu-style-1.menu-md-gray .l-region--main-menu-second-wrapper,.menu-style-1.menu-md-gray .main-menu-second-ul{background:#4d4d4d}.menu-style-1.menu-md-gray #search-block-toggle{color:#fff}.menu-style-1.menu-md-gray #search-block-toggle:hover{color:#d4df48}.menu-style-1.menu-md-gray #search-block-toggle:active{color:#028da9}.menu-style-1.menu-md-gray #search-block-toggle:focus{color:#d4df48}.menu-style-1.menu-md-gray .sf-menu ul:before{border-bottom-color:#4d4d4d}.menu-style-1.menu-md-gray .main-menu-top-li a,.menu-style-1.menu-md-gray .main-menu-top-li span{color:#fff!important}.menu-style-1.menu-md-gray .main-menu-top-li a:hover,.menu-style-1.menu-md-gray .main-menu-top-li span:hover{color:#d2d2d2!important}.menu-style-1.menu-md-gray .main-menu-top-li a:active,.menu-style-1.menu-md-gray .main-menu-top-li span:active{color:#028da9!important}.menu-style-1.menu-md-gray .main-menu-top-li a:focus,.menu-style-1.menu-md-gray .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-1.menu-md-gray .main-menu-second-ul a,.menu-style-1.menu-md-gray .main-menu-second-ul span{color:#fff!important}.menu-style-1.menu-md-gray .main-menu-second-ul a:hover,.menu-style-1.menu-md-gray .main-menu-second-ul span:hover{color:#d2d2d2!important}.menu-style-1.menu-md-gray .main-menu-second-ul a:active,.menu-style-1.menu-md-gray .main-menu-second-ul span:active{color:#028da9!important}.menu-style-1.menu-md-gray .main-menu-second-ul a:focus,.menu-style-1.menu-md-gray .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#d2d2d2!important}.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-1.menu-dk-gray .l-region--main-menu,.menu-style-1.menu-dk-gray .l-region--main-menu-wrapper{background:#2d2d2d}.menu-style-1.menu-dk-gray .l-region--main-menu-second-wrapper,.menu-style-1.menu-dk-gray .main-menu-second-ul{background:#666}.menu-style-1.menu-dk-gray #search-block-toggle{color:#fff}.menu-style-1.menu-dk-gray #search-block-toggle:hover{color:#d4df48}.menu-style-1.menu-dk-gray #search-block-toggle:active{color:#028da9}.menu-style-1.menu-dk-gray #search-block-toggle:focus{color:#d4df48}.menu-style-1.menu-dk-gray .sf-menu ul:before{border-bottom-color:#666}.menu-style-1.menu-dk-gray .main-menu-top-li a,.menu-style-1.menu-dk-gray .main-menu-top-li span{color:#fff!important}.menu-style-1.menu-dk-gray .main-menu-top-li a:hover,.menu-style-1.menu-dk-gray .main-menu-top-li span:hover{color:#d2d2d2!important}.menu-style-1.menu-dk-gray .main-menu-top-li a:active,.menu-style-1.menu-dk-gray .main-menu-top-li span:active{color:#028da9!important}.menu-style-1.menu-dk-gray .main-menu-top-li a:focus,.menu-style-1.menu-dk-gray .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-1.menu-dk-gray .main-menu-second-ul a,.menu-style-1.menu-dk-gray .main-menu-second-ul span{color:#fff!important}.menu-style-1.menu-dk-gray .main-menu-second-ul a:hover,.menu-style-1.menu-dk-gray .main-menu-second-ul span:hover{color:#d2d2d2!important}.menu-style-1.menu-dk-gray .main-menu-second-ul a:active,.menu-style-1.menu-dk-gray .main-menu-second-ul span:active{color:#028da9!important}.menu-style-1.menu-dk-gray .main-menu-second-ul a:focus,.menu-style-1.menu-dk-gray .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#d2d2d2!important}.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-1.menu-black .l-region--main-menu,.menu-style-1.menu-black .l-region--main-menu-wrapper{background:#000}.menu-style-1.menu-black .l-region--main-menu-second-wrapper,.menu-style-1.menu-black .main-menu-second-ul{background:#3a3a3a}.menu-style-1.menu-black #search-block-toggle{color:#fff}.menu-style-1.menu-black #search-block-toggle:hover{color:#d4df48}.menu-style-1.menu-black #search-block-toggle:active{color:#028da9}.menu-style-1.menu-black #search-block-toggle:focus{color:#d4df48}.menu-style-1.menu-black .sf-menu ul:before{border-bottom-color:#3a3a3a}.menu-style-1.menu-red .sf-menu ul:before,.menu-style-2 .sf-menu ul:before,.menu-style-2.menu-white .sf-menu ul:before{border-bottom-color:#ebebeb}.menu-style-1.menu-black .main-menu-top-li a,.menu-style-1.menu-black .main-menu-top-li span{color:#fff!important}.menu-style-1.menu-black .main-menu-top-li a:hover,.menu-style-1.menu-black .main-menu-top-li span:hover{color:#d2d2d2!important}.menu-style-1.menu-black .main-menu-top-li a:active,.menu-style-1.menu-black .main-menu-top-li span:active{color:#028da9!important}.menu-style-1.menu-black .main-menu-top-li a:focus,.menu-style-1.menu-black .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-1.menu-black .main-menu-second-ul a,.menu-style-1.menu-black .main-menu-second-ul span{color:#fff!important}.menu-style-1.menu-black .main-menu-second-ul a:hover,.menu-style-1.menu-black .main-menu-second-ul span:hover{color:#d2d2d2!important}.menu-style-1.menu-black .main-menu-second-ul a:active,.menu-style-1.menu-black .main-menu-second-ul span:active{color:#028da9!important}.menu-style-1.menu-black .main-menu-second-ul a:focus,.menu-style-1.menu-black .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#d2d2d2!important}.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-1.menu-red .l-region--main-menu,.menu-style-1.menu-red .l-region--main-menu-wrapper{background:#b00}.menu-style-1.menu-red .l-region--main-menu-second-wrapper,.menu-style-1.menu-red .main-menu-second-ul{background:#ebebeb}.menu-style-1.menu-red #search-block-toggle{color:#fff}.menu-style-1.menu-red #search-block-toggle:hover{color:#d2d2d2}.menu-style-1.menu-red #search-block-toggle:active{color:#d4df48}.menu-style-1.menu-red #search-block-toggle:focus{color:#d2d2d2}.menu-style-1.menu-red .main-menu-top-li a,.menu-style-1.menu-red .main-menu-top-li span{color:#fff!important}.menu-style-1.menu-red .main-menu-top-li a:hover,.menu-style-1.menu-red .main-menu-top-li span:hover{color:#d2d2d2!important}.menu-style-1.menu-red .main-menu-top-li a:active,.menu-style-1.menu-red .main-menu-top-li span:active{color:#d4df48!important}.menu-style-1.menu-red .main-menu-top-li a:focus,.menu-style-1.menu-red .main-menu-top-li span:focus{color:#d2d2d2!important}.menu-style-1.menu-red .main-menu-second-ul a,.menu-style-1.menu-red .main-menu-second-ul span{color:#2d2d2d!important}.menu-style-1.menu-red .main-menu-second-ul a:hover,.menu-style-1.menu-red .main-menu-second-ul span:hover{color:#b00!important}.menu-style-1.menu-red .main-menu-second-ul a:active,.menu-style-1.menu-red .main-menu-second-ul span:active{color:#d4df48!important}.menu-style-1.menu-red .main-menu-second-ul a:focus,.menu-style-1.menu-red .main-menu-second-ul span:focus{color:#d2d2d2!important}.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover span:active{color:#d4df48!important}.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d2d2d2!important}.menu-style-2 .l-region--main-menu ul.sf-menu li{padding:.75em 1em}.menu-style-2 .l-region--main-menu ul.sf-menu li.sf-depth-2{display:inline-block;width:auto;padding-top:1em}.l-region--main-menu-second .main-menu-second-ul li{float:left;height:48px;text-transform:uppercase;padding:.75em 1em}.l-region--main-menu-second .main-menu-second-ul li a,.l-region--main-menu-second .main-menu-second-ul li span{font-weight:500;text-decoration:none}.l-region--main-menu-second .main-menu-second-ul li a:hover{text-decoration:none}.menu-style-2 .l-region--main-menu,.menu-style-2 .l-region--main-menu-wrapper,.menu-style-2.menu-white .l-region--main-menu,.menu-style-2.menu-white .l-region--main-menu-wrapper{background:#fff}.menu-style-2 .l-region--main-menu-second-wrapper,.menu-style-2.menu-white .l-region--main-menu-second-wrapper{background:#ebebeb}.menu-style-2 .l-region--main-menu-second-wrapper.menu-hover,.menu-style-2.menu-white .l-region--main-menu-second-wrapper.menu-hover{background:#d9d9d9}.menu-style-2 #search-block-toggle,.menu-style-2.menu-white #search-block-toggle{color:#666}.menu-style-2 #search-block-toggle:hover,.menu-style-2.menu-white #search-block-toggle:hover{color:#d4df48}.menu-style-2 #search-block-toggle:active,.menu-style-2.menu-white #search-block-toggle:active{color:#028da9}.menu-style-2 #search-block-toggle:focus,.menu-style-2.menu-white #search-block-toggle:focus{color:#d4df48}.menu-style-2 .main-menu-top-li a,.menu-style-2 .main-menu-top-li span,.menu-style-2.menu-white .main-menu-top-li a,.menu-style-2.menu-white .main-menu-top-li span{color:#666!important}.menu-style-2 .main-menu-top-li a:hover,.menu-style-2 .main-menu-top-li span:hover,.menu-style-2.menu-white .main-menu-top-li a:hover,.menu-style-2.menu-white .main-menu-top-li span:hover{color:#b00!important}.menu-style-2 .main-menu-top-li a:active,.menu-style-2 .main-menu-top-li span:active,.menu-style-2.menu-white .main-menu-top-li a:active,.menu-style-2.menu-white .main-menu-top-li span:active{color:#028da9!important}.menu-style-2 .main-menu-top-li a:focus,.menu-style-2 .main-menu-top-li span:focus,.menu-style-2.menu-white .main-menu-top-li a:focus,.menu-style-2.menu-white .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-2 .main-menu-top-li.active-trail,.menu-style-2.menu-white .main-menu-top-li.active-trail{background:#ebebeb}.menu-style-2 .main-menu-second-ul,.menu-style-2 .main-menu-top-li:hover,.menu-style-2.menu-white .main-menu-second-ul,.menu-style-2.menu-white .main-menu-top-li:hover{background:#d9d9d9}.menu-style-2 .main-menu-top-li.active-trail a,.menu-style-2 .main-menu-top-li.active-trail a:hover,.menu-style-2 .main-menu-top-li.active-trail span,.menu-style-2 .main-menu-top-li.active-trail span:hover,.menu-style-2.menu-white .main-menu-top-li.active-trail a,.menu-style-2.menu-white .main-menu-top-li.active-trail a:hover,.menu-style-2.menu-white .main-menu-top-li.active-trail span,.menu-style-2.menu-white .main-menu-top-li.active-trail span:hover{color:#b00!important}.menu-style-2 .main-menu-top-li.active-trail a:active,.menu-style-2 .main-menu-top-li.active-trail span:active,.menu-style-2.menu-white .main-menu-top-li.active-trail a:active,.menu-style-2.menu-white .main-menu-top-li.active-trail span:active{color:#028da9!important}.menu-style-2 .main-menu-top-li.active-trail a:focus,.menu-style-2 .main-menu-top-li.active-trail span:focus,.menu-style-2.menu-white .main-menu-top-li.active-trail a:focus,.menu-style-2.menu-white .main-menu-top-li.active-trail span:focus{color:#d4df48!important}.menu-style-2 .main-menu-second-ul a,.menu-style-2 .main-menu-second-ul span,.menu-style-2 .main-menu-top-li:hover a,.menu-style-2 .main-menu-top-li:hover a:hover,.menu-style-2 .main-menu-top-li:hover span,.menu-style-2 .main-menu-top-li:hover span:hover,.menu-style-2.menu-white .main-menu-second-ul a,.menu-style-2.menu-white .main-menu-second-ul span,.menu-style-2.menu-white .main-menu-top-li:hover a,.menu-style-2.menu-white .main-menu-top-li:hover a:hover,.menu-style-2.menu-white .main-menu-top-li:hover span,.menu-style-2.menu-white .main-menu-top-li:hover span:hover{color:#666!important}.menu-style-2 .main-menu-second-ul a:hover,.menu-style-2 .main-menu-second-ul span:hover,.menu-style-2.menu-white .main-menu-second-ul a:hover,.menu-style-2.menu-white .main-menu-second-ul span:hover{color:#b00!important}.menu-style-2 .main-menu-second-ul a:active,.menu-style-2 .main-menu-second-ul span:active,.menu-style-2.menu-white .main-menu-second-ul a:active,.menu-style-2.menu-white .main-menu-second-ul span:active{color:#028da9!important}.menu-style-2 .main-menu-second-ul a:focus,.menu-style-2 .main-menu-second-ul span:focus,.menu-style-2.menu-white .main-menu-second-ul a:focus,.menu-style-2.menu-white .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-2 .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2 .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2 .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2 .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover span:hover,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-2 .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2 .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover span:active,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-2 .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2 .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover span:focus,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-2.menu-lt-gray .l-region--main-menu,.menu-style-2.menu-lt-gray .l-region--main-menu-wrapper{background:#ccc}.menu-style-2.menu-lt-gray .l-region--main-menu-second-wrapper{background:#f0f0f0}.menu-style-2.menu-lt-gray .l-region--main-menu-second-wrapper.menu-hover{background:#e6e6e6}.menu-style-2.menu-lt-gray #search-block-toggle{color:#2d2d2d}.menu-style-2.menu-lt-gray #search-block-toggle:hover{color:#d4df48}.menu-style-2.menu-lt-gray #search-block-toggle:active{color:#028da9}.menu-style-2.menu-lt-gray #search-block-toggle:focus{color:#d4df48}.menu-style-2.menu-lt-gray .sf-menu ul:before{border-bottom-color:#f0f0f0}.menu-style-2.menu-black .sf-menu ul:before,.menu-style-2.menu-dk-gray .sf-menu ul:before,.menu-style-2.menu-md-gray .sf-menu ul:before{border-bottom-color:#ebebeb}.menu-style-2.menu-lt-gray .main-menu-top-li a,.menu-style-2.menu-lt-gray .main-menu-top-li a:hover,.menu-style-2.menu-lt-gray .main-menu-top-li span,.menu-style-2.menu-lt-gray .main-menu-top-li span:hover{color:#2d2d2d!important}.menu-style-2.menu-lt-gray .main-menu-top-li a:active,.menu-style-2.menu-lt-gray .main-menu-top-li span:active{color:#028da9!important}.menu-style-2.menu-lt-gray .main-menu-top-li a:focus,.menu-style-2.menu-lt-gray .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail{background:#f0f0f0}.menu-style-2.menu-lt-gray .main-menu-second-ul,.menu-style-2.menu-lt-gray .main-menu-top-li:hover{background:#e6e6e6}.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail a,.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail span{color:#2d2d2d!important}.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail a:hover,.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail span:hover{color:#b00!important}.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail a:active,.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail span:active{color:#028da9!important}.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail a:focus,.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail span:focus{color:#d4df48!important}.menu-style-2.menu-lt-gray .main-menu-second-ul a,.menu-style-2.menu-lt-gray .main-menu-second-ul span,.menu-style-2.menu-lt-gray .main-menu-top-li:hover a,.menu-style-2.menu-lt-gray .main-menu-top-li:hover a:hover,.menu-style-2.menu-lt-gray .main-menu-top-li:hover span,.menu-style-2.menu-lt-gray .main-menu-top-li:hover span:hover{color:#4d4d4d!important}.menu-style-2.menu-lt-gray .main-menu-second-ul a:hover,.menu-style-2.menu-lt-gray .main-menu-second-ul span:hover{color:#b00!important}.menu-style-2.menu-lt-gray .main-menu-second-ul a:active,.menu-style-2.menu-lt-gray .main-menu-second-ul span:active{color:#028da9!important}.menu-style-2.menu-lt-gray .main-menu-second-ul a:focus,.menu-style-2.menu-lt-gray .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-2.menu-md-gray .l-region--main-menu,.menu-style-2.menu-md-gray .l-region--main-menu-wrapper{background:#666}.menu-style-2.menu-md-gray .l-region--main-menu-second-wrapper{background:#ebebeb}.menu-style-2.menu-md-gray .l-region--main-menu-second-wrapper.menu-hover{background:#dedede}.menu-style-2.menu-md-gray #search-block-toggle{color:#fff}.menu-style-2.menu-md-gray #search-block-toggle:hover{color:#d4df48}.menu-style-2.menu-md-gray #search-block-toggle:active{color:#028da9}.menu-style-2.menu-md-gray #search-block-toggle:focus{color:#d4df48}.menu-style-2.menu-md-gray .main-menu-top-li a,.menu-style-2.menu-md-gray .main-menu-top-li span{color:#fff!important}.menu-style-2.menu-md-gray .main-menu-top-li a:hover,.menu-style-2.menu-md-gray .main-menu-top-li span:hover{color:#4d4d4d!important}.menu-style-2.menu-md-gray .main-menu-top-li a:active,.menu-style-2.menu-md-gray .main-menu-top-li span:active{color:#028da9!important}.menu-style-2.menu-md-gray .main-menu-top-li a:focus,.menu-style-2.menu-md-gray .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-2.menu-md-gray .main-menu-top-li.active-trail{background:#ebebeb}.menu-style-2.menu-md-gray .main-menu-second-ul,.menu-style-2.menu-md-gray .main-menu-top-li:hover{background:#dedede}.menu-style-2.menu-md-gray .main-menu-top-li.active-trail a,.menu-style-2.menu-md-gray .main-menu-top-li.active-trail span{color:#4d4d4d!important}.menu-style-2.menu-md-gray .main-menu-top-li.active-trail a:hover,.menu-style-2.menu-md-gray .main-menu-top-li.active-trail span:hover{color:#b00!important}.menu-style-2.menu-md-gray .main-menu-top-li.active-trail a:active,.menu-style-2.menu-md-gray .main-menu-top-li.active-trail span:active{color:#028da9!important}.menu-style-2.menu-md-gray .main-menu-top-li.active-trail a:focus,.menu-style-2.menu-md-gray .main-menu-top-li.active-trail span:focus{color:#d4df48!important}.menu-style-2.menu-md-gray .main-menu-second-ul a,.menu-style-2.menu-md-gray .main-menu-second-ul span,.menu-style-2.menu-md-gray .main-menu-top-li:hover a,.menu-style-2.menu-md-gray .main-menu-top-li:hover a:hover,.menu-style-2.menu-md-gray .main-menu-top-li:hover span,.menu-style-2.menu-md-gray .main-menu-top-li:hover span:hover{color:#4d4d4d!important}.menu-style-2.menu-md-gray .main-menu-second-ul a:hover,.menu-style-2.menu-md-gray .main-menu-second-ul span:hover{color:#b00!important}.menu-style-2.menu-md-gray .main-menu-second-ul a:active,.menu-style-2.menu-md-gray .main-menu-second-ul span:active{color:#028da9!important}.menu-style-2.menu-md-gray .main-menu-second-ul a:focus,.menu-style-2.menu-md-gray .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-2.menu-dk-gray .l-region--main-menu,.menu-style-2.menu-dk-gray .l-region--main-menu-wrapper{background:#2d2d2d}.menu-style-2.menu-dk-gray .l-region--main-menu-second-wrapper{background:#ebebeb}.menu-style-2.menu-dk-gray .l-region--main-menu-second-wrapper.menu-hover{background:#d2d2d2}.menu-style-2.menu-dk-gray #search-block-toggle{color:#fff}.menu-style-2.menu-dk-gray #search-block-toggle:hover{color:#d4df48}.menu-style-2.menu-dk-gray #search-block-toggle:active{color:#028da9}.menu-style-2.menu-dk-gray #search-block-toggle:focus{color:#d4df48}.menu-style-2.menu-dk-gray .main-menu-top-li a,.menu-style-2.menu-dk-gray .main-menu-top-li span{color:#fff!important}.menu-style-2.menu-dk-gray .main-menu-top-li a:hover,.menu-style-2.menu-dk-gray .main-menu-top-li span:hover{color:#2d2d2d!important}.menu-style-2.menu-dk-gray .main-menu-top-li a:active,.menu-style-2.menu-dk-gray .main-menu-top-li span:active{color:#028da9!important}.menu-style-2.menu-dk-gray .main-menu-top-li a:focus,.menu-style-2.menu-dk-gray .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail{background:#ebebeb}.menu-style-2.menu-dk-gray .main-menu-second-ul,.menu-style-2.menu-dk-gray .main-menu-top-li:hover{background:#d2d2d2}.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail a,.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail span{color:#2d2d2d!important}.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail a:hover,.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail span:hover{color:#b00!important}.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail a:active,.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail span:active{color:#028da9!important}.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail a:focus,.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail span:focus{color:#d4df48!important}.menu-style-2.menu-dk-gray .main-menu-second-ul a,.menu-style-2.menu-dk-gray .main-menu-second-ul span,.menu-style-2.menu-dk-gray .main-menu-top-li:hover a,.menu-style-2.menu-dk-gray .main-menu-top-li:hover a:hover,.menu-style-2.menu-dk-gray .main-menu-top-li:hover span,.menu-style-2.menu-dk-gray .main-menu-top-li:hover span:hover{color:#2d2d2d!important}.menu-style-2.menu-dk-gray .main-menu-second-ul a:hover,.menu-style-2.menu-dk-gray .main-menu-second-ul span:hover{color:#b00!important}.menu-style-2.menu-dk-gray .main-menu-second-ul a:active,.menu-style-2.menu-dk-gray .main-menu-second-ul span:active{color:#028da9!important}.menu-style-2.menu-dk-gray .main-menu-second-ul a:focus,.menu-style-2.menu-dk-gray .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-2.menu-black .l-region--main-menu,.menu-style-2.menu-black .l-region--main-menu-wrapper{background:#000}.menu-style-2.menu-black .l-region--main-menu-second-wrapper{background:#ebebeb}.menu-style-2.menu-black .l-region--main-menu-second-wrapper.menu-hover{background:#d2d2d2}.menu-style-2.menu-black #search-block-toggle{color:#fff}.menu-style-2.menu-black #search-block-toggle:hover{color:#d4df48}.menu-style-2.menu-black #search-block-toggle:active{color:#028da9}.menu-style-2.menu-black #search-block-toggle:focus{color:#d4df48}.menu-style-2.menu-black .main-menu-top-li a,.menu-style-2.menu-black .main-menu-top-li span{color:#fff!important}.menu-style-2.menu-black .main-menu-top-li a:hover,.menu-style-2.menu-black .main-menu-top-li span:hover{color:#2d2d2d!important}.menu-style-2.menu-black .main-menu-top-li a:active,.menu-style-2.menu-black .main-menu-top-li span:active{color:#028da9!important}.menu-style-2.menu-black .main-menu-top-li a:focus,.menu-style-2.menu-black .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-2.menu-black .main-menu-top-li.active-trail{background:#ebebeb}.menu-style-2.menu-black .main-menu-second-ul,.menu-style-2.menu-black .main-menu-top-li:hover{background:#d2d2d2}.menu-style-2.menu-black .main-menu-top-li.active-trail a,.menu-style-2.menu-black .main-menu-top-li.active-trail span{color:#2d2d2d!important}.menu-style-2.menu-black .main-menu-top-li.active-trail a:hover,.menu-style-2.menu-black .main-menu-top-li.active-trail span:hover{color:#b00!important}.menu-style-2.menu-black .main-menu-top-li.active-trail a:active,.menu-style-2.menu-black .main-menu-top-li.active-trail span:active{color:#028da9!important}.menu-style-2.menu-black .main-menu-top-li.active-trail a:focus,.menu-style-2.menu-black .main-menu-top-li.active-trail span:focus{color:#d4df48!important}.menu-style-2.menu-black .main-menu-second-ul a,.menu-style-2.menu-black .main-menu-second-ul span,.menu-style-2.menu-black .main-menu-top-li:hover a,.menu-style-2.menu-black .main-menu-top-li:hover a:hover,.menu-style-2.menu-black .main-menu-top-li:hover span,.menu-style-2.menu-black .main-menu-top-li:hover span:hover{color:#2d2d2d!important}.menu-style-2.menu-black .main-menu-second-ul a:hover,.menu-style-2.menu-black .main-menu-second-ul span:hover{color:#b00!important}.menu-style-2.menu-black .main-menu-second-ul a:active,.menu-style-2.menu-black .main-menu-second-ul span:active{color:#028da9!important}.menu-style-2.menu-black .main-menu-second-ul a:focus,.menu-style-2.menu-black .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-2.menu-red .l-region--main-menu,.menu-style-2.menu-red .l-region--main-menu-wrapper{background:#b00}.menu-style-2.menu-red .l-region--main-menu-second-wrapper{background:#eee}.menu-style-2.menu-red .l-region--main-menu-second-wrapper.menu-hover{background:#dcdcdc}.menu-style-2.menu-red #search-block-toggle{color:#fff}.menu-style-2.menu-red #search-block-toggle:hover{color:#d2d2d2}.menu-style-2.menu-red #search-block-toggle:active{color:#028da9}.menu-style-2.menu-red #search-block-toggle:focus{color:#d2d2d2}.menu-style-2.menu-red .sf-menu ul:before{border-bottom-color:#eee}.menu-style-2.menu-red .main-menu-top-li a,.menu-style-2.menu-red .main-menu-top-li span{color:#fff!important}.menu-style-2.menu-red .main-menu-top-li a:hover,.menu-style-2.menu-red .main-menu-top-li span:hover{color:#2d2d2d!important}.menu-style-2.menu-red .main-menu-top-li a:active,.menu-style-2.menu-red .main-menu-top-li span:active{color:#028da9!important}.menu-style-2.menu-red .main-menu-top-li a:focus,.menu-style-2.menu-red .main-menu-top-li span:focus{color:#d2d2d2!important}.menu-style-2.menu-red .main-menu-top-li.active-trail{background:#eee}.menu-style-2.menu-red .main-menu-second-ul,.menu-style-2.menu-red .main-menu-top-li:hover{background:#dcdcdc}.menu-style-2.menu-red .main-menu-top-li.active-trail a,.menu-style-2.menu-red .main-menu-top-li.active-trail span{color:#2d2d2d!important}.menu-style-2.menu-red .main-menu-top-li.active-trail a:hover,.menu-style-2.menu-red .main-menu-top-li.active-trail span:hover{color:#b00!important}.menu-style-2.menu-red .main-menu-top-li.active-trail a:active,.menu-style-2.menu-red .main-menu-top-li.active-trail span:active{color:#028da9!important}.menu-style-2.menu-red .main-menu-top-li.active-trail a:focus,.menu-style-2.menu-red .main-menu-top-li.active-trail span:focus{color:#d2d2d2!important}.menu-style-2.menu-red .main-menu-second-ul a,.menu-style-2.menu-red .main-menu-second-ul span,.menu-style-2.menu-red .main-menu-top-li:hover a,.menu-style-2.menu-red .main-menu-top-li:hover a:hover,.menu-style-2.menu-red .main-menu-top-li:hover span,.menu-style-2.menu-red .main-menu-top-li:hover span:hover{color:#2d2d2d!important}.panels-ipe .modal-content .panels-choose-layout .layout-link.current-layout,.sidebar-panel{background-color:#f5f5f5}.menu-style-2.menu-red .main-menu-second-ul a:hover,.menu-style-2.menu-red .main-menu-second-ul span:hover{color:#b00!important}.menu-style-2.menu-red .main-menu-second-ul a:active,.menu-style-2.menu-red .main-menu-second-ul span:active{color:#028da9!important}.menu-style-2.menu-red .main-menu-second-ul a:focus,.menu-style-2.menu-red .main-menu-second-ul span:focus{color:#d2d2d2!important}.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d2d2d2!important}.panels-ipe-editing .panels-row.empty{display:block}.panels-ipe .modal-content .panels-choose-layout .layout-link{text-align:center;height:190px}.panels-ipe .modal-content .panels-choose-layout .layout-link img{margin-top:.8em}.panels-ipe .modal-content .panels-choose-layout .layout-link .ajax-progress-throbber{display:block;text-align:center;margin:0 auto}.panels-ipe .modal-content .change-layout-display{display:table;margin:2em auto;text-align:center}.panels-ipe .modal-content .change-layout-display .layout-icon{text-align:center}.panels-ipe .modal-content .change-layout-display>img{padding:5em 2em}.panels-ipe .modal-content #panels-dnd-main div.panel-region h2.label{margin:.5em 0}.panels-ipe-editing .panels-ipe-portlet-content{overflow:visible}.panels-ipe-sort-container>.panels-ipe-portlet-wrapper:first-child .panel-pane{margin-top:20px}.panels-ipe-sort-container>.panels-ipe-portlet-wrapper:last-child .panel-pane{margin-bottom:0}.panel-pane{margin-bottom:40px!important}.panel-pane:last-child{margin-bottom:0!important}.panel-pane.pane-bundle-tile-pane,.panel-pane.pane-bundle-tile-pane-plus-text-area{margin-bottom:30px!important}.panels-ipe-region .panels-ipe-portlet-wrapper .panel-pane{margin-bottom:40px!important}.panels-ipe-region .panels-ipe-portlet-wrapper .panel-pane.pane-bundle-tile-pane,.panels-ipe-region .panels-ipe-portlet-wrapper .panel-pane.pane-bundle-tile-pane-plus-text-area{margin-bottom:20px!important}.panel-pane.title-only{margin-bottom:0!important}.panel-pane.title-only h2.underlined{margin-bottom:10px}.panels-ipe-region .panels-ipe-portlet-wrapper .panel-pane.title-only{margin-bottom:0!important}.panels-ipe-processed .panel-pane{margin-top:0!important}div.pane-bundle-video .media-vimeo-video,div.pane-bundle-video .media-youtube-video{height:auto;padding:0}.sidebar-panel{padding:1em}.sidebar-panel .panel-pane{margin-top:0;margin-bottom:0}.sidebar-panel>.panel-pane:first-child,.sidebar-panel>.panels-ipe-portlet-wrapper:first-child .panel-pane{margin-top:0}.panels-row.active{padding:15px 0}.panels-row.empty{padding:0;display:none}.panels-row.even,.panels-row.odd{padding:30px 0}.panels-row.first{padding-top:7.5px}.panels-row.last{padding-bottom:30px}.node-type-ocio-landing-page .l-main.lt-gray,.node-type-ocio-landing-page .l-main.lt-gray .panels-row.even{background:#f5f5f5}.node-type-ocio-landing-page .l-main.lt-gray .panels-row.odd,.node-type-ocio-landing-page .l-main.white,.node-type-ocio-landing-page .l-main.white .panels-row.even{background:#fff}.node-type-ocio-landing-page .l-main.white .panels-row.odd{background:#f5f5f5}.panel-pane.pane-bundle-tile-pane,.panel-pane.pane-bundle-tile-pane-plus-text-area{box-shadow:0 1px 1px 0 rgba(0,0,0,.22);padding:0;z-index:9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane{background:#fff;width:100%;z-index:99}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.tile-pane-linked:hover,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.tile-pane-linked:hover{opacity:.85}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane>a,.panel-pane.pane-bundle-tile-pane .ui-accordion-content .fieldable-panels-pane>a,.panel-pane.pane-bundle-tile-pane .ui-tabs-content .fieldable-panels-pane>a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane>a,.panel-pane.pane-bundle-tile-pane-plus-text-area .ui-accordion-content .fieldable-panels-pane>a,.panel-pane.pane-bundle-tile-pane-plus-text-area .ui-tabs-content .fieldable-panels-pane>a{text-decoration:none;height:100%;display:block}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .field--name-field-tile-background-img img,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .field--name-field-tile-background-img img{display:block;width:100%}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane blockquote.pull-quote li,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane blockquote.pull-quote p,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane blockquote.pull-quote li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane blockquote.pull-quote p{font-size:20px;font-size:2rem}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane a,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane a:visited{color:#b00}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane a:hover{color:#666}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.lt-gray{background:#ebebeb}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.lt-gray a,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.lt-gray a:visited{color:#2d2d2d}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.lt-gray a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.lt-gray a:hover{color:#b00}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.lt-gray a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.md-gray{background:#666;color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.md-gray a,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.md-gray a:visited{color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.md-gray a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.md-gray a:hover{color:#ebebeb}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.md-gray a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.dk-gray{background:#2d2d2d;color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.dk-gray a,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.dk-gray a:visited{color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.dk-gray a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.dk-gray a:hover{color:#ebebeb}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.dk-gray a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.black{background:#000;color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.black a,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.black a:visited{color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.black a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.black a:hover{color:#ebebeb}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.black a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.red{background:#b60000;color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.red a,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.red a:visited{color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.red a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.red a:hover{color:#ebebeb}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.red a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .title-box{padding:.8em 1em;display:table;width:100%}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .title-box .title-text{display:table-cell;vertical-align:middle;width:100%;text-align:center;padding:0 1em}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .title-box .title-text h2{font-size:18px;font-size:1.8rem;font-family:proximanova,Helvetica,Arial,sans-serif!important;line-height:110%;font-weight:300;margin:1px 0 0;padding:0}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .title-box .title-icon{display:table-cell;vertical-align:middle;font-size:24px;font-size:2.4rem}@media (max-width:47.4em){.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .text-areas h2,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .title-box .title-text h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .text-areas h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .title-box .title-text h2{font-size:24px;font-size:2.4rem}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .text-areas .title-icon,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .title-box .title-text .title-icon,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .text-areas .title-icon,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .title-box .title-text .title-icon{font-size:30px;font-size:3rem}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .field--name-field-tile-text-area li,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .field--name-field-tile-text-area p,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .field--name-field-tile-text-area li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .field--name-field-tile-text-area p{font-size:20px;font-size:2rem}}.panel-pane.pane-bundle-tile-pane-plus-text-area{text-align:center;color:#2d2d2d}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a:visited{color:#b00}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a:hover{color:#666}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane h2{color:#b00;font-size:20px;font-size:2rem;font-weight:400;margin-top:0;text-decoration:none}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.lt-gray{background:#ebebeb}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.lt-gray a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.lt-gray a:visited{color:#2d2d2d}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.lt-gray a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.lt-gray a:hover{color:#b00}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.lt-gray a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray{background:#666}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray{background:#2d2d2d}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black{background:#000}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red{background:#b60000}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black a:visited,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black p,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray a:visited,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray p,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray a:visited,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray p,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red a:visited,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red p{color:#fff}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black a:focus,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray a:focus,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray a:focus,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black a:hover,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray a:hover,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray a:hover,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red a:hover{color:#ebebeb}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black a:active,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray a:active,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray a:active,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .text-areas{padding:1.6em .4em .6em}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane p{font-size:16px;font-size:1.6rem;font-weight:300;line-height:140%}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane ol,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane p,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane ul{margin:1em 0 0}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane li{text-align:left;margin-left:-2em}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane li.align-center{margin-left:-3em;text-align:center}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane li.align-right{text-align:right}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a p{color:#2d2d2d}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a h2:visited{color:#b00}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a h2:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a h2:hover{color:#b00}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a h2:active{color:#2d2d2d}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon{display:block;padding:1.4em 1.4em 1em}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon .field--name-field-tile-background-img{display:table-cell;vertical-align:middle;width:25%}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon .field--name-field-tile-background-img img{width:100%}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon .field--name-field-tile-background-img+h2{display:table-cell;padding-left:.8em;vertical-align:middle;width:75%;text-align:left}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon .field--name-field-tile-background-img+h2+.text-areas{display:inline-block;width:100%;background:inherit}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon .text-areas{padding:0}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon-center{display:block;padding:2em 1em 1em}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon-center .field--name-field-tile-background-img{width:50%;max-width:110px;margin:0 auto}@media (min-width:47.5em){.tile-5 .panel-pane.pane-bundle-tile-pane-plus-text-area h2{font-size:19px;font-size:1.9rem}.tile-5 .panel-pane.pane-bundle-tile-pane-plus-text-area .field--name-field-tile-text-area li,.tile-5 .panel-pane.pane-bundle-tile-pane-plus-text-area .field--name-field-tile-text-area p{font-size:15px;font-size:1.5rem;line-height:130%}.tile-5 .panel-pane.pane-bundle-tile-pane-plus-text-area .text-areas{padding:1.2em .2em .6em}}#edit-field-tile-background-img .description{font-size:120%;line-height:130%;margin-top:10px}.l-content{min-height:4em}.l-footer-wrapper .l-region{margin-bottom:20px;text-align:left}.l-footer-wrapper .l-region--footer-1 p,.l-footer-wrapper .l-region--footer-3 p{font-size:13px;font-size:1.3rem;line-height:135%;margin:0}.l-footer-wrapper .l-region--footer-2{text-align:right}.l-footer-wrapper .l-region--footer-3{clear:both}.l-footer-wrapper a{font-weight:400}.l-footer-wrapper #osu-wordmark{margin-bottom:10px}.l-footer-wrapper #osu-wordmark img{max-width:300px}.l-footer-wrapper .osu-siteinfo-name{font-weight:600}.l-footer-wrapper .osu-siteinfo-address{float:left;font-style:normal}.l-footer-wrapper .osu-siteinfo-address .pipe{margin:0 2px;color:#b8b8b8}@media (max-width:47.4em){.l-page .l-footer-wrapper .l-region{text-align:center}.l-page .l-footer-wrapper .l-region p{font-size:17px;font-size:1.7rem}.l-page .l-footer-wrapper .l-region>*{float:none;text-align:center}.l-page .l-footer-wrapper .l-region ul{padding:0}.l-page .l-footer-wrapper .l-region ul li:first-child *{margin-left:0}}.footer-dk-gray .l-footer-wrapper{background:#2d2d2d;color:#fff}.footer-dk-gray .l-footer-wrapper a,.footer-dk-gray .l-footer-wrapper a:visited{color:#fff}.footer-dk-gray .l-footer-wrapper a:focus{color:#d4df48}.footer-dk-gray .l-footer-wrapper a:hover{color:#666}.footer-dk-gray .l-footer-wrapper a:active{color:#b00}.footer-dk-gray .l-footer-wrapper .pipe{color:#b8b8b8}.footer-md-gray .l-footer-wrapper{background:#666;color:#fff}.footer-md-gray .l-footer-wrapper a,.footer-md-gray .l-footer-wrapper a:visited{color:#fff}.footer-md-gray .l-footer-wrapper a:focus{color:#d4df48}.footer-md-gray .l-footer-wrapper a:hover{color:#ebebeb}.footer-md-gray .l-footer-wrapper a:active{color:#b00}.footer-md-gray .l-footer-wrapper .pipe{color:#ebebeb}.footer-md-gray .l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link{color:#666;background-color:#fff}.footer-md-gray .l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link:focus,.footer-md-gray .l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link:hover{color:#fff}.footer-lt-gray .l-footer-wrapper{background:#ebebeb;color:#474747}.footer-lt-gray .l-footer-wrapper a,.footer-lt-gray .l-footer-wrapper a:visited{color:#2d2d2d}.footer-lt-gray .l-footer-wrapper a:focus{color:#d4df48}.footer-lt-gray .l-footer-wrapper .pipe,.footer-lt-gray .l-footer-wrapper a:active,.footer-lt-gray .l-footer-wrapper a:hover{color:#b00}.footer-lt-gray .l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link{background-color:#2d2d2d}.footer-white .l-footer-wrapper{background:#fff;color:#666}.footer-white .l-footer-wrapper a,.footer-white .l-footer-wrapper a:visited{color:#666}.footer-white .l-footer-wrapper a:focus{color:#d4df48}.footer-white .l-footer-wrapper .pipe,.footer-white .l-footer-wrapper a:active,.footer-white .l-footer-wrapper a:hover{color:#b00}.l-footer-wrapper .osu-siteinfo-social{margin-top:0;padding-left:0;text-align:right}.l-footer-wrapper .osu-siteinfo-social li{list-style-type:none;display:inline-block}@media (min-width:47.5em) and (max-width:59em){.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(5):first-child:nth-child(4),.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(5):first-child~:nth-child(4){clear:both}.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(5):first-child:nth-child(n+4),.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(5):first-child~:nth-child(n+4){float:right}}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link{color:#fff;background-color:#666;margin:0 0 1em 1em;width:2.55em;padding:.62em 0 .46em;text-align:center;display:block}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link:hover{background-color:#000}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-facebook:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-facebook:hover{background-color:#3b5998}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-twitter:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-twitter:hover{background-color:#00aced}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-youtube:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-youtube:hover{background-color:#b00}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-googleplus:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-googleplus:hover{background-color:#dd4b39}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-photos:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-photos:hover{background-color:#ff0084}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-instagram:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-instagram:hover{background-color:#517fa4}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-linkedin:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-linkedin:hover{background-color:#007bb6}.l-main.white{background:#fff}.l-main.lt-gray{background:#f5f5f5}.l-main{padding-bottom:30px}.node-type-ocio-landing-page .l-main{padding-bottom:0}.l-region--masthead{padding:20px 0}@media (min-width:47.5em){.l-footer-wrapper .osu-siteinfo-social{float:right}.l-footer-wrapper .osu-siteinfo-social li{float:left}.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(6):first-child:nth-child(4),.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(6):first-child~:nth-child(4),.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(7):first-child:nth-child(5),.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(7):first-child~:nth-child(5){clear:both}.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(7):first-child:nth-child(n+5),.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(7):first-child~:nth-child(n+5){float:right}.l-region--masthead .l-constrained{width:100%;display:table}}#site-name{display:table-cell;vertical-align:middle;font-size:48px;font-size:4.8rem;max-width:500px}#site-name .site-name-prefix{display:block;font-size:.5em;font-weight:300;color:#666}#site-name .site-name-main{color:#2d2d2d;font-weight:600;display:block;line-height:1em}#site-name a{text-decoration:none;display:block}#site-name .site-name-slogan{font-size:.5em;font-weight:400;color:#666;margin-top:20px}#site-name.site-name-2-lines{font-size:44px;font-size:4.4rem}#site-name.site-name-3-lines{font-size:32px;font-size:3.2rem}#site-name.site-name-4-lines{font-size:30px;font-size:3rem}#site-logo{display:table-cell;vertical-align:middle;text-align:right}#site-logo img{height:140px;width:auto;margin-right:-.5em}@media (max-width:47.4em){#site-logo{display:none}}.l-region--masthead.white{background-color:#fff}.l-region--masthead.dk-gray{background-color:#2d2d2d}.l-region--masthead.dk-gray #site-name .site-name-main{color:#fff}.l-region--masthead.dk-gray #site-name .site-name-prefix,.l-region--masthead.dk-gray #site-name .site-name-slogan{color:#ebebeb}.l-region--masthead.md-gray{background-color:#666}.l-region--masthead.md-gray #site-name .site-name-main{color:#fff}.l-region--masthead.md-gray #site-name .site-name-prefix,.l-region--masthead.md-gray #site-name .site-name-slogan{color:#f3f3f3}.l-region--masthead.lt-gray{background-color:#ebebeb}.l-region--osu-navbar{clear:both;margin:0;padding:0;background:url(../images/osu-navbar/lt-gray/bg-navbar_red.png) left bottom repeat-x #eaeaea;overflow:hidden}#osu_navbar *{font-family:proximanova,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:13px;line-height:1.4;font-weight:400}#osu_navbar p{margin:0;padding:0}#osu_navbar .univ_info{float:left;padding:.9em 0 1.1em;margin-left:0}#osu_navbar .univ_links{float:right;clear:none;padding:1em 0 0;margin-top:-2px}#osu_navbar .univ_name a{height:16px;width:90px;display:block;text-indent:-9999px;background:url(../images/osu-navbar/lt-gray/osu_name.png) no-repeat;margin-left:0;overflow:hidden}#osu_navbar div.links{float:left;margin-bottom:10px}#osu_navbar div.links ul{margin:0;padding:0}#osu_navbar div.links ul li{list-style:none;float:left;margin-left:1em}#osu_navbar div.links ul li a{color:#333;text-decoration:none;background-position:0 0}#osu_navbar div.links ul li a:hover{text-decoration:underline}.osu-semantic{position:absolute;left:0;top:-500px;width:1px;height:1px;overflow:hidden}a.osu-semantic:active,a.osu-semantic:focus{position:absolute;left:0;top:0;overflow:visible}a#skip:active,a#skip:focus{position:absolute;top:0;left:25%;width:50%;text-align:center;padding:.5em 0 1.5em;display:block;color:#fff;z-index:999999999999999999;text-decoration:none;background:#666;background:rgba(0,0,0,.8);border:1px dotted #ccc;border-top:none;border-radius:0 0 6px 6px}.view,.views-exposed-form,.views-exposed-widgets .views-exposed-.views-exposed-widgets{position:relative}a#skip:active:hover,a#skip:focus:hover{background:#b00;background:rgba(187,0,0,.8)}.l-region--osu-navbar.dk-gray{background:url(../images/osu-navbar/dk-gray/bg-navbar_red.png) left bottom repeat-x #333}.l-region--osu-navbar.dk-gray #osu_navbar .univ_name a{background-image:url(../images/osu-navbar/dk-gray/osu_name.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a{color:#fff}@media (max-width:47.4em){#osu_navbar div.links ul{margin-top:-2px}#osu_navbar div.links ul li{list-style:none;float:left;margin-left:.5em}#osu_navbar div.links ul li a{height:23px;width:23px;display:block;overflow:hidden;text-indent:-999px}#osu_navbar div.links ul li a:hover{text-decoration:none}.l-region--osu-navbar #osu_navbar div.links ul li a.help,.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.help{background-image:url(../images/osu-navbar/lt-gray/resp-help.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.buckeyelink,.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.buckeyelink{background-image:url(../images/osu-navbar/lt-gray/resp-buckeyelink.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.map,.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.map{background-image:url(../images/osu-navbar/lt-gray/resp-map.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.findpeople,.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.findpeople{background-image:url(../images/osu-navbar/lt-gray/resp-findpeople.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.webmail,.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.webmail{background-image:url(../images/osu-navbar/lt-gray/resp-webmail.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.search,.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.search{background-image:url(../images/osu-navbar/lt-gray/resp-search.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.help{background-image:url(../images/osu-navbar/dk-gray/resp-help.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.buckeyelink{background-image:url(../images/osu-navbar/dk-gray/resp-buckeyelink.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.map{background-image:url(../images/osu-navbar/dk-gray/resp-map.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.findpeople{background-image:url(../images/osu-navbar/dk-gray/resp-findpeople.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.webmail{background-image:url(../images/osu-navbar/dk-gray/resp-webmail.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.search{background-image:url(../images/osu-navbar/dk-gray/resp-search.png)}}@media only screen and (max-width:720px) and (-webkit-min-device-pixel-ratio:2),only screen and (max-width:720px) and (min--moz-device-pixel-ratio:2),only screen and (max-width:720px) and (-o-min-device-pixel-ratio:2 / 1),only screen and (max-width:720px) and (min-device-pixel-ratio:2){.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a{background-size:23px}.l-region--osu-navbar.lt-gray #osu_navbar .univ_name a{background-size:contain}.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.help{background-image:url(../images/osu-navbar/lt-gray/resp-help@2x.png)}.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.buckeyelink{background-image:url(../images/osu-navbar/lt-gray/resp-buckeyelink@2x.png)}.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.map{background-image:url(../images/osu-navbar/lt-gray/resp-map@2x.png)}.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.findpeople{background-image:url(../images/osu-navbar/lt-gray/resp-findpeople@2x.png)}.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.webmail{background-image:url(../images/osu-navbar/lt-gray/resp-webmail@2x.png)}.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.search{background-image:url(../images/osu-navbar/lt-gray/resp-search@2x.png)}.l-region--osu-navbar #osu_navbar div.links ul li .ui-accordion-content a,.l-region--osu-navbar #osu_navbar div.links ul li .ui-tabs-content a,.l-region--osu-navbar #osu_navbar div.links ul li a,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a,.ui-accordion-content .l-region--osu-navbar #osu_navbar div.links ul li a,.ui-tabs-content .l-region--osu-navbar #osu_navbar div.links ul li a{background-size:23px}.l-region--osu-navbar #osu_navbar .univ_name .ui-accordion-content a,.l-region--osu-navbar #osu_navbar .univ_name .ui-tabs-content a,.l-region--osu-navbar #osu_navbar .univ_name a,.l-region--osu-navbar.dk-gray #osu_navbar .univ_name a,.ui-accordion-content .l-region--osu-navbar #osu_navbar .univ_name a,.ui-tabs-content .l-region--osu-navbar #osu_navbar .univ_name a{background-size:contain}.l-region--osu-navbar #osu_navbar div.links ul li a.help,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.help{background-image:url(../images/osu-navbar/dk-gray/resp-help@2x.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.buckeyelink,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.buckeyelink{background-image:url(../images/osu-navbar/dk-gray/resp-buckeyelink@2x.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.map,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.map{background-image:url(../images/osu-navbar/dk-gray/resp-map@2x.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.findpeople,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.findpeople{background-image:url(../images/osu-navbar/dk-gray/resp-findpeople@2x.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.webmail,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.webmail{background-image:url(../images/osu-navbar/dk-gray/resp-webmail@2x.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.search,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.search{background-image:url(../images/osu-navbar/dk-gray/resp-search@2x.png)}}@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min--moz-device-pixel-ratio:2),only screen and (-o-min-device-pixel-ratio:2 / 1),only screen and (min-device-pixel-ratio:2){.l-region--osu-navbar #osu_navbar .univ_name a{background-size:contain}.l-region--osu-navbar.lt-gray #osu_navbar .univ_name a{background-image:url(../images/osu-navbar/lt-gray/osu_name@2x.png)}.l-region--osu-navbar #osu_navbar .univ_name a,.l-region--osu-navbar.dk-gray #osu_navbar .univ_name a{background-image:url(../images/osu-navbar/dk-gray/osu_name@2x.png)}}.l-region--pre-footer-wrapper{line-height:0}.field--name-field-pre-footer-banner-image img{display:block;width:100%;margin:0}.node--article--teaser .field--name-field-featured-image,.section-tags a.feed-icon{display:none}.section-tags h1{font-weight:600}.section-tags .l-region--content{padding-bottom:40px}.section-tags .node-teaser{border-bottom:1px solid #c7c7c7}.page-user-login .l-main{padding-top:20px}.page-user-login h1{margin-bottom:20px}.page-user-login h2{font-family:proximanova,Helvetica,Arial,sans-serif}.page-user-login .login-box{background:#ebebeb;padding:20px 30px;margin-bottom:2em}.page-user-login .login-box h2{margin-top:0;margin-bottom:0;font-size:20px;font-weight:600}.page-user-login .login-box.osu h2{padding-bottom:10px}.page-user-login .login-box.osu a{margin-bottom:10px}.page-user-login .login-box.non-osu .ctools-collapsible-content{padding-top:2em}.page-user-login .login-box.non-osu #edit-actions{margin-top:20px}.user-profile{padding-bottom:20px}.user-profile .field--name-field-job-title{font-size:24px;font-size:2.4rem;font-weight:400;margin-bottom:30px}.user-profile .field--name-field-user-photo{float:right;margin:-40px 0 20px 30px}.user-profile .field--name-email{margin-top:20px}.field--name-field-user-photo img,.views-field-field-user-photo img{border:1px solid #8c8c8c}.view-wcm-news-client.view-display-id-teasers_pane{margin-bottom:10px;padding-bottom:40px;border-bottom:1px solid #c7c7c7}.view-wcm-news-client.view-display-id-teasers_pane .views-row{margin:30px 0;border-bottom:none}.view-wcm-news-client.view-display-id-teasers_pane .views-row.views-row-last{margin-bottom:0}@media (min-width:60em){.view-wcm-news-client.view-display-id-teasers_pane .views-row{width:95%}}.node--news-client-cached-article--teaser h3{font-size:30px;font-size:3rem}.node--news-client-cached-article--teaser .more-link{margin-top:10px;margin-bottom:0}.view-ocio-news-archive .field--name-title{margin-bottom:.6em}.view-ocio-news-archive .field--name-node-link{margin-top:1em}.view-ocio-news-archive .view-header .more-link{border-bottom:1px solid #b00;margin-bottom:1.4em;margin-top:0}.view-ocio-news-archive .view-header .more-link a{margin-top:-2em;font-weight:400;color:#2d2d2d;font-size:13px;float:right}.view-ocio-news-archive .view-header .more-link a:hover{text-decoration:none;color:#028da9}@media (min-width:47.5em){.node--article--teaser .field--name-field-featured-image{display:block;float:right;margin:0 0 40px 2em}}.node--article--teaser .more-link{float:left;margin-top:10px;margin-bottom:10px}.view-display-id-page .views-row,.view-display-id-teasers_pane .views-row{border-bottom:1px solid #c7c7c7;margin-bottom:30px}.view-display-id-page .views-row h2,.view-display-id-teasers_pane .views-row h2{font-size:32px;font-size:3.2rem;line-height:110%}.pane-ocio-news-archive-titles-pane .views-row{margin-bottom:.2em}.pane-ocio-news-archive-trio-image-pane h2.pane-title,.pane-ocio-news-archive-trio-pane h2.pane-title{font-size:28px;font-size:2.8rem;margin-bottom:.2em}.pane-ocio-news-archive-trio-image-pane .views-row,.pane-ocio-news-archive-trio-pane .views-row{margin-bottom:3em}.pane-ocio-news-archive-trio-image-pane .views-field-title h3,.pane-ocio-news-archive-trio-pane .views-field-title h3{font-size:22px;font-size:2.2rem;margin-top:.4em;line-height:120%;margin-bottom:.5em}.pane-ocio-news-archive-trio-image-pane .field--name-post-date,.pane-ocio-news-archive-trio-pane .field--name-post-date{font-weight:400;color:#666;font-size:15px;font-size:1.5rem}.pane-ocio-news-archive-trio-image-pane .views-field-field-ocio-body a,.pane-ocio-news-archive-trio-image-pane .views-field-field-ocio-body:hover,.pane-ocio-news-archive-trio-pane .views-field-field-ocio-body a,.pane-ocio-news-archive-trio-pane .views-field-field-ocio-body:hover{color:#2d2d2d;text-decoration:none}@media (min-width:47.5em){.pane-ocio-news-archive-trio-image-pane .views-row,.pane-ocio-news-archive-trio-pane .views-row{margin-bottom:1em;width:33.3%}.pane-ocio-news-archive-trio-image-pane .views-row:nth-child(3n+1),.pane-ocio-news-archive-trio-pane .views-row:nth-child(3n+1){float:left;padding-right:4%;clear:left}.pane-ocio-news-archive-trio-image-pane .views-row:nth-child(3n+2),.pane-ocio-news-archive-trio-pane .views-row:nth-child(3n+2){float:left;padding-left:2%;padding-right:2%}.pane-ocio-news-archive-trio-image-pane .views-row:nth-child(3n+3),.pane-ocio-news-archive-trio-pane .views-row:nth-child(3n+3){float:right;padding-left:4%}}.section-news .l-region--sidebar-2 h2.block__title{padding-top:20px}.view-display-id-archive_listing_block h3{font-size:18px;font-size:1.8rem;text-transform:uppercase;color:#666;margin-top:1.2em}.view-display-id-archive_listing_block .view-grouping-header{background:#d2d2d2;color:#2d2d2d;border-radius:0;border-color:#d2d2d2;font-weight:600;font-size:16px;font-size:1.6rem;margin-bottom:1px}.view-display-id-archive_listing_block .view-grouping-header:hover{background:#c2c2c2}.view-display-id-archive_listing_block .view-grouping-header:before{top:14px;left:12px}.view-display-id-archive_listing_block .view-grouping-content{margin-bottom:1px}.view-display-id-archive_listing_block .ui-accordion-header{background:#ebebeb!important;padding-left:2em!important;margin-top:1px!important}.view-display-id-archive_listing_block .ui-accordion-header a{font-size:16px;font-size:1.6rem;margin-left:16px}.view-display-id-archive_listing_block .ui-accordion-header.ui-state-hover{background-color:#d2d2d2!important}.view-display-id-archive_listing_block .ui-accordion-header .ui-accordion-header-icon{margin-left:18px}.view-display-id-archive_listing_block .ui-accordion .ui-accordion-content{padding:10px 30px 10px 32px!important;border:1px solid #ebebeb!important;background:#fff!important}.view-display-id-archive_listing_block .views-field-title{font-size:16px;font-size:1.6rem;margin-bottom:12px;line-height:120%}.view-display-id-archive_listing_block .views-field-title a.active{color:#b00;text-decoration:underline}.view-display-id-archive_listing_block .views-row-last .views-field-title{margin-bottom:0}.pane-ocio-news-archive-teasers-pane h2.pane-title{margin-bottom:30px}.l-main.lt-gray .view-display-id-archive_listing_block .view-grouping-header{background:#c2c2c2;border-color:#c2c2c2}.l-main.lt-gray .view-display-id-archive_listing_block .view-grouping-header:hover{background:#b8b8b8}.view-id-leadership_listing .views-field,.view-id-user_contact .views-field{font-size:15px;font-size:1.5rem;margin-bottom:5px;line-height:120%}.view-id-leadership_listing .views-field-realname h2,.view-id-leadership_listing .views-field-realname h3,.view-id-user_contact .views-field-realname h2,.view-id-user_contact .views-field-realname h3{font-size:21px;font-size:2.1rem}.view-id-leadership_listing .views-field-field-user-photo img,.view-id-user_contact .views-field-field-user-photo img{width:100%;height:auto}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group-header,.view-id-user_contact.view-display-id-panel_pane_1 .views-group-header,.view-id-wcm_media_gallery .views-group-header{margin-bottom:.4em;margin-top:1.4em;padding-bottom:.2em;color:#666}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group,.view-id-user_contact.view-display-id-panel_pane_1 .views-group,.view-id-wcm_media_gallery .views-group{clear:both}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row,.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row,.view-id-wcm_media_gallery .views-group .views-row{width:46%;margin-right:8%;float:left;margin-bottom:.75em;margin-top:.75em}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(2n+1),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(2n+1),.view-id-wcm_media_gallery .views-group .views-row:nth-child(2n+1){clear:left}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(2n+2),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(2n+2),.view-id-wcm_media_gallery .views-group .views-row:nth-child(2n+2){margin-right:0}@media (min-width:47.5em){.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row,.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(3n+1),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(3n+2),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(3n+3),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row,.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(3n+1),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(3n+2),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(3n+3),.view-id-wcm_media_gallery .views-group .views-row,.view-id-wcm_media_gallery .views-group .views-row:nth-child(3n+1),.view-id-wcm_media_gallery .views-group .views-row:nth-child(3n+2),.view-id-wcm_media_gallery .views-group .views-row:nth-child(3n+3){width:20.5%;margin-right:6%;margin-bottom:1em;margin-top:1em;float:left;clear:none}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+1),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+1),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+1){clear:both}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+4),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+4),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+4){margin-right:0}}@media (min-width:60em){.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row,.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+1),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+2),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+3),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+4),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row,.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+1),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+2),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+3),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+4),.view-id-wcm_media_gallery .views-group .views-row,.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+1),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+2),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+3),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+4){width:16%;margin-right:5%;float:left;clear:none}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(5n+1),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(5n+1),.view-id-wcm_media_gallery .views-group .views-row:nth-child(5n+1){clear:both}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(5n+5),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(5n+5),.view-id-wcm_media_gallery .views-group .views-row:nth-child(5n+5){margin-right:0}}@media (min-width:82em){.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row,.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+1),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+2),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+3),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+4),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row,.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+1),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+2),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+3),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+4),.view-id-wcm_media_gallery .views-group .views-row,.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+1),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+2),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+3),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+4){margin-top:1.3em;margin-bottom:1.3em}}.pane-user-contact-panel-pane-2 .views-row{margin-top:20px;margin-bottom:30px}.pane-leadership-listing-panel-pane-2 .views-row{border-bottom:1px solid #ccc;padding:1em 0 0}.pane-leadership-listing-panel-pane-2 .views-row:after{content:"";display:table;clear:both}.pane-leadership-listing-panel-pane-2 .views-row.views-row-1{border-top:1px solid #ccc;margin-top:0}.pane-leadership-listing-panel-pane-2 .views-field-field-user-photo{margin-bottom:15px}.pane-leadership-listing-panel-pane-2 .views-field-field-user-photo img{width:100%;border:none}.pane-leadership-listing-panel-pane-2 .views-field-realname{font-size:32px;font-size:3.2rem;margin-top:0;margin-bottom:6px}.pane-leadership-listing-panel-pane-2 .views-field-field-job-title{font-size:20px;font-size:2rem;display:block;margin-bottom:8px}.pane-leadership-listing-panel-pane-2 .views-field-field-bio{margin-top:12px}.pane-leadership-listing-panel-pane-2 .more-link{margin-top:15px;font-size:14px}@media (min-width:47.5em){.pane-leadership-listing-panel-pane-2 .views-row{padding:1.5em 0 1em}.pane-leadership-listing-panel-pane-2 .views-row .views-field-field-user-photo{float:right;width:300px;margin:0 0 1em 2em}}@media (min-width:60em){.pane-leadership-listing-panel-pane-2 .views-row .views-field-field-user-photo{width:360px}}@media (min-width:82em){.pane-leadership-listing-panel-pane-2 .views-row{padding:1.8em 0 1em}.pane-leadership-listing-panel-pane-2 .views-row .text-grouping{width:58.5%}.pane-leadership-listing-panel-pane-2 .views-row .views-field-field-user-photo{width:39%;margin:0}.pane-leadership-listing-panel-pane-2 .views-row-odd .text-grouping{float:right}.pane-leadership-listing-panel-pane-2 .views-row-even .text-grouping,.pane-leadership-listing-panel-pane-2 .views-row-odd .views-field-field-user-photo{float:left}.pane-leadership-listing-panel-pane-2 .views-row-even .views-field-field-user-photo{float:right}}.views-table td.views-field *{margin:0}.views-exposed-widgets .views-exposed-widget .form-submit{margin-top:1.6em!important}.views-exposed-widgets .views-exposed-widget.views-submit-button{padding:0}.views-exposed-widgets .form-actions .description,.views-exposed-widgets .form-item .description{display:none}.view .ajax-progress,.views-exposed-form .ajax-progress{bottom:-1.75em;position:absolute;right:50%} \ No newline at end of file +@charset "UTF-8";.align-left,table caption{text-align:left}.visuallyhidden{position:absolute;overflow:hidden;clip:rect(0 0 0 0);height:1px;width:1px;margin:-1px;padding:0;border:0}.ui-accordion .ui-accordion-header{background:#ebebeb!important}.ui-accordion .ui-accordion-header-active,.ui-accordion .ui-accordion-header:hover{background:#d2d2d2!important}.ui-accordion .ui-accordion-header p{margin:0}.ui-accordion .ui-accordion-content{background:#fff;border:1px solid #d2d2d2}.ui-accordion .ui-accordion-content h2:first-child,.ui-accordion .ui-accordion-content h3:first-child{margin-top:10px}.ui-accordion .ui-accordion-content ol{padding-left:.6em}.l-main.lt-gray .ui-accordion .ui-accordion-header{background:#e1e1e1!important}.l-main.lt-gray .ui-accordion .ui-accordion-header:hover{background:#d7d7d7!important}.l-main.lt-gray .ui-accordion .ui-accordion-header-active{background:#e1e1e1!important}.l-main.lt-gray .ui-accordion .ui-accordion-content{background:#fff;border:1px solid #e1e1e1}.ui-accordion-header{overflow:auto}body .panels-row.odd .ui-accordion .ui-accordion-header{background:#d7d7d7}body .panels-row.odd .ui-accordion .ui-accordion-content{border-color:#d7d7d7}.ctools-collapsible-container .ctools-toggle{background-image:url(../images/jquery-images/ui-icons_222222_256x240.png);background-position:-64px -15px}.ctools-collapsible-container .ctools-toggle-collapsed{background-position:-32px -15px;background-image:url(../images/jquery-images/ui-icons_222222_256x240.png)}.ctools-collapsible-container .ctools-toggle-collapsed:hover,.nested-accordion:before,.view-grouping-header:before{background-image:url(../images/jquery-images/ui-icons_222222_256x240.png)}ul.breadcrumb{padding:20px 0;margin:0}ul.breadcrumb li{display:inline-block;margin-right:.45em;font-weight:600}ul.breadcrumb li:after{content:"|";color:#b00;font-weight:700;margin-left:.45em}ul.breadcrumb li a{color:#666;text-decoration:none}ul.breadcrumb li a:visited{color:#666}ul.breadcrumb li a:focus{color:#dcaa38}ul.breadcrumb li a:hover{color:#666;text-decoration:underline}ul.breadcrumb li a:active{color:#028da9}ul.breadcrumb li:last-child{margin-right:0}ul.breadcrumb li:last-child:after{content:" "}#edit-preview,#edit-submit,#edit-submit--2,#edit-submit--3,.button-primary,.form-submit,.page-user-login .login-box.osu a,.red-button,.webform-previous,.webform-submit,html body .button,input[type=button]{font-size:14px;padding:.7em 1.3em .4em;display:inline-block;cursor:pointer;background-color:#b00;border:0;color:#fff;text-transform:uppercase;font-family:proximanova,Helvetica,Arial,sans-serif;letter-spacing:.05em;border-radius:2px;box-shadow:0 3px 0 0 #920000;font-weight:400;margin-right:1.5em}#edit-preview:hover,#edit-submit--2:hover,#edit-submit--3:hover,#edit-submit:hover,.button-primary:hover,.form-submit:hover,.page-user-login .login-box.osu a:hover,.red-button:hover,.webform-previous:hover,.webform-submit:hover,html body .button:hover,input[type=button]:hover{text-decoration:none;background-color:#a20000}#edit-preview:active,#edit-submit--2:active,#edit-submit--3:active,#edit-submit:active,.button-primary:active,.form-submit:active,.page-user-login .login-box.osu a:active,.red-button:active,.webform-previous:active,.webform-submit:active,html body .button:active,input[type=button]:active{background-color:#920000}.disabled#edit-preview,.disabled#edit-submit,.disabled#edit-submit--2,.disabled#edit-submit--3,.disabled.button-primary,.disabled.form-submit,.disabled.webform-previous,.disabled.webform-submit,.page-user-login .login-box.osu a.disabled,.page-user-login .login-box.osu a[disabled],.red-button.disabled,.red-button[disabled],[disabled]#edit-preview,[disabled]#edit-submit,[disabled]#edit-submit--2,[disabled]#edit-submit--3,[disabled].button-primary,[disabled].form-submit,[disabled].webform-previous,[disabled].webform-submit,html body .disabled.button,html body [disabled].button,input.disabled[type=button],input[disabled][type=button]{opacity:.6;background:false;cursor:default;box-shadow:none}#edit-preview.ext .ext,#edit-submit--2.ext .ext,#edit-submit--3.ext .ext,#edit-submit.ext .ext,.button-primary.ext .ext,.form-submit.ext .ext,.webform-previous.ext .ext,.webform-submit.ext .ext,html body .button.ext .ext,input[type=button].ext .ext{background-image:none;padding:0;width:0}a.button{margin-top:20px}#colorbox #cboxWrapper{border-radius:0;font-size:1.1em}#colorbox #cboxWrapper #cboxClose,#colorbox #cboxWrapper #cboxNext,#colorbox #cboxWrapper #cboxPrevious{background-image:none;text-indent:0;color:transparent;overflow:hidden}#colorbox #cboxWrapper #cboxClose:before,#colorbox #cboxWrapper #cboxNext:before,#colorbox #cboxWrapper #cboxPrevious:before{font-family:FontAwesome;bottom:-3px;position:absolute;color:#000}#colorbox #cboxWrapper #cboxClose:before{content:"\f00d";right:0;font-size:1.2em}#colorbox #cboxWrapper #cboxPrevious:before{content:"\f053"}#colorbox #cboxWrapper #cboxNext:before{content:"\f054"}#colorbox #cboxWrapper #cboxCurrent{bottom:-3px}span.ext{margin-left:2px;margin-right:2px}img.file-icon{height:40px;width:auto;padding-bottom:7px;margin:0 3px}.views-exposed-form,.webform-component .description{margin-bottom:30px}input{max-width:100%}input:focus{outline:#999 solid 1px}textarea{resize:none}.webform-component label{text-transform:uppercase;font-weight:600;font-size:14px}.webform-component table .form-text{width:100%}.views-exposed-form label{font-weight:400;font-size:14px;text-transform:uppercase}.views-exposed-form .form-text{height:32px}.webform-component-fieldset .webform-component label{text-transform:uppercase;font-weight:400;font-size:13px}.webform-component-fieldset,.webform-component-file,.webform-component-grid{margin-bottom:40px}.webform-component-file #edit-submitted-file-upload{max-width:240px}@media (max-width:47.4em){.l-main input:not([type=checkbox]):not([type=radio]),.l-main select,.l-main textarea{width:100%}}form .chosen-container .chosen-choices,form .form-text{padding:4px 6px 2px;border:1px solid #bbb;background-image:none;box-shadow:none;font-size:.9em}form .chosen-container{font-size:1em}form .chosen-container .result-selected{display:none!important}form .chosen-container .chosen-results{font-size:.9em}form .chosen-container .search-field input{width:.1px!important;height:.1px!important}form .chosen-container .chosen-results li{padding:7px 6px 4px;line-height:1em}form .chosen-container .chosen-results li.highlighted{background-image:none}form .chosen-container.chosen-container-active.chosen-with-drop .chosen-single,form .chosen-container.chosen-container-multi .chosen-choices li.search-choice,form .chosen-container.chosen-container-single .chosen-single{border-radius:0;background:#eee;box-shadow:none}form .chosen-container.chosen-container .search-field:after,form .chosen-container.chosen-container-active.chosen-with-drop .chosen-choices li.search-choice+.search-field:after{content:"- Select -";color:#666;cursor:default}form .chosen-container.chosen-container-active .search-field,form .chosen-container.chosen-container-multi .chosen-choices li.search-choice+.search-field{float:none}form .chosen-container.chosen-container-single .chosen-results{margin:0;padding:0}form .chosen-container.chosen-container-single .chosen-drop{border-radius:0}form .chosen-container.chosen-container-single .chosen-single{padding:0 0 0 6px;height:27px}form .chosen-container.chosen-container-single .chosen-single div b{background-size:52px 40px!important}form .chosen-container.chosen-container-multi .chosen-choices{padding:1px 3px 0;cursor:default}form .chosen-container.chosen-container-multi .chosen-choices li.search-choice{display:inline-block;float:none;line-height:1em;margin:2px 4px 2px 0;padding:4px 20px 2px 4px}form .chosen-container.chosen-container-multi .chosen-choices li.search-choice .search-choice-close{top:4px}form .chosen-container.chosen-container-multi .chosen-choices li.search-choice+.search-field:after{content:"+ Add";cursor:pointer}.l-constrained:after,.l-main:after,.l-region--sidebar-1:after,.l-region--sidebar-2:after{content:"";display:table;clear:both}form .chosen-container.chosen-container-multi .chosen-choices li.search-field input[type=text]{margin:1px 0 0 2px;cursor:default}.type-group1 h1,.type-group1 h2,.type-group1 h3,.type-group1 h4,.type-group1 h5,.type-group1 h6,.type-group1-sample h1,.type-group1-sample h2,.type-group1-sample h3,.type-group1-sample h4,.type-group1-sample h5,.type-group1-sample h6{font-family:proximanova,Helvetica,Arial,sans-serif;font-weight:400}.type-group1 h1,.type-group1-sample h1{color:#b00}.type-group1 h2.block__title,.type-group1 h2.pane-title,.type-group1-sample h2.block__title,.type-group1-sample h2.pane-title{margin-bottom:.6em;text-transform:uppercase;color:#2d2d2d;font-weight:400;line-height:120%}.type-group2 h1,.type-group2 h2,.type-group2 h3,.type-group2 h4,.type-group2 h5,.type-group2 h6,.type-group2-sample h1,.type-group2-sample h2,.type-group2-sample h3,.type-group2-sample h4,.type-group2-sample h5,.type-group2-sample h6{font-family:proximanova,Helvetica,Arial,sans-serif;font-weight:300}.type-group2 h1,.type-group2-sample h1{font-weight:600}.type-group2 h2,.type-group2 h3,.type-group2-sample h2,.type-group2-sample h3{font-family:capita,Georgia,serif;font-weight:100}.type-group2 h3,.type-group2-sample h3{font-style:italic}.type-group2 h4,.type-group2-sample h4{font-weight:400}.type-group2 h2.block__title,.type-group2 h2.pane-title,.type-group2-sample h2.block__title,.type-group2-sample h2.pane-title{font-weight:400;font-family:proximanova,Helvetica,Arial,sans-serif}.type-group3 h1,.type-group3 h2,.type-group3 h3,.type-group3 h4,.type-group3 h5,.type-group3 h6,.type-group3-sample h1,.type-group3-sample h2,.type-group3-sample h3,.type-group3-sample h4,.type-group3-sample h5,.type-group3-sample h6{font-family:capita,Georgia,serif;font-weight:400}.type-group3 h2,.type-group3-sample h2{font-weight:100;font-style:italic}.type-group3 h3,.type-group3 h4,.type-group3-sample h3,.type-group3-sample h4{font-family:proximanova,Helvetica,Arial,sans-serif;font-weight:400}.type-group3 h2.block__title,.type-group3 h2.pane-title,.type-group3-sample h2.block__title,.type-group3-sample h2.pane-title{font-weight:400;font-style:normal}.l-page img{width:inherit}.image-border,.panopoly-image-featured,.panopoly-image-full,.panopoly-image-half,.panopoly-image-original,.panopoly-image-quarter,.panopoly-image-square,.panopoly-image-thumbnail{border:1px solid #666}.node__content .panopoly-image-featured,.node__content .panopoly-image-full,.node__content .panopoly-image-half,.node__content .panopoly-image-original,.node__content .panopoly-image-quarter,.node__content .panopoly-image-square,.node__content .panopoly-image-thumbnail{float:right;margin:0 0 20px 1.5em}.ui-widget table,.ui-widget td,.ui-widget th,.ui-widget tr{border:0}.ui-widget{font-family:proximanova,Helvetica,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget button,.ui-widget input,.ui-widget select,.ui-widget textarea{font-family:proximanova,Helvetica,Arial,sans-serif;font-size:1em}.ui-widget-content{border:0;background:#ebebeb;color:#2d2d2d}.ui-widget-content a{color:#2d2d2d}.ui-widget-header{border:0;background:#666;color:#fff;font-weight:700}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:0;background:#fff;font-weight:400;color:#2d2d2d}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#2d2d2d;text-decoration:none}.ui-state-focus,.ui-state-hover,.ui-widget-content .ui-state-focus,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-focus,.ui-widget-header .ui-state-hover{border:0;background:#d2d2d2;font-weight:400;color:#2d2d2d}.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited{color:#fff;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:0;background:url(../images/jquery-images/ui-bg_flat_65_ffffff_40x100.png) 50% 50% repeat-x #fff;font-weight:400;color:#2d2d2d}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#2d2d2d;text-decoration:none}.ui-icon{background-image:url(../images/jquery-images/ui-icons_222222_256x240.png)!important}.ui-corner-all,.ui-corner-left,.ui-corner-tl,.ui-corner-top{border-top-left-radius:0}.ui-corner-all,.ui-corner-right,.ui-corner-top,.ui-corner-tr{border-top-right-radius:0}.ui-corner-all,.ui-corner-bl,.ui-corner-bottom,.ui-corner-left{border-bottom-left-radius:0}.ui-corner-all,.ui-corner-bottom,.ui-corner-br,.ui-corner-right{border-bottom-right-radius:0}#modalBackdrop,.cke_dialog_background_cover,.ui-widget-overlay{background-image:none!important;background-color:#000!important;opacity:.5!important}.ui-dialog .ui-dialog-titlebar{height:auto;line-height:unset;font-weight:700;font-size:13px;color:#474747;text-shadow:0 1px 0 rgba(255,255,255,.75);border-bottom:1px solid #999;padding:6px 10px;border-radius:2px 2px 0 0;box-shadow:0 1px 0 #fff inset;background:#cfd1cf;background-image:linear-gradient(top,#f5f5f5,#cfd1cf);filter:progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#fff5f5f5', endColorstr='#ffcfd1cf')}.messages,.pager>li{background-image:none}.ui-front{z-index:1050}.l-constrained{margin:0 auto;padding:0 6%}@media (min-width:47.5em){.l-constrained{padding:0 8%}}@media (min-width:82em){.max-width{max-width:70em;margin:0 auto;padding:0}}ol ol,ol ol ol,ul ul,ul ul ul{margin-top:8px}ul.menu{padding:0}ol,ul{padding-left:3em}ul{list-style-type:square;list-style-position:outside}ul ul,ul ul ul{margin-left:20px}ol{list-style-type:decimal}ol ol{list-style-type:lower-alpha}ol ol ol{list-style-type:lower-roman}.no-list-style,ul.breadcrumb,ul.menu{list-style:none}.field--name-field-basic-text-text li,.field--name-field-ocio-body li,.ui-accordion-content li{margin-bottom:.6em}.ui-accordion-content ul{padding-left:.6em}.caret-list-type ul,.dot-list-type ul,.page-newsletter-archive .l-region--content ul,.pane-bundle-quick-links ul,.pane-wcm-mailchimp-pane ul{padding-left:0;list-style-image:none;list-style-type:none}.caret-list-type li,.page-newsletter-archive .l-region--content li,.pane-bundle-quick-links li,.pane-wcm-mailchimp-pane li{margin-bottom:10px}.caret-list-type li:before,.page-newsletter-archive .l-region--content li:before,.pane-bundle-quick-links li:before,.pane-wcm-mailchimp-pane li:before{content:"\f0da";font-family:FontAwesome;color:gray;margin-right:10px;margin-left:4px;font-size:85%}.dot-list-type li{margin-bottom:40px}.dot-list-type li:before{content:"\f111";font-family:FontAwesome;color:gray;margin-right:10px;font-size:40%}.media-element{display:block}.media-element img{display:block;width:100%;margin:0}.media-element.file-default,.media-element.file-image-full,.media-element.file-image-large,.media-element.file-image-medium,.media-element.file-image-small{margin:0 0 1em}.media-element.file-image-left{float:left;clear:left;margin:0 2em 1em 0;max-width:30%}.media-element.file-image-right{float:right;clear:right;margin:0 0 1em 2em;max-width:30%}.media-element.file-image-center{float:none;margin:0 auto;max-width:50%}.media-element.file-image-max{margin:0 0 1em;width:100%}.media-element.file-image-max .content{width:100%}.media-element.file-video-full,.media-element.file-video-large,.media-element.file-video-medium,.media-element.file-video-small{margin:0 0 1em}.media-element.file-video-left{float:left;clear:left;margin:0 2em 1em 0;width:50%}.media-element.file-video-right{float:right;clear:right;margin:0 0 1em 2em;width:50%}.media-element.file-video-center{float:none;margin:0 auto;width:75%}.media-element.file-video-max{margin:0 0 1em;width:100%}.media-element.file-video-max .content{width:100%}.media-element-container{display:block;display:table;table-layout:fixed;max-width:100%}.media-element-container img{display:block;width:100%;margin:0}.media-element-container.media-default,.media-element-container.media-image_full,.media-element-container.media-image_large,.media-element-container.media-image_medium,.media-element-container.media-image_small{margin:0 0 1em}.media-element-container.media-image_left{float:left;clear:left;margin:0 2em 1em 0;max-width:30%}.media-element-container.media-image_right{float:right;clear:right;margin:0 0 1em 2em;max-width:30%}.media-element-container.media-image_center{float:none;margin:0 auto;max-width:50%}.media-element-container.media-image_max{margin:0 0 1em;width:100%}.media-element-container.media-image_max .content{width:100%}.media-element-container.media-video_full,.media-element-container.media-video_large,.media-element-container.media-video_medium,.media-element-container.media-video_small{margin:0 0 1em}.media-element-container.media-video_left{float:left;clear:left;margin:0 2em 1em 0;width:50%}.media-element-container.media-video_right{float:right;clear:right;margin:0 0 1em 2em;width:50%}.media-element-container.media-video_center{float:none;margin:0 auto;width:75%}.media-element-container.media-video_max .content,.pane-bundle-table table,table{width:100%}.media-element-container.media-video_max{margin:0 0 1em;width:100%}.media-element-container .field--name-field-basic-image-caption,.media-element-container .field-name-field-basic-image-caption{display:table-caption;caption-side:bottom;font-family:capita,Georgia,serif;font-size:.9em;font-weight:300;font-style:italic;line-height:1.3em;color:#606060}.error,.error .error,.messages--error,.messages--status,.messages--warning,.ok,.warning{color:#2d2d2d}.align-center .media-element.file-default{margin-left:auto;margin-right:auto}.align-right .media-element.file-default{margin-left:auto}img,media{max-width:100%}@media (max-width:47.4em){.field .media-element.media-vimeo-video,.field .media-element.media-youtube-video{width:100%;margin:0;float:none;display:block}.field img.media-element{margin:0 auto;float:none;display:block;max-width:100%}}.messages{margin:1.8em 0;padding:1.2em 1.6em;border:0;background-color:#d9d9d9}.messages ul{margin:0 0 0 1em;padding:0}.messages li{list-style-image:none}.messages--status,tr.ok{border-left:8px solid #d4df48}.messages--warning,tr.warning{border-left:8px solid #dcaa38}.messages--error,tr.error{border-left:8px solid #b00}.pager>li{display:inline;padding:.5em;list-style-type:none}table{margin-bottom:20px;line-height:140%}.ui-accordion-content table a,.ui-tabs-content table a,table .ui-accordion-content a,table .ui-tabs-content a,table a,table li,table p{font-size:15px;font-size:1.5rem;line-height:120%!important}table th{background:#dedede;font-weight:600;border:1px solid #c7c7c7!important;text-transform:uppercase}.ui-accordion-content table td,table tbody,table td,table th{border:1px solid #c7c7c7}.ui-accordion-content table th a,.ui-tabs-content table th a,table th .ui-accordion-content a,table th .ui-tabs-content a,table th a{text-decoration:none}table tbody tr{border-bottom:1px solid #c7c7c7}table tbody tr.odd,table tbody tr:nth-child(odd){background:#f0f0f0}table tbody tr.even,table tbody tr:nth-child(even){background:#fff}table thead+tbody tr.odd,table thead+tbody tr:nth-child(odd){background:#f0f0f0}.panels-row.odd table tbody tr.odd,.panels-row.odd table tbody tr:nth-child(odd),table thead+tbody tr.even,table thead+tbody tr:nth-child(even){background:#fff}table td,table th{padding:.6em 1em}table caption{color:#666;margin-bottom:5px}.panels-row.odd table tbody tr.even,.panels-row.odd table tbody tr:nth-child(even),.panels-row.odd table thead+tbody tr.odd,.panels-row.odd table thead+tbody tr:nth-child(odd){background:#f3f3f3}.panels-row.odd table thead+tbody tr.even,.panels-row.odd table thead+tbody tr:nth-child(even){background:#fff}table ul{padding-left:3px;list-style-position:inside}.tabs--primary{padding-top:2em}.tabs--primary li{font-weight:400;background:#ebebeb}.tabs--primary li a{text-decoration:none;color:#b00}.tabs--primary li a:visited{color:#b00}.tabs--primary li a:focus{color:#dcaa38}.tabs--primary li a:hover{color:#2d2d2d;background:#d2d2d2}.tabs--primary li a:active{color:#028da9}.tabs--primary li .active{background:#c5c5c5}body,html{font-family:proximanova,Helvetica,Arial,sans-serif;color:#2d2d2d;font-weight:300}p{margin-bottom:14px}em{font-style:italic}@media (max-width:47.4em){html{font-size:58%}.body,.ui-accordion .ui-accordion-content li,.ui-accordion .ui-accordion-content p,body{font-size:18px;font-size:1.8rem;line-height:150%}}@media (min-width:47.5em){html{font-size:60%}.body,.ui-accordion .ui-accordion-content li,.ui-accordion .ui-accordion-content p,body{font-size:17px;font-size:1.7rem;line-height:150%}.width-70{width:85%}}@media (min-width:60em){html{font-size:62.5%}.body,.ui-accordion .ui-accordion-content li,.ui-accordion .ui-accordion-content p,body{font-size:17px;font-size:1.7rem;line-height:150%}}@media (min-width:82em){html{font-size:66%}.body,.ui-accordion .ui-accordion-content li,.ui-accordion .ui-accordion-content p,body{font-size:16px;font-size:1.6rem;line-height:150%}}h1,h2,h3,h4{margin-bottom:10px;line-height:120%}.pane-bundle-text h2,body h2,body h3,body h4,h2.block__title{margin-top:0}h1{font-size:42px;font-size:4.2rem}h2{font-size:32px;font-size:3.2rem}h2.block__title,h2.pane-title{font-size:27px;font-size:2.7rem}h3{font-size:24px;font-size:2.4rem}h4{font-size:20px;font-size:2rem}.block-title-style,.section-tags h1,.views-page h1{text-transform:uppercase;color:#2d2d2d;font-size:27px;font-size:2.7rem}.ui-accordion-content a,.ui-tabs-content a,a{color:#b00;font-weight:500;text-decoration:none}a:visited{color:#b00}a:focus{color:#d4df48}a:hover{color:#028da9;text-decoration:underline}a:active{color:#d65828}.ui-accordion-content strong a,.ui-tabs-content strong a,strong .ui-accordion-content a,strong .ui-tabs-content a,strong a{font-weight:700}.header-links,.pane-node-title a{color:#b00;text-decoration:none}.header-links:visited,.pane-node-title a:visited{color:#b00}.header-links:focus,.pane-node-title a:focus{color:#d4df48}.header-links:hover,.pane-node-title a:hover{color:#2d2d2d;text-decoration:none}.header-links:active,.pane-node-title a:active{color:#d65828}.reverse-links,.reverse-links:visited{color:#ebebeb}.reverse-links:focus{color:#d4df48}.reverse-links:hover{color:#fff}.pipe,.reverse-links:active{color:#b00}.more-link,.more-link a{text-transform:uppercase;font-weight:600;text-decoration:none;margin-top:2em}.pipe{font-weight:600}body .ui-accordion .ui-accordion-header,body .ui-accordion .ui-accordion-header a,body .ui-accordion .ui-accordion-header.ui-state-active,body .ui-accordion .ui-accordion-header.ui-state-active a,body .ui-accordion .ui-accordion-header.ui-state-default,body .ui-accordion .ui-accordion-header.ui-state-default a,body .ui-accordion .ui-accordion-header.ui-state-hover,body .ui-accordion .ui-accordion-header.ui-state-hover a,body .ui-tabs .ui-tabs-nav,body .ui-tabs .ui-tabs-nav a{font-weight:400;color:#2d2d2d}.fine-print,table caption{font-size:12px;font-size:1.2rem;line-height:135%}.labels{font-size:13px;font-size:1.3rem;text-transform:uppercase;font-weight:400}.align-right{text-align:right}.align-center{text-align:center}blockquote{background:#f5f5f5;border-left:4px solid #ddd;padding:1.9em 2em;overflow:hidden}blockquote li,blockquote ol,blockquote p,blockquote ul{margin:.4em 0 0}blockquote div,blockquote h2,blockquote h3,blockquote h4,blockquote h5{margin:0 0 .4em}blockquote.pull-quote{font-size:26px;font-size:2.6rem;background:0 0;border-left:0 none;font-family:capita,Georgia,serif;font-style:italic;line-height:130%;padding:0;margin:1.5em 1.5em 1.5em 2em}blockquote.pull-quote :first-child{margin-top:.3em}blockquote.pull-quote::before{font-size:35px;font-size:3.5rem;color:rgba(0,0,0,.6);content:"\f10d";font-family:FontAwesome;font-style:normal;margin-left:-1.5em;float:left}blockquote.pull-quote cite,body .ui-tabs .ui-tabs-nav{font-family:proximanova,Helvetica,Arial,sans-serif}blockquote.pull-quote cite{font-size:16px;font-size:1.6rem;font-style:normal;display:block;padding-top:.6em}blockquote.pull-quote cite::before{content:"―";margin-right:3px}body .ui-accordion{margin:1em 0;position:relative}body .ui-accordion .accordion-item,body .ui-accordion .views-row{margin:.5em 0}body .ui-accordion .ui-accordion-header{font-size:.9em;padding:.5em 1em .4em 1.9em}body .ui-accordion .ui-accordion-header.cke_widget_editable{padding:.5em 3em .3em 1.9em}body .ui-accordion .ui-accordion-header p{margin:0;color:#2d2d2d}body .ui-accordion .ui-accordion-header,body .ui-accordion .ui-accordion-header.ui-state-active,body .ui-accordion .ui-accordion-header.ui-state-default,body .ui-accordion .ui-accordion-header.ui-state-hover{border:0;background-color:#dedede}body .ui-accordion .ui-accordion-header a,body .ui-accordion .ui-accordion-header.ui-state-active a,body .ui-accordion .ui-accordion-header.ui-state-default a,body .ui-accordion .ui-accordion-header.ui-state-hover a{padding:0}body .ui-accordion .ui-accordion-header.ui-state-active{background-image:none}body .ui-accordion .ui-accordion-content{box-sizing:content-box;background-color:#fff;padding:1.2em 1.9em .5em;border:1px solid #dedede}body .ui-tabs{background-color:transparent;margin:1em 0;position:relative;padding:0;clear:both}body .ui-tabs .ui-tabs-nav{font-size:.9em;padding:.5em 1em 0 0;background-color:transparent}.callout,.intro-text,.tagline{font-family:capita,Georgia,serif}body .ui-tabs .ui-tabs-nav.cke_widget_editable{background-color:#dedede;padding:.5em 3em .3em 1.9em}body .ui-tabs .ui-tabs-nav li,body .ui-tabs .ui-tabs-nav li.ui-state-active,body .ui-tabs .ui-tabs-nav li.ui-state-default,body .ui-tabs .ui-tabs-nav li.ui-state-hover{border-width:1px 1px 0;border-style:solid;border-color:#dedede}body .ui-tabs .ui-tabs-nav li.ui-state-default,body .ui-tabs .ui-tabs-nav li.ui-state-hover{background-color:#dedede;background-image:none}body .ui-tabs .ui-tabs-nav li.ui-tabs-active{background-color:#fff}body .ui-tabs .ui-tabs-content{box-sizing:content-box;background-color:#fff;padding:1.2em 1.9em .5em;border:1px solid #dedede}body .ui-tabs .ui-tabs-content:after{content:"";display:table;clear:both}body .drulog-panels-accordion .accordion-title{margin-bottom:.5em}body .drulog-panels-accordion .accordion-content{margin-top:-.8em;margin-bottom:.8em}.tagline,h2.underlined,h3.underlined{margin-bottom:20px}.tagline{font-size:32px;font-size:3.2rem;font-weight:100;line-height:130%}.subhead{font-size:22px;font-size:2.2rem;color:#b00;line-height:130%}.underlined{border-bottom:1px solid #c7c7c7;padding-bottom:4px;font-weight:300!important;margin-top:0}h2.underlined{font-size:30px;font-size:3rem}h3.underlined{font-size:26px;font-size:2.6rem}.field--name-field-ocio-body .underlined{padding-top:20px}.field--name-field-ocio-body .underlined:first-child{padding-top:0}.row-tiles .underlined{margin-bottom:30px!important;padding-top:20px!important}.intro-text{font-size:22px;font-size:2.2rem;font-style:italic;font-weight:100;line-height:160%;padding-bottom:20px}.intro-text:last-child{padding-bottom:0}.intro-text-alt{font-size:20px;font-size:2rem;font-weight:300;line-height:160%;padding-bottom:10px}.intro-text-alt:last-child{padding-bottom:0}.callout{font-size:36px;font-size:3.6rem;color:#b00;font-weight:300;margin:1em 0 .4em}hr{background-color:#d2d2d2;border:0;height:1px;margin:2em 0}.width-70{margin:10px auto}@media (min-width:60em){.width-70{width:75%}}@media (min-width:82em){.width-70{width:70%}}#block-views-featured-slideshow-block .flexslider{background:#2d2d2d;border:0;border-radius:0;box-shadow:none;margin:0}#block-views-featured-slideshow-block .flexslider .flex-meta{display:block;width:100%;position:absolute;color:#fff;text-align:center;bottom:.6em;padding:.4em 8%;font-size:24px;font-size:2.4rem}#block-views-featured-slideshow-block .flexslider .flex-meta .flex-title{display:block;font-weight:400;line-height:1.1em}#block-views-featured-slideshow-block .flexslider .flex-meta .flex-summary{font-weight:300;font-size:.6em;line-height:1.2em;display:none}@media (min-width:47.5em){#block-views-featured-slideshow-block .flexslider .flex-meta .flex-summary{display:block}#block-views-featured-slideshow-block .flexslider .flex-meta{bottom:.3em;padding:.5em 6%;font-size:32px;font-size:3.2rem}#block-views-featured-slideshow-block .flexslider .flex-meta .flex-title{margin-bottom:.1em}}@media (min-width:60em){#block-views-featured-slideshow-block .flexslider .flex-meta{font-size:34px;font-size:3.4rem}}@media (min-width:82em){#block-views-featured-slideshow-block .flexslider .flex-meta{font-size:40px;font-size:4rem}}#block-views-featured-slideshow-block .flexslider .flex-meta.white{color:#fff}#block-views-featured-slideshow-block .flexslider .flex-meta.white.translucent{bottom:0;background-color:rgba(20,20,20,.6)}#block-views-featured-slideshow-block .flexslider .flex-meta.black.translucent,#block-views-featured-slideshow-block .flexslider .flex-meta.dk-gray.translucent{background-color:rgba(200,200,200,.7);bottom:0}#block-views-featured-slideshow-block .flexslider .flex-meta.dk-gray{color:#2d2d2d}#block-views-featured-slideshow-block .flexslider .flex-meta.black{color:#000}#block-views-featured-slideshow-block .flexslider .flex-direction-nav a{color:rgba(0,0,0,.8);text-decoration:none}#block-views-featured-slideshow-block .flexslider .flex-direction-nav a:before{line-height:1em}#block-views-featured-slideshow-block .lt-ie9 .flexslider a .flex-meta{background-color:transparent;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#AA000000, endColorstr=#AA000000)"}#block-views-featured-slideshow-block .lt-ie9 .flexslider .flex-direction-nav a{color:#000;filter:alpha(opacity="60")}#block-views-featured-slideshow-block .lt-ie9 .flexslider .flex-direction-nav a:hover{filter:alpha(opacity="80")}#block-views-featured-slideshow-block ul.flex-direction-nav,#block-views-featured-slideshow-block ul.flex-direction-nav:hover{display:none}#block-views-featured-slideshow-block .flex-control-nav{text-align:right;padding-right:1.8em;top:20px;z-index:99;width:100%;height:30px}#block-views-featured-slideshow-block .flex-control-paging li a{background-color:#2d2d2d;text-align:left;width:15px;height:15px;margin-bottom:1em}#block-views-featured-slideshow-block .flex-control-paging li a.flex-active{background-color:#fff}@media (max-width:47.4em){#block-views-featured-slideshow-block .flex-control-paging li a{display:none}}.l-region--hero-wrapper{position:relative;max-height:500px}.l-region--hero-wrapper .views-field-field-basic-image-image{position:relative;top:0;z-index:9;max-height:500px;overflow:hidden}.page-newsletter-archive h1{margin-bottom:25px}.page-newsletter-archive .l-region--content{padding-bottom:20px}.page-newsletter-archive .l-region--content li{margin-bottom:15px}.block--mm-widgets .item,.pane-mm-widgets-live-pane .item{margin:1.8em 0}.block--mm-widgets .item .content,.pane-mm-widgets-live-pane .item .content{margin-bottom:.3em}.block--mm-widgets .item .network .fa,.pane-mm-widgets-live-pane .item .network .fa{margin-right:.6em;position:relative;top:1px;padding:.3em 0 .25em;width:1.6em}.block--mm-widgets .fa,.pane-mm-widgets-live-pane .fa{color:#fff;padding:.55em 0 .5em;text-align:center;width:1.8em}.block--mm-widgets .fa.fa-twitter,.pane-mm-widgets-live-pane .fa.fa-twitter{background-color:#00aced}.block--mm-widgets .fa.fa-facebook-page,.pane-mm-widgets-live-pane .fa.fa-facebook-page{background-color:#3b5998}.block--mm-widgets .fa.fa-facebook-page:before,.pane-mm-widgets-live-pane .fa.fa-facebook-page:before{content:'\f09a'}.block--mm-widgets .fa.fa-instagram,.pane-mm-widgets-live-pane .fa.fa-instagram{background-color:#517fa4;top:2px}.block--mm-widgets .fa.fa-rss,.pane-mm-widgets-live-pane .fa.fa-rss{background-color:#f60}.block--mm-widgets .fa.fa-youtube-playlist,.pane-mm-widgets-live-pane .fa.fa-youtube-playlist{background-color:#b00}.block--mm-widgets .fa.fa-youtube-playlist:before,.pane-mm-widgets-live-pane .fa.fa-youtube-playlist:before{content:'\f16a'}.block--mm-widgets.mm-single-channel .fa.mm-channel,.pane-mm-widgets-live-pane.mm-single-channel .fa.mm-channel{float:left;margin-right:.6em}.block--mm-widgets.mm-single-channel .fa.mm-channel+.pane-title,.pane-mm-widgets-live-pane.mm-single-channel .fa.mm-channel+.pane-title{line-height:1.6em}body.html.footer-dk-gray{background-color:#2d2d2d}body.html.footer-md-gray{background-color:#666}body.html.footer-lt-gray{background-color:#f5f5f5}body.html.footer-white{background-color:#fff}form.search-form{margin-top:1em}fieldset.search-advanced{border:0;background-color:#ebebeb;margin-left:0;margin-right:0;padding:.5em 0 0}fieldset.search-advanced legend{margin-top:2.5em}fieldset.search-advanced .criterion{margin-top:1em}fieldset.search-advanced input.form-submit{margin-bottom:1em}p.search-result__snippet{padding-left:0;margin-bottom:.4em}.l-page .l-region--main-menu:hover #search-block-toggle{outline:0!important}.l-page .l-region--main-menu #search-block-toggle{cursor:pointer}.l-page .l-region--main-menu #search-block-toggle:focus{outline:red dotted 1px}.l-page .l-region--main-menu #wcm-search{position:relative}.l-page .l-region--main-menu #wcm-search #block-search-form{z-index:498;position:absolute;right:0;top:100%;background-color:rgba(0,0,0,.8);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#333333, endColorstr=#333333);height:auto;display:none}.l-page .l-region--main-menu #wcm-search #block-search-form *{height:100%}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline{display:table;padding:1em}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline .form-item{display:table-cell;vertical-align:middle}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline .form-item .form-text{border:0;padding:0 6px;font-size:1em}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline .form-actions{display:table-cell;text-align:center;width:1.9em}.book_printer,.node-type-news-client-cached-article .tabs--primary,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text span.ext{display:none}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline .form-actions .form-submit{border-radius:0;-webkit-box-sizing:content-box;box-shadow:none;padding:.6em 1.3em .4em;margin:0;height:auto}@media (max-width:47.4em){.l-page .l-region--main-menu #wcm-search #search-block-toggle{position:absolute;right:0;padding:1em;font-size:1.2em;z-index:500;width:auto;margin-top:.25em}.l-page .l-region--main-menu #wcm-search #block-search-form{display:none;height:auto;width:100%;top:4em;z-index:499}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline{width:100%;clear:both;padding:4%}.l-page .l-region--main-menu #wcm-search #block-search-form .container-inline .form-text{width:100%}}.field--name-field-ocio-body .block--webform{font-size:14px;font-size:1.4rem;margin-bottom:20px}.field--name-field-ocio-body .block--webform .block__title{font-size:22px;font-size:2.2rem;font-weight:400!important;color:#b00!important;padding-top:20px}.field--name-field-ocio-body .block--webform label{font-size:13px;font-size:1.3rem}.field--name-field-ocio-body .block--webform .button-primary{margin-top:10px}div.workbench-info-block{background-color:#d9d9d9;padding:1em 1.5em;margin:1em 0 3em;border:none;color:#2d2d2d;font-size:14px;font-size:1.4rem;border-left:8px solid #d65828}div.workbench-info-block #edit-submit{margin-left:1em;font-size:13px!important;padding:.4em .8em!important}.ds-2col-stacked-fluid.node--article--full .group-left,.ds-2col-stacked-fluid.node--article--full .group-right,.ds-2col-stacked-fluid.node--news-client-cached-article--full .group-left,.ds-2col-stacked-fluid.node--news-client-cached-article--full .group-right{width:100%;float:none}.ds-2col-stacked-fluid.node--article--full .group-right,.ds-2col-stacked-fluid.node--news-client-cached-article--full .group-right{margin-top:30px;margin-bottom:30px}@media (min-width:60em){.ds-2col-stacked-fluid.node--article--full.has-sidebar .group-left,.ds-2col-stacked-fluid.node--news-client-cached-article--full.has-sidebar .group-left{width:70%;float:left;margin-bottom:30px}.ds-2col-stacked-fluid.node--article--full.has-sidebar .group-right,.ds-2col-stacked-fluid.node--news-client-cached-article--full.has-sidebar .group-right{width:27%;float:right;margin-top:10px}}.node--article,.node--news-client-cached-article{position:relative}.node--article .field--name-field-kicker,.node--news-client-cached-article .field--name-field-kicker{text-transform:uppercase;color:#666;font-weight:600;font-size:22px;font-size:2.2rem;margin-bottom:10px}.node--article .field--name-byline,.node--article .field--name-byline-with-date,.node--news-client-cached-article .field--name-byline,.node--news-client-cached-article .field--name-byline-with-date{font-weight:600;padding-top:6px;margin-bottom:12px}.node--article .field--name-field-featured-image,.node--article .field--name-news-client-image-json,.node--news-client-cached-article .field--name-field-featured-image,.node--news-client-cached-article .field--name-news-client-image-json{float:right;max-width:50%;margin:10px 0 40px 40px}.node--article .field--name-field-sidebar,.node--article .field--name-news-client-sidebar,.node--news-client-cached-article .field--name-field-sidebar,.node--news-client-cached-article .field--name-news-client-sidebar{background:#ebebeb;padding:30px 1.8em 20px}.node--article .field--name-field-sidebar h2,.node--article .field--name-field-sidebar h3,.node--article .field--name-field-sidebar h4,.node--article .field--name-news-client-sidebar h2,.node--article .field--name-news-client-sidebar h3,.node--article .field--name-news-client-sidebar h4,.node--news-client-cached-article .field--name-field-sidebar h2,.node--news-client-cached-article .field--name-field-sidebar h3,.node--news-client-cached-article .field--name-field-sidebar h4,.node--news-client-cached-article .field--name-news-client-sidebar h2,.node--news-client-cached-article .field--name-news-client-sidebar h3,.node--news-client-cached-article .field--name-news-client-sidebar h4{margin-top:20px;margin-bottom:20px}.node--article .field--name-field-sidebar h2:first-child,.node--article .field--name-field-sidebar h3:first-child,.node--article .field--name-field-sidebar h4:first-child,.node--article .field--name-news-client-sidebar h2:first-child,.node--article .field--name-news-client-sidebar h3:first-child,.node--article .field--name-news-client-sidebar h4:first-child,.node--news-client-cached-article .field--name-field-sidebar h2:first-child,.node--news-client-cached-article .field--name-field-sidebar h3:first-child,.node--news-client-cached-article .field--name-field-sidebar h4:first-child,.node--news-client-cached-article .field--name-news-client-sidebar h2:first-child,.node--news-client-cached-article .field--name-news-client-sidebar h3:first-child,.node--news-client-cached-article .field--name-news-client-sidebar h4:first-child{margin-top:0}.node--article .field--name-field-learn-more,.node--article .field--name-news-client-links,.node--news-client-cached-article .field--name-field-learn-more,.node--news-client-cached-article .field--name-news-client-links{background:#ebebeb;padding:1em 1.4em;clear:both}.node--article .field--name-field-learn-more .label-above,.node--article .field--name-news-client-links .label-above,.node--news-client-cached-article .field--name-field-learn-more .label-above,.node--news-client-cached-article .field--name-news-client-links .label-above{font-size:17px;font-size:1.7rem;font-weight:600;text-transform:uppercase;padding-bottom:.2em}.node--article .field--name-field-learn-more ul,.node--article .field--name-news-client-links ul,.node--news-client-cached-article .field--name-field-learn-more ul,.node--news-client-cached-article .field--name-news-client-links ul{padding-left:1.2em}.node--article .field--name-field-learn-more ul li,.node--article .field--name-news-client-links ul li,.node--news-client-cached-article .field--name-field-learn-more ul li,.node--news-client-cached-article .field--name-news-client-links ul li{margin:5px 0}.node--article .field--name-field-learn-more ul li.last,.node--article .field--name-news-client-links ul li.last,.node--news-client-cached-article .field--name-field-learn-more ul li.last,.node--news-client-cached-article .field--name-news-client-links ul li.last{margin-bottom:0}.node--article .field--name-field-tags,.node--article .field--name-news-client-tags,.node--news-client-cached-article .field--name-field-tags,.node--news-client-cached-article .field--name-news-client-tags{padding-top:30px}.node--article .field--name-field-tags .field__label,.node--article .field--name-news-client-tags .field__label,.node--news-client-cached-article .field--name-field-tags .field__label,.node--news-client-cached-article .field--name-news-client-tags .field__label{margin-right:5px}.node--article .article-modified,.node--news-client-cached-article .article-modified{margin-top:1em;font-size:13px;font-style:italic}.node--article .article-modified .label-inline,.node--news-client-cached-article .article-modified .label-inline{font-weight:600}.node-type-basic-page h1{margin-bottom:24px}.node-type-basic-page .field--name-field-ocio-body{margin-bottom:20px}.node--basic-page{padding-bottom:2em}.book-navigation{border-top:1px solid #ebebeb;border-bottom:1px solid #ebebeb;padding:.5em 0;margin:2em 0}.book-navigation__links a{color:#2d2d2d;text-transform:uppercase}.book-navigation__links a:hover,.book-navigation__links a:visited:hover{color:#b00;text-decoration:none}.book-navigation__links a:visited{color:#2d2d2d}.book-navigation__links a .fa{color:#b00}.book-navigation__links>.book-navigation__previous .fa{margin-right:10px}.book-navigation__links>.book-navigation__next .fa{margin-left:10px}.book_add_child a{color:#2d2d2d;text-transform:uppercase;min-width:180px}.book_add_child:before{content:"\f067";font-family:FontAwesome;color:#028da9;float:left;margin-right:5px}.node-type-ocio-landing-page .l-region--content{padding-top:20px}.node-type-ocio-landing-page h1{margin-bottom:0}.node-type-ocio-landing-page .l-region--hero-wrapper{position:relative;max-height:500px;overflow:hidden;line-height:0}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image{position:relative;z-index:9}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text{position:absolute;width:100%;padding:20px 12%;text-align:center;margin:0 auto;left:0;right:0;z-index:99;font-size:26px;font-size:2.6rem;line-height:120%}.panels-ipe .modal-content .change-layout-display .layout-icon .caption,.panels-ipe .modal-content .panels-choose-layout .layout-link>div{line-height:1.4em}@media (min-width:60em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text{font-size:30px;font-size:3rem}}@media (min-width:82em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text{padding:20px 14%;font-size:32px;font-size:3.2rem}}@media (min-width:100em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text{padding:20px 16%}}@media (min-width:112em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text{padding:20px 20%}}@media (min-width:125em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text{padding:20px 28%}}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text a:hover{text-decoration:none}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.white,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.white a{color:#fff}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.white a.translucent,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.white.translucent{background-color:rgba(20,20,20,.6)}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.white a.translucent:hover,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.white.translucent:hover{background-color:rgba(46,46,46,.6);color:#fff}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.dk-gray,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.dk-gray a{color:#2d2d2d}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.dk-gray a.translucent,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.dk-gray.translucent{background-color:rgba(220,220,220,.7)}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.dk-gray a.translucent:hover,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.dk-gray.translucent:hover{background-color:rgba(200,200,200,.7)}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.black,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.black a{color:#000}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.black a.translucent,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.black.translucent{background-color:rgba(220,220,220,.7)}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.black a.translucent:hover,.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.black.translucent:hover{background-color:rgba(200,200,200,.7)}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.center-top{top:0}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.center-middle{top:24%}@media (min-width:47.5em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.center-middle{top:30%}}@media (min-width:60em){.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.center-middle{top:36%}}.node-type-ocio-landing-page .l-region--hero-wrapper .field--name-field-banner-image-text.center-bottom{bottom:0;overflow:hidden}.l-region--main-menu.mean-container .mean-bar,.l-region--main-menu.mean-container .mean-nav{background:0 0}.l-region--main-menu.mean-container .mean-bar{z-index:499;padding:0}.l-region--main-menu.mean-container a.meanmenu-reveal{color:#fff;font-size:1.5em;padding:.9em 1em;text-indent:0;text-align:center;left:0!important;right:auto!important}.l-region--main-menu.mean-container .mean-nav{margin-top:4em}.l-region--main-menu.mean-container .mean-nav ul li{text-transform:uppercase}.l-region--main-menu.mean-container .mean-nav ul li li{display:block;float:left;width:100%;margin:0;text-align:left;font-weight:500;box-sizing:border-box;background:rgba(0,0,0,.1);color:rgba(0,0,0,.9)}.l-region--main-menu.mean-container .mean-nav ul li a,.l-region--main-menu.mean-container .mean-nav ul li span{color:#fff;text-decoration:none;padding:1em 1em .9em 1.2em;border:0;box-sizing:border-box;width:100%;display:block}.l-region--main-menu.mean-container .mean-nav ul li li a{padding-left:3em;box-sizing:border-box;width:100%;color:#222;opacity:1}.l-region--main-menu.mean-container .mean-nav ul li a.mean-expand{border:0!important;padding:.7em .9em 1.55em .8em!important;width:auto;margin:0;background-color:transparent}.l-region--main-menu.mean-container .mean-nav ul li a.mean-expand:hover{background:0 0}.l-region--main-menu.mean-container.white{background:#fff;border-bottom:1px solid #e6e6e6}.l-region--main-menu.mean-container.white .mean-nav a,.l-region--main-menu.mean-container.white .mean-nav span,.l-region--main-menu.mean-container.white a.meanmenu-reveal{color:#666}.l-region--main-menu.mean-container.white .mean-bar,.l-region--main-menu.mean-container.white .mean-nav{background:#fff}.l-region--main-menu.mean-container.white .mean-nav ul li li{background:#e6e6e6}.l-region--main-menu.mean-container.white .mean-nav ul li li a,.l-region--main-menu.mean-container.white .mean-nav ul li li span{color:#1a1a1a}.l-region--main-menu.mean-container.lt-gray{background:#ebebeb;border-bottom:1px solid #d2d2d2}.l-region--main-menu.mean-container.lt-gray .mean-nav a,.l-region--main-menu.mean-container.lt-gray .mean-nav span,.l-region--main-menu.mean-container.lt-gray a.meanmenu-reveal{color:#666}.l-region--main-menu.mean-container.lt-gray .mean-bar,.l-region--main-menu.mean-container.lt-gray .mean-nav{background:#ebebeb}.l-region--main-menu.mean-container.lt-gray .mean-nav ul li li{background:#d2d2d2}.l-region--main-menu.mean-container.lt-gray .mean-nav ul li li a,.l-region--main-menu.mean-container.lt-gray .mean-nav ul li li span{color:#1a1a1a}.l-region--main-menu.mean-container.black .mean-nav a,.l-region--main-menu.mean-container.black .mean-nav span,.l-region--main-menu.mean-container.black .mean-nav ul li li a,.l-region--main-menu.mean-container.black .mean-nav ul li li span,.l-region--main-menu.mean-container.black a.meanmenu-reveal,.l-region--main-menu.mean-container.dk-gray .mean-nav a,.l-region--main-menu.mean-container.dk-gray .mean-nav span,.l-region--main-menu.mean-container.dk-gray .mean-nav ul li li a,.l-region--main-menu.mean-container.dk-gray .mean-nav ul li li span,.l-region--main-menu.mean-container.dk-gray a.meanmenu-reveal,.l-region--main-menu.mean-container.md-gray .mean-nav a,.l-region--main-menu.mean-container.md-gray .mean-nav span,.l-region--main-menu.mean-container.md-gray .mean-nav ul li li a,.l-region--main-menu.mean-container.md-gray .mean-nav ul li li span,.l-region--main-menu.mean-container.md-gray a.meanmenu-reveal,.l-region--main-menu.mean-container.red .mean-nav a,.l-region--main-menu.mean-container.red .mean-nav span,.l-region--main-menu.mean-container.red .mean-nav ul li li a,.l-region--main-menu.mean-container.red .mean-nav ul li li span,.l-region--main-menu.mean-container.red a.meanmenu-reveal{color:#fff}.l-region--main-menu.mean-container.md-gray{background:#666;border-bottom:1px solid #4d4d4d}.l-region--main-menu.mean-container.md-gray .mean-bar,.l-region--main-menu.mean-container.md-gray .mean-nav{background:#666}.l-region--main-menu.mean-container.md-gray .mean-nav ul li li{background:#4d4d4d}.l-region--main-menu.mean-container.dk-gray{background:#2d2d2d;border-bottom:1px solid #141414}.l-region--main-menu.mean-container.dk-gray .mean-bar,.l-region--main-menu.mean-container.dk-gray .mean-nav{background:#2d2d2d}.l-region--main-menu.mean-container.dk-gray .mean-nav ul li li{background:#535353}.l-region--main-menu.mean-container.black{background:#000;border-bottom:1px solid #000}.l-region--main-menu.mean-container.black .mean-bar,.l-region--main-menu.mean-container.black .mean-nav{background:#000}.l-region--main-menu.mean-container.black .mean-nav ul li li{background:#262626}.l-region--main-menu.mean-container.red{background:#b00;border-bottom:1px solid #800}.l-region--main-menu.mean-container.red .mean-bar,.l-region--main-menu.mean-container.red .mean-nav{background:#b00}.l-region--main-menu.mean-container.red .mean-nav ul li li{background:#800}.l-page .l-constrained .mean-container #search-block-toggle,.l-page .l-constrained .mean-container .mean-nav ul li a,.l-page .l-constrained .mean-container .mean-nav ul li span,.l-page .l-constrained .mean-container a.meanmenu-reveal{padding-left:4%;padding-right:4%}.l-page .l-constrained .mean-container .mean-nav a.mean-expand{padding-left:4%!important;padding-right:4%!important;margin-right:-2px}.l-page .l-constrained .mean-container .mean-nav ul li li a{padding-left:8%;padding-right:8%}@media (min-width:47.5em){.l-region--main-menu>*{display:table-cell!important}}@media (max-width:47.4em){.l-region--main-menu-wrapper .l-constrained,.l-region--main-menu-wrapper .l-region--main-menu{padding:0}.l-region--main-menu-wrapper .l-region--main-menu>*{display:block}.l-region--main-menu-second-wrapper{display:none}}#superfish-1-toggle span,.l-region--main-menu h2.block__title,.l-region--main-menu span.ext,.l-region--main-menu-second h2.block__title,.l-region--main-menu-second span.ext,.l-region--sidebar-1 h2.block__title,.l-region--sidebar-1 span.ext{display:none}.l-region--main-menu .menu .collapsed,.l-region--main-menu .menu .expanded,.l-region--main-menu .menu .leaf,.l-region--main-menu-second .menu .collapsed,.l-region--main-menu-second .menu .expanded,.l-region--main-menu-second .menu .leaf,.l-region--sidebar-1 .menu .collapsed,.l-region--sidebar-1 .menu .expanded,.l-region--sidebar-1 .menu .leaf{list-style-image:none;list-style-type:none}.l-region--main-menu>*{display:table-cell;vertical-align:middle;width:100%}.l-region--main-menu ul.sf-menu{float:left;clear:left;margin:0}.l-region--main-menu ul.sf-menu li{float:left;margin:0;padding:.75em 1.6em .75em 0;text-transform:uppercase}.l-region--main-menu ul.sf-menu li a,.l-region--main-menu ul.sf-menu li span{font-weight:500;text-decoration:none}.l-region--main-menu ul.sf-menu li a:hover{text-decoration:none}.menu-style-1 .l-region--main-menu-second-wrapper{display:none}.menu-style-1 .l-region--main-menu ul.sf-menu ul{display:none;position:absolute;z-index:99;margin-top:.7em;margin-left:-.9em}.l-region--main-menu-second .main-menu-second-ul,.menu-style-2 .l-region--main-menu ul.sf-menu{margin-left:-1em}.menu-style-1 .l-region--main-menu ul.sf-menu ul li{padding:0}.menu-style-1 .l-region--main-menu ul.sf-menu ul li a{padding:.75em .9em .65em}.menu-style-1 .l-region--main-menu ul li:hover>ul{display:block}.menu-style-1 .l-region--main-menu ul ul.menu li{float:none;position:relative}.menu-style-1 .sf-menu ul:before{content:' ';height:0;position:absolute;width:0;border:10px solid transparent;top:-19px;left:10px;z-index:2}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:after,.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group:after,.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:after,.view-id-user_contact.view-display-id-panel_pane_1 .views-group:after,.view-id-wcm_media_gallery .views-group .views-row:after,.view-id-wcm_media_gallery .views-group:after{content:"";display:table;clear:both}.menu-style-1 .l-region--main-menu,.menu-style-1 .l-region--main-menu-wrapper,.menu-style-1.menu-white .l-region--main-menu,.menu-style-1.menu-white .l-region--main-menu-wrapper{background:#fff}.menu-style-1 .l-region--main-menu-second-wrapper,.menu-style-1 .main-menu-second-ul,.menu-style-1.menu-lt-gray .l-region--main-menu,.menu-style-1.menu-lt-gray .l-region--main-menu-wrapper,.menu-style-1.menu-white .l-region--main-menu-second-wrapper,.menu-style-1.menu-white .main-menu-second-ul{background:#ebebeb}.menu-style-1 #search-block-toggle,.menu-style-1.menu-white #search-block-toggle{color:#666}.menu-style-1 #search-block-toggle:hover,.menu-style-1.menu-white #search-block-toggle:hover{color:#d4df48}.menu-style-1 #search-block-toggle:active,.menu-style-1.menu-white #search-block-toggle:active{color:#028da9}.menu-style-1 #search-block-toggle:focus,.menu-style-1.menu-white #search-block-toggle:focus{color:#d4df48}.menu-style-1 .sf-menu ul:before,.menu-style-1.menu-white .sf-menu ul:before{border-bottom-color:#ebebeb}.menu-style-1 .main-menu-top-li a,.menu-style-1 .main-menu-top-li span,.menu-style-1.menu-white .main-menu-top-li a,.menu-style-1.menu-white .main-menu-top-li span{color:#666!important}.menu-style-1 .main-menu-top-li a:hover,.menu-style-1 .main-menu-top-li span:hover,.menu-style-1.menu-white .main-menu-top-li a:hover,.menu-style-1.menu-white .main-menu-top-li span:hover{color:#b00!important}.menu-style-1 .main-menu-top-li a:active,.menu-style-1 .main-menu-top-li span:active,.menu-style-1.menu-white .main-menu-top-li a:active,.menu-style-1.menu-white .main-menu-top-li span:active{color:#028da9!important}.menu-style-1 .main-menu-top-li a:focus,.menu-style-1 .main-menu-top-li span:focus,.menu-style-1.menu-white .main-menu-top-li a:focus,.menu-style-1.menu-white .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-1 .main-menu-second-ul a,.menu-style-1 .main-menu-second-ul span,.menu-style-1.menu-white .main-menu-second-ul a,.menu-style-1.menu-white .main-menu-second-ul span{color:#666!important}.menu-style-1 .main-menu-second-ul a:hover,.menu-style-1 .main-menu-second-ul span:hover,.menu-style-1.menu-white .main-menu-second-ul a:hover,.menu-style-1.menu-white .main-menu-second-ul span:hover{color:#b00!important}.menu-style-1 .main-menu-second-ul a:active,.menu-style-1 .main-menu-second-ul span:active,.menu-style-1.menu-white .main-menu-second-ul a:active,.menu-style-1.menu-white .main-menu-second-ul span:active{color:#028da9!important}.menu-style-1 .main-menu-second-ul a:focus,.menu-style-1 .main-menu-second-ul span:focus,.menu-style-1.menu-white .main-menu-second-ul a:focus,.menu-style-1.menu-white .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-1 .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1 .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1 .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1 .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover span:hover,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-1 .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1 .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover span:active,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-1 .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1 .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1 .main-menu-second-ul .main-menu-second-li:hover span:focus,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1.menu-white .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-1.menu-lt-gray .l-region--main-menu-second-wrapper,.menu-style-1.menu-lt-gray .main-menu-second-ul{background:#d7d7d7}.menu-style-1.menu-lt-gray #search-block-toggle{color:#2d2d2d}.menu-style-1.menu-lt-gray #search-block-toggle:hover{color:#d4df48}.menu-style-1.menu-lt-gray #search-block-toggle:active{color:#028da9}.menu-style-1.menu-lt-gray #search-block-toggle:focus{color:#d4df48}.menu-style-1.menu-lt-gray .sf-menu ul:before{border-bottom-color:#d7d7d7}.menu-style-1.menu-lt-gray .main-menu-top-li a,.menu-style-1.menu-lt-gray .main-menu-top-li span{color:#2d2d2d!important}.menu-style-1.menu-lt-gray .main-menu-top-li a:hover,.menu-style-1.menu-lt-gray .main-menu-top-li span:hover{color:#b00!important}.menu-style-1.menu-lt-gray .main-menu-top-li a:active,.menu-style-1.menu-lt-gray .main-menu-top-li span:active{color:#028da9!important}.menu-style-1.menu-lt-gray .main-menu-top-li a:focus,.menu-style-1.menu-lt-gray .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-1.menu-lt-gray .main-menu-second-ul a,.menu-style-1.menu-lt-gray .main-menu-second-ul span{color:#4d4d4d!important}.menu-style-1.menu-lt-gray .main-menu-second-ul a:hover,.menu-style-1.menu-lt-gray .main-menu-second-ul span:hover{color:#b00!important}.menu-style-1.menu-lt-gray .main-menu-second-ul a:active,.menu-style-1.menu-lt-gray .main-menu-second-ul span:active{color:#028da9!important}.menu-style-1.menu-lt-gray .main-menu-second-ul a:focus,.menu-style-1.menu-lt-gray .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-1.menu-md-gray .l-region--main-menu,.menu-style-1.menu-md-gray .l-region--main-menu-wrapper{background:#666}.menu-style-1.menu-md-gray .l-region--main-menu-second-wrapper,.menu-style-1.menu-md-gray .main-menu-second-ul{background:#4d4d4d}.menu-style-1.menu-md-gray #search-block-toggle{color:#fff}.menu-style-1.menu-md-gray #search-block-toggle:hover{color:#d4df48}.menu-style-1.menu-md-gray #search-block-toggle:active{color:#028da9}.menu-style-1.menu-md-gray #search-block-toggle:focus{color:#d4df48}.menu-style-1.menu-md-gray .sf-menu ul:before{border-bottom-color:#4d4d4d}.menu-style-1.menu-md-gray .main-menu-top-li a,.menu-style-1.menu-md-gray .main-menu-top-li span{color:#fff!important}.menu-style-1.menu-md-gray .main-menu-top-li a:hover,.menu-style-1.menu-md-gray .main-menu-top-li span:hover{color:#d2d2d2!important}.menu-style-1.menu-md-gray .main-menu-top-li a:active,.menu-style-1.menu-md-gray .main-menu-top-li span:active{color:#028da9!important}.menu-style-1.menu-md-gray .main-menu-top-li a:focus,.menu-style-1.menu-md-gray .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-1.menu-md-gray .main-menu-second-ul a,.menu-style-1.menu-md-gray .main-menu-second-ul span{color:#fff!important}.menu-style-1.menu-md-gray .main-menu-second-ul a:hover,.menu-style-1.menu-md-gray .main-menu-second-ul span:hover{color:#d2d2d2!important}.menu-style-1.menu-md-gray .main-menu-second-ul a:active,.menu-style-1.menu-md-gray .main-menu-second-ul span:active{color:#028da9!important}.menu-style-1.menu-md-gray .main-menu-second-ul a:focus,.menu-style-1.menu-md-gray .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#d2d2d2!important}.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-1.menu-dk-gray .l-region--main-menu,.menu-style-1.menu-dk-gray .l-region--main-menu-wrapper{background:#2d2d2d}.menu-style-1.menu-dk-gray .l-region--main-menu-second-wrapper,.menu-style-1.menu-dk-gray .main-menu-second-ul{background:#666}.menu-style-1.menu-dk-gray #search-block-toggle{color:#fff}.menu-style-1.menu-dk-gray #search-block-toggle:hover{color:#d4df48}.menu-style-1.menu-dk-gray #search-block-toggle:active{color:#028da9}.menu-style-1.menu-dk-gray #search-block-toggle:focus{color:#d4df48}.menu-style-1.menu-dk-gray .sf-menu ul:before{border-bottom-color:#666}.menu-style-1.menu-dk-gray .main-menu-top-li a,.menu-style-1.menu-dk-gray .main-menu-top-li span{color:#fff!important}.menu-style-1.menu-dk-gray .main-menu-top-li a:hover,.menu-style-1.menu-dk-gray .main-menu-top-li span:hover{color:#d2d2d2!important}.menu-style-1.menu-dk-gray .main-menu-top-li a:active,.menu-style-1.menu-dk-gray .main-menu-top-li span:active{color:#028da9!important}.menu-style-1.menu-dk-gray .main-menu-top-li a:focus,.menu-style-1.menu-dk-gray .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-1.menu-dk-gray .main-menu-second-ul a,.menu-style-1.menu-dk-gray .main-menu-second-ul span{color:#fff!important}.menu-style-1.menu-dk-gray .main-menu-second-ul a:hover,.menu-style-1.menu-dk-gray .main-menu-second-ul span:hover{color:#d2d2d2!important}.menu-style-1.menu-dk-gray .main-menu-second-ul a:active,.menu-style-1.menu-dk-gray .main-menu-second-ul span:active{color:#028da9!important}.menu-style-1.menu-dk-gray .main-menu-second-ul a:focus,.menu-style-1.menu-dk-gray .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#d2d2d2!important}.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-1.menu-black .l-region--main-menu,.menu-style-1.menu-black .l-region--main-menu-wrapper{background:#000}.menu-style-1.menu-black .l-region--main-menu-second-wrapper,.menu-style-1.menu-black .main-menu-second-ul{background:#3a3a3a}.menu-style-1.menu-black #search-block-toggle{color:#fff}.menu-style-1.menu-black #search-block-toggle:hover{color:#d4df48}.menu-style-1.menu-black #search-block-toggle:active{color:#028da9}.menu-style-1.menu-black #search-block-toggle:focus{color:#d4df48}.menu-style-1.menu-black .sf-menu ul:before{border-bottom-color:#3a3a3a}.menu-style-1.menu-red .sf-menu ul:before,.menu-style-2 .sf-menu ul:before,.menu-style-2.menu-white .sf-menu ul:before{border-bottom-color:#ebebeb}.menu-style-1.menu-black .main-menu-top-li a,.menu-style-1.menu-black .main-menu-top-li span{color:#fff!important}.menu-style-1.menu-black .main-menu-top-li a:hover,.menu-style-1.menu-black .main-menu-top-li span:hover{color:#d2d2d2!important}.menu-style-1.menu-black .main-menu-top-li a:active,.menu-style-1.menu-black .main-menu-top-li span:active{color:#028da9!important}.menu-style-1.menu-black .main-menu-top-li a:focus,.menu-style-1.menu-black .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-1.menu-black .main-menu-second-ul a,.menu-style-1.menu-black .main-menu-second-ul span{color:#fff!important}.menu-style-1.menu-black .main-menu-second-ul a:hover,.menu-style-1.menu-black .main-menu-second-ul span:hover{color:#d2d2d2!important}.menu-style-1.menu-black .main-menu-second-ul a:active,.menu-style-1.menu-black .main-menu-second-ul span:active{color:#028da9!important}.menu-style-1.menu-black .main-menu-second-ul a:focus,.menu-style-1.menu-black .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#d2d2d2!important}.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1.menu-black .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-1.menu-red .l-region--main-menu,.menu-style-1.menu-red .l-region--main-menu-wrapper{background:#b00}.menu-style-1.menu-red .l-region--main-menu-second-wrapper,.menu-style-1.menu-red .main-menu-second-ul{background:#ebebeb}.menu-style-1.menu-red #search-block-toggle{color:#fff}.menu-style-1.menu-red #search-block-toggle:hover{color:#d2d2d2}.menu-style-1.menu-red #search-block-toggle:active{color:#d4df48}.menu-style-1.menu-red #search-block-toggle:focus{color:#d2d2d2}.menu-style-1.menu-red .main-menu-top-li a,.menu-style-1.menu-red .main-menu-top-li span{color:#fff!important}.menu-style-1.menu-red .main-menu-top-li a:hover,.menu-style-1.menu-red .main-menu-top-li span:hover{color:#d2d2d2!important}.menu-style-1.menu-red .main-menu-top-li a:active,.menu-style-1.menu-red .main-menu-top-li span:active{color:#d4df48!important}.menu-style-1.menu-red .main-menu-top-li a:focus,.menu-style-1.menu-red .main-menu-top-li span:focus{color:#d2d2d2!important}.menu-style-1.menu-red .main-menu-second-ul a,.menu-style-1.menu-red .main-menu-second-ul span{color:#2d2d2d!important}.menu-style-1.menu-red .main-menu-second-ul a:hover,.menu-style-1.menu-red .main-menu-second-ul span:hover{color:#b00!important}.menu-style-1.menu-red .main-menu-second-ul a:active,.menu-style-1.menu-red .main-menu-second-ul span:active{color:#d4df48!important}.menu-style-1.menu-red .main-menu-second-ul a:focus,.menu-style-1.menu-red .main-menu-second-ul span:focus{color:#d2d2d2!important}.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active a,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active span,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover span:active{color:#d4df48!important}.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-1.menu-red .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d2d2d2!important}.menu-style-2 .l-region--main-menu ul.sf-menu li{padding:.75em 1em}.menu-style-2 .l-region--main-menu ul.sf-menu li.sf-depth-2{display:inline-block;width:auto;padding-top:1em}.l-region--main-menu-second .main-menu-second-ul li{float:left;height:48px;text-transform:uppercase;padding:.75em 1em}.l-region--main-menu-second .main-menu-second-ul li a,.l-region--main-menu-second .main-menu-second-ul li span{font-weight:500;text-decoration:none}.l-region--main-menu-second .main-menu-second-ul li a:hover{text-decoration:none}.menu-style-2 .l-region--main-menu,.menu-style-2 .l-region--main-menu-wrapper,.menu-style-2.menu-white .l-region--main-menu,.menu-style-2.menu-white .l-region--main-menu-wrapper{background:#fff}.menu-style-2 .l-region--main-menu-second-wrapper,.menu-style-2.menu-white .l-region--main-menu-second-wrapper{background:#ebebeb}.menu-style-2 .l-region--main-menu-second-wrapper.menu-hover,.menu-style-2.menu-white .l-region--main-menu-second-wrapper.menu-hover{background:#d9d9d9}.menu-style-2 #search-block-toggle,.menu-style-2.menu-white #search-block-toggle{color:#666}.menu-style-2 #search-block-toggle:hover,.menu-style-2.menu-white #search-block-toggle:hover{color:#d4df48}.menu-style-2 #search-block-toggle:active,.menu-style-2.menu-white #search-block-toggle:active{color:#028da9}.menu-style-2 #search-block-toggle:focus,.menu-style-2.menu-white #search-block-toggle:focus{color:#d4df48}.menu-style-2 .main-menu-top-li a,.menu-style-2 .main-menu-top-li span,.menu-style-2.menu-white .main-menu-top-li a,.menu-style-2.menu-white .main-menu-top-li span{color:#666!important}.menu-style-2 .main-menu-top-li a:hover,.menu-style-2 .main-menu-top-li span:hover,.menu-style-2.menu-white .main-menu-top-li a:hover,.menu-style-2.menu-white .main-menu-top-li span:hover{color:#b00!important}.menu-style-2 .main-menu-top-li a:active,.menu-style-2 .main-menu-top-li span:active,.menu-style-2.menu-white .main-menu-top-li a:active,.menu-style-2.menu-white .main-menu-top-li span:active{color:#028da9!important}.menu-style-2 .main-menu-top-li a:focus,.menu-style-2 .main-menu-top-li span:focus,.menu-style-2.menu-white .main-menu-top-li a:focus,.menu-style-2.menu-white .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-2 .main-menu-top-li.active-trail,.menu-style-2.menu-white .main-menu-top-li.active-trail{background:#ebebeb}.menu-style-2 .main-menu-second-ul,.menu-style-2 .main-menu-top-li:hover,.menu-style-2.menu-white .main-menu-second-ul,.menu-style-2.menu-white .main-menu-top-li:hover{background:#d9d9d9}.menu-style-2 .main-menu-top-li.active-trail a,.menu-style-2 .main-menu-top-li.active-trail a:hover,.menu-style-2 .main-menu-top-li.active-trail span,.menu-style-2 .main-menu-top-li.active-trail span:hover,.menu-style-2.menu-white .main-menu-top-li.active-trail a,.menu-style-2.menu-white .main-menu-top-li.active-trail a:hover,.menu-style-2.menu-white .main-menu-top-li.active-trail span,.menu-style-2.menu-white .main-menu-top-li.active-trail span:hover{color:#b00!important}.menu-style-2 .main-menu-top-li.active-trail a:active,.menu-style-2 .main-menu-top-li.active-trail span:active,.menu-style-2.menu-white .main-menu-top-li.active-trail a:active,.menu-style-2.menu-white .main-menu-top-li.active-trail span:active{color:#028da9!important}.menu-style-2 .main-menu-top-li.active-trail a:focus,.menu-style-2 .main-menu-top-li.active-trail span:focus,.menu-style-2.menu-white .main-menu-top-li.active-trail a:focus,.menu-style-2.menu-white .main-menu-top-li.active-trail span:focus{color:#d4df48!important}.menu-style-2 .main-menu-second-ul a,.menu-style-2 .main-menu-second-ul span,.menu-style-2 .main-menu-top-li:hover a,.menu-style-2 .main-menu-top-li:hover a:hover,.menu-style-2 .main-menu-top-li:hover span,.menu-style-2 .main-menu-top-li:hover span:hover,.menu-style-2.menu-white .main-menu-second-ul a,.menu-style-2.menu-white .main-menu-second-ul span,.menu-style-2.menu-white .main-menu-top-li:hover a,.menu-style-2.menu-white .main-menu-top-li:hover a:hover,.menu-style-2.menu-white .main-menu-top-li:hover span,.menu-style-2.menu-white .main-menu-top-li:hover span:hover{color:#666!important}.menu-style-2 .main-menu-second-ul a:hover,.menu-style-2 .main-menu-second-ul span:hover,.menu-style-2.menu-white .main-menu-second-ul a:hover,.menu-style-2.menu-white .main-menu-second-ul span:hover{color:#b00!important}.menu-style-2 .main-menu-second-ul a:active,.menu-style-2 .main-menu-second-ul span:active,.menu-style-2.menu-white .main-menu-second-ul a:active,.menu-style-2.menu-white .main-menu-second-ul span:active{color:#028da9!important}.menu-style-2 .main-menu-second-ul a:focus,.menu-style-2 .main-menu-second-ul span:focus,.menu-style-2.menu-white .main-menu-second-ul a:focus,.menu-style-2.menu-white .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-2 .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2 .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2 .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2 .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover span:hover,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-2 .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2 .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover span:active,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-2 .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2 .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2 .main-menu-second-ul .main-menu-second-li:hover span:focus,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2.menu-white .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-2.menu-lt-gray .l-region--main-menu,.menu-style-2.menu-lt-gray .l-region--main-menu-wrapper{background:#ccc}.menu-style-2.menu-lt-gray .l-region--main-menu-second-wrapper{background:#f0f0f0}.menu-style-2.menu-lt-gray .l-region--main-menu-second-wrapper.menu-hover{background:#e6e6e6}.menu-style-2.menu-lt-gray #search-block-toggle{color:#2d2d2d}.menu-style-2.menu-lt-gray #search-block-toggle:hover{color:#d4df48}.menu-style-2.menu-lt-gray #search-block-toggle:active{color:#028da9}.menu-style-2.menu-lt-gray #search-block-toggle:focus{color:#d4df48}.menu-style-2.menu-lt-gray .sf-menu ul:before{border-bottom-color:#f0f0f0}.menu-style-2.menu-black .sf-menu ul:before,.menu-style-2.menu-dk-gray .sf-menu ul:before,.menu-style-2.menu-md-gray .sf-menu ul:before{border-bottom-color:#ebebeb}.menu-style-2.menu-lt-gray .main-menu-top-li a,.menu-style-2.menu-lt-gray .main-menu-top-li a:hover,.menu-style-2.menu-lt-gray .main-menu-top-li span,.menu-style-2.menu-lt-gray .main-menu-top-li span:hover{color:#2d2d2d!important}.menu-style-2.menu-lt-gray .main-menu-top-li a:active,.menu-style-2.menu-lt-gray .main-menu-top-li span:active{color:#028da9!important}.menu-style-2.menu-lt-gray .main-menu-top-li a:focus,.menu-style-2.menu-lt-gray .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail{background:#f0f0f0}.menu-style-2.menu-lt-gray .main-menu-second-ul,.menu-style-2.menu-lt-gray .main-menu-top-li:hover{background:#e6e6e6}.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail a,.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail span{color:#2d2d2d!important}.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail a:hover,.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail span:hover{color:#b00!important}.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail a:active,.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail span:active{color:#028da9!important}.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail a:focus,.menu-style-2.menu-lt-gray .main-menu-top-li.active-trail span:focus{color:#d4df48!important}.menu-style-2.menu-lt-gray .main-menu-second-ul a,.menu-style-2.menu-lt-gray .main-menu-second-ul span,.menu-style-2.menu-lt-gray .main-menu-top-li:hover a,.menu-style-2.menu-lt-gray .main-menu-top-li:hover a:hover,.menu-style-2.menu-lt-gray .main-menu-top-li:hover span,.menu-style-2.menu-lt-gray .main-menu-top-li:hover span:hover{color:#4d4d4d!important}.menu-style-2.menu-lt-gray .main-menu-second-ul a:hover,.menu-style-2.menu-lt-gray .main-menu-second-ul span:hover{color:#b00!important}.menu-style-2.menu-lt-gray .main-menu-second-ul a:active,.menu-style-2.menu-lt-gray .main-menu-second-ul span:active{color:#028da9!important}.menu-style-2.menu-lt-gray .main-menu-second-ul a:focus,.menu-style-2.menu-lt-gray .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2.menu-lt-gray .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-2.menu-md-gray .l-region--main-menu,.menu-style-2.menu-md-gray .l-region--main-menu-wrapper{background:#666}.menu-style-2.menu-md-gray .l-region--main-menu-second-wrapper{background:#ebebeb}.menu-style-2.menu-md-gray .l-region--main-menu-second-wrapper.menu-hover{background:#dedede}.menu-style-2.menu-md-gray #search-block-toggle{color:#fff}.menu-style-2.menu-md-gray #search-block-toggle:hover{color:#d4df48}.menu-style-2.menu-md-gray #search-block-toggle:active{color:#028da9}.menu-style-2.menu-md-gray #search-block-toggle:focus{color:#d4df48}.menu-style-2.menu-md-gray .main-menu-top-li a,.menu-style-2.menu-md-gray .main-menu-top-li span{color:#fff!important}.menu-style-2.menu-md-gray .main-menu-top-li a:hover,.menu-style-2.menu-md-gray .main-menu-top-li span:hover{color:#4d4d4d!important}.menu-style-2.menu-md-gray .main-menu-top-li a:active,.menu-style-2.menu-md-gray .main-menu-top-li span:active{color:#028da9!important}.menu-style-2.menu-md-gray .main-menu-top-li a:focus,.menu-style-2.menu-md-gray .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-2.menu-md-gray .main-menu-top-li.active-trail{background:#ebebeb}.menu-style-2.menu-md-gray .main-menu-second-ul,.menu-style-2.menu-md-gray .main-menu-top-li:hover{background:#dedede}.menu-style-2.menu-md-gray .main-menu-top-li.active-trail a,.menu-style-2.menu-md-gray .main-menu-top-li.active-trail span{color:#4d4d4d!important}.menu-style-2.menu-md-gray .main-menu-top-li.active-trail a:hover,.menu-style-2.menu-md-gray .main-menu-top-li.active-trail span:hover{color:#b00!important}.menu-style-2.menu-md-gray .main-menu-top-li.active-trail a:active,.menu-style-2.menu-md-gray .main-menu-top-li.active-trail span:active{color:#028da9!important}.menu-style-2.menu-md-gray .main-menu-top-li.active-trail a:focus,.menu-style-2.menu-md-gray .main-menu-top-li.active-trail span:focus{color:#d4df48!important}.menu-style-2.menu-md-gray .main-menu-second-ul a,.menu-style-2.menu-md-gray .main-menu-second-ul span,.menu-style-2.menu-md-gray .main-menu-top-li:hover a,.menu-style-2.menu-md-gray .main-menu-top-li:hover a:hover,.menu-style-2.menu-md-gray .main-menu-top-li:hover span,.menu-style-2.menu-md-gray .main-menu-top-li:hover span:hover{color:#4d4d4d!important}.menu-style-2.menu-md-gray .main-menu-second-ul a:hover,.menu-style-2.menu-md-gray .main-menu-second-ul span:hover{color:#b00!important}.menu-style-2.menu-md-gray .main-menu-second-ul a:active,.menu-style-2.menu-md-gray .main-menu-second-ul span:active{color:#028da9!important}.menu-style-2.menu-md-gray .main-menu-second-ul a:focus,.menu-style-2.menu-md-gray .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2.menu-md-gray .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-2.menu-dk-gray .l-region--main-menu,.menu-style-2.menu-dk-gray .l-region--main-menu-wrapper{background:#2d2d2d}.menu-style-2.menu-dk-gray .l-region--main-menu-second-wrapper{background:#ebebeb}.menu-style-2.menu-dk-gray .l-region--main-menu-second-wrapper.menu-hover{background:#d2d2d2}.menu-style-2.menu-dk-gray #search-block-toggle{color:#fff}.menu-style-2.menu-dk-gray #search-block-toggle:hover{color:#d4df48}.menu-style-2.menu-dk-gray #search-block-toggle:active{color:#028da9}.menu-style-2.menu-dk-gray #search-block-toggle:focus{color:#d4df48}.menu-style-2.menu-dk-gray .main-menu-top-li a,.menu-style-2.menu-dk-gray .main-menu-top-li span{color:#fff!important}.menu-style-2.menu-dk-gray .main-menu-top-li a:hover,.menu-style-2.menu-dk-gray .main-menu-top-li span:hover{color:#2d2d2d!important}.menu-style-2.menu-dk-gray .main-menu-top-li a:active,.menu-style-2.menu-dk-gray .main-menu-top-li span:active{color:#028da9!important}.menu-style-2.menu-dk-gray .main-menu-top-li a:focus,.menu-style-2.menu-dk-gray .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail{background:#ebebeb}.menu-style-2.menu-dk-gray .main-menu-second-ul,.menu-style-2.menu-dk-gray .main-menu-top-li:hover{background:#d2d2d2}.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail a,.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail span{color:#2d2d2d!important}.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail a:hover,.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail span:hover{color:#b00!important}.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail a:active,.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail span:active{color:#028da9!important}.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail a:focus,.menu-style-2.menu-dk-gray .main-menu-top-li.active-trail span:focus{color:#d4df48!important}.menu-style-2.menu-dk-gray .main-menu-second-ul a,.menu-style-2.menu-dk-gray .main-menu-second-ul span,.menu-style-2.menu-dk-gray .main-menu-top-li:hover a,.menu-style-2.menu-dk-gray .main-menu-top-li:hover a:hover,.menu-style-2.menu-dk-gray .main-menu-top-li:hover span,.menu-style-2.menu-dk-gray .main-menu-top-li:hover span:hover{color:#2d2d2d!important}.menu-style-2.menu-dk-gray .main-menu-second-ul a:hover,.menu-style-2.menu-dk-gray .main-menu-second-ul span:hover{color:#b00!important}.menu-style-2.menu-dk-gray .main-menu-second-ul a:active,.menu-style-2.menu-dk-gray .main-menu-second-ul span:active{color:#028da9!important}.menu-style-2.menu-dk-gray .main-menu-second-ul a:focus,.menu-style-2.menu-dk-gray .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2.menu-dk-gray .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-2.menu-black .l-region--main-menu,.menu-style-2.menu-black .l-region--main-menu-wrapper{background:#000}.menu-style-2.menu-black .l-region--main-menu-second-wrapper{background:#ebebeb}.menu-style-2.menu-black .l-region--main-menu-second-wrapper.menu-hover{background:#d2d2d2}.menu-style-2.menu-black #search-block-toggle{color:#fff}.menu-style-2.menu-black #search-block-toggle:hover{color:#d4df48}.menu-style-2.menu-black #search-block-toggle:active{color:#028da9}.menu-style-2.menu-black #search-block-toggle:focus{color:#d4df48}.menu-style-2.menu-black .main-menu-top-li a,.menu-style-2.menu-black .main-menu-top-li span{color:#fff!important}.menu-style-2.menu-black .main-menu-top-li a:hover,.menu-style-2.menu-black .main-menu-top-li span:hover{color:#2d2d2d!important}.menu-style-2.menu-black .main-menu-top-li a:active,.menu-style-2.menu-black .main-menu-top-li span:active{color:#028da9!important}.menu-style-2.menu-black .main-menu-top-li a:focus,.menu-style-2.menu-black .main-menu-top-li span:focus{color:#d4df48!important}.menu-style-2.menu-black .main-menu-top-li.active-trail{background:#ebebeb}.menu-style-2.menu-black .main-menu-second-ul,.menu-style-2.menu-black .main-menu-top-li:hover{background:#d2d2d2}.menu-style-2.menu-black .main-menu-top-li.active-trail a,.menu-style-2.menu-black .main-menu-top-li.active-trail span{color:#2d2d2d!important}.menu-style-2.menu-black .main-menu-top-li.active-trail a:hover,.menu-style-2.menu-black .main-menu-top-li.active-trail span:hover{color:#b00!important}.menu-style-2.menu-black .main-menu-top-li.active-trail a:active,.menu-style-2.menu-black .main-menu-top-li.active-trail span:active{color:#028da9!important}.menu-style-2.menu-black .main-menu-top-li.active-trail a:focus,.menu-style-2.menu-black .main-menu-top-li.active-trail span:focus{color:#d4df48!important}.menu-style-2.menu-black .main-menu-second-ul a,.menu-style-2.menu-black .main-menu-second-ul span,.menu-style-2.menu-black .main-menu-top-li:hover a,.menu-style-2.menu-black .main-menu-top-li:hover a:hover,.menu-style-2.menu-black .main-menu-top-li:hover span,.menu-style-2.menu-black .main-menu-top-li:hover span:hover{color:#2d2d2d!important}.menu-style-2.menu-black .main-menu-second-ul a:hover,.menu-style-2.menu-black .main-menu-second-ul span:hover{color:#b00!important}.menu-style-2.menu-black .main-menu-second-ul a:active,.menu-style-2.menu-black .main-menu-second-ul span:active{color:#028da9!important}.menu-style-2.menu-black .main-menu-second-ul a:focus,.menu-style-2.menu-black .main-menu-second-ul span:focus{color:#d4df48!important}.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2.menu-black .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d4df48!important}.menu-style-2.menu-red .l-region--main-menu,.menu-style-2.menu-red .l-region--main-menu-wrapper{background:#b00}.menu-style-2.menu-red .l-region--main-menu-second-wrapper{background:#eee}.menu-style-2.menu-red .l-region--main-menu-second-wrapper.menu-hover{background:#dcdcdc}.menu-style-2.menu-red #search-block-toggle{color:#fff}.menu-style-2.menu-red #search-block-toggle:hover{color:#d2d2d2}.menu-style-2.menu-red #search-block-toggle:active{color:#028da9}.menu-style-2.menu-red #search-block-toggle:focus{color:#d2d2d2}.menu-style-2.menu-red .sf-menu ul:before{border-bottom-color:#eee}.menu-style-2.menu-red .main-menu-top-li a,.menu-style-2.menu-red .main-menu-top-li span{color:#fff!important}.menu-style-2.menu-red .main-menu-top-li a:hover,.menu-style-2.menu-red .main-menu-top-li span:hover{color:#2d2d2d!important}.menu-style-2.menu-red .main-menu-top-li a:active,.menu-style-2.menu-red .main-menu-top-li span:active{color:#028da9!important}.menu-style-2.menu-red .main-menu-top-li a:focus,.menu-style-2.menu-red .main-menu-top-li span:focus{color:#d2d2d2!important}.menu-style-2.menu-red .main-menu-top-li.active-trail{background:#eee}.menu-style-2.menu-red .main-menu-second-ul,.menu-style-2.menu-red .main-menu-top-li:hover{background:#dcdcdc}.menu-style-2.menu-red .main-menu-top-li.active-trail a,.menu-style-2.menu-red .main-menu-top-li.active-trail span{color:#2d2d2d!important}.menu-style-2.menu-red .main-menu-top-li.active-trail a:hover,.menu-style-2.menu-red .main-menu-top-li.active-trail span:hover{color:#b00!important}.menu-style-2.menu-red .main-menu-top-li.active-trail a:active,.menu-style-2.menu-red .main-menu-top-li.active-trail span:active{color:#028da9!important}.menu-style-2.menu-red .main-menu-top-li.active-trail a:focus,.menu-style-2.menu-red .main-menu-top-li.active-trail span:focus{color:#d2d2d2!important}.menu-style-2.menu-red .main-menu-second-ul a,.menu-style-2.menu-red .main-menu-second-ul span,.menu-style-2.menu-red .main-menu-top-li:hover a,.menu-style-2.menu-red .main-menu-top-li:hover a:hover,.menu-style-2.menu-red .main-menu-top-li:hover span,.menu-style-2.menu-red .main-menu-top-li:hover span:hover{color:#2d2d2d!important}.panels-ipe .modal-content .panels-choose-layout .layout-link.current-layout,.sidebar-panel{background-color:#f5f5f5}.menu-style-2.menu-red .main-menu-second-ul a:hover,.menu-style-2.menu-red .main-menu-second-ul span:hover{color:#b00!important}.menu-style-2.menu-red .main-menu-second-ul a:active,.menu-style-2.menu-red .main-menu-second-ul span:active{color:#028da9!important}.menu-style-2.menu-red .main-menu-second-ul a:focus,.menu-style-2.menu-red .main-menu-second-ul span:focus{color:#d2d2d2!important}.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active a,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active a:hover,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active span,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active span:hover,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover a,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover a:hover,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover span,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover span:hover{color:#b00!important}.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active a:active,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active span:active,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover a:active,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover span:active{color:#028da9!important}.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active a:focus,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li.active span:focus,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover a:focus,.menu-style-2.menu-red .main-menu-second-ul .main-menu-second-li:hover span:focus{color:#d2d2d2!important}.panels-ipe-editing .panels-row.empty{display:block}.panels-ipe .modal-content .panels-choose-layout .layout-link{text-align:center;height:190px}.panels-ipe .modal-content .panels-choose-layout .layout-link img{margin-top:.8em}.panels-ipe .modal-content .panels-choose-layout .layout-link .ajax-progress-throbber{display:block;text-align:center;margin:0 auto}.panels-ipe .modal-content .change-layout-display{display:table;margin:2em auto;text-align:center}.panels-ipe .modal-content .change-layout-display .layout-icon{text-align:center}.panels-ipe .modal-content .change-layout-display>img{padding:5em 2em}.panels-ipe .modal-content #panels-dnd-main div.panel-region h2.label{margin:.5em 0}.panels-ipe-editing .panels-ipe-portlet-content{overflow:visible}.panels-ipe-sort-container>.panels-ipe-portlet-wrapper:first-child .panel-pane{margin-top:20px}.panels-ipe-sort-container>.panels-ipe-portlet-wrapper:last-child .panel-pane{margin-bottom:0}.panel-pane{margin-bottom:40px!important}.panel-pane:last-child{margin-bottom:0!important}.panel-pane.pane-bundle-tile-pane,.panel-pane.pane-bundle-tile-pane-plus-text-area{margin-bottom:30px!important}.panels-ipe-region .panels-ipe-portlet-wrapper .panel-pane{margin-bottom:40px!important}.panels-ipe-region .panels-ipe-portlet-wrapper .panel-pane.pane-bundle-tile-pane,.panels-ipe-region .panels-ipe-portlet-wrapper .panel-pane.pane-bundle-tile-pane-plus-text-area{margin-bottom:20px!important}.panel-pane.title-only{margin-bottom:0!important}.panel-pane.title-only h2.underlined{margin-bottom:10px}.panels-ipe-region .panels-ipe-portlet-wrapper .panel-pane.title-only{margin-bottom:0!important}.panels-ipe-processed .panel-pane{margin-top:0!important}div.pane-bundle-video .media-vimeo-video,div.pane-bundle-video .media-youtube-video{height:auto;padding:0}.sidebar-panel{padding:1em}.sidebar-panel .panel-pane{margin-top:0;margin-bottom:0}.sidebar-panel>.panel-pane:first-child,.sidebar-panel>.panels-ipe-portlet-wrapper:first-child .panel-pane{margin-top:0}.panels-row.active{padding:15px 0}.panels-row.empty{padding:0;display:none}.panels-row.even,.panels-row.odd{padding:30px 0}.panels-row.first{padding-top:7.5px}.panels-row.last{padding-bottom:30px}.node-type-ocio-landing-page .l-main.lt-gray,.node-type-ocio-landing-page .l-main.lt-gray .panels-row.even{background:#f5f5f5}.node-type-ocio-landing-page .l-main.lt-gray .panels-row.odd,.node-type-ocio-landing-page .l-main.white,.node-type-ocio-landing-page .l-main.white .panels-row.even{background:#fff}.node-type-ocio-landing-page .l-main.white .panels-row.odd{background:#f5f5f5}.panel-pane.pane-bundle-tile-pane,.panel-pane.pane-bundle-tile-pane-plus-text-area{box-shadow:0 1px 1px 0 rgba(0,0,0,.22);padding:0;z-index:9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane{background:#fff;width:100%;z-index:99}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.tile-pane-linked:hover,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.tile-pane-linked:hover{opacity:.85}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane>a,.panel-pane.pane-bundle-tile-pane .ui-accordion-content .fieldable-panels-pane>a,.panel-pane.pane-bundle-tile-pane .ui-tabs-content .fieldable-panels-pane>a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane>a,.panel-pane.pane-bundle-tile-pane-plus-text-area .ui-accordion-content .fieldable-panels-pane>a,.panel-pane.pane-bundle-tile-pane-plus-text-area .ui-tabs-content .fieldable-panels-pane>a{text-decoration:none;height:100%;display:block}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .field--name-field-tile-background-img img,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .field--name-field-tile-background-img img{display:block;width:100%}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane blockquote.pull-quote li,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane blockquote.pull-quote p,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane blockquote.pull-quote li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane blockquote.pull-quote p{font-size:20px;font-size:2rem}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane a,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane a:visited{color:#b00}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane a:hover{color:#666}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.lt-gray{background:#ebebeb}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.lt-gray a,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.lt-gray a:visited{color:#2d2d2d}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.lt-gray a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.lt-gray a:hover{color:#b00}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.lt-gray a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.md-gray{background:#666;color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.md-gray a,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.md-gray a:visited{color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.md-gray a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.md-gray a:hover{color:#ebebeb}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.md-gray a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.dk-gray{background:#2d2d2d;color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.dk-gray a,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.dk-gray a:visited{color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.dk-gray a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.dk-gray a:hover{color:#ebebeb}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.dk-gray a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.black{background:#000;color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.black a,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.black a:visited{color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.black a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.black a:hover{color:#ebebeb}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.black a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.red{background:#b60000;color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.red a,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.red a:visited{color:#fff}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.red a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.red a:hover{color:#ebebeb}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane.red a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .title-box{padding:.8em 1em;display:table;width:100%}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .title-box .title-text{display:table-cell;vertical-align:middle;width:100%;text-align:center;padding:0 1em}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .title-box .title-text h2{font-size:18px;font-size:1.8rem;font-family:proximanova,Helvetica,Arial,sans-serif!important;line-height:110%;font-weight:300;margin:1px 0 0;padding:0}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .title-box .title-icon{display:table-cell;vertical-align:middle;font-size:24px;font-size:2.4rem}@media (max-width:47.4em){.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .text-areas h2,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .title-box .title-text h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .text-areas h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .title-box .title-text h2{font-size:24px;font-size:2.4rem}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .text-areas .title-icon,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .title-box .title-text .title-icon,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .text-areas .title-icon,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .title-box .title-text .title-icon{font-size:30px;font-size:3rem}.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .field--name-field-tile-text-area li,.panel-pane.pane-bundle-tile-pane .fieldable-panels-pane .field--name-field-tile-text-area p,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .field--name-field-tile-text-area li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .field--name-field-tile-text-area p{font-size:20px;font-size:2rem}}.panel-pane.pane-bundle-tile-pane-plus-text-area{text-align:center;color:#2d2d2d}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a:visited{color:#b00}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a:hover{color:#666}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane h2{color:#b00;font-size:20px;font-size:2rem;font-weight:400;margin-top:0;text-decoration:none}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.lt-gray{background:#ebebeb}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.lt-gray a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.lt-gray a:visited{color:#2d2d2d}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.lt-gray a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.lt-gray a:hover{color:#b00}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.lt-gray a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray{background:#666}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray{background:#2d2d2d}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black{background:#000}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red{background:#b60000}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black a:visited,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black p,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray a:visited,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray p,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray a:visited,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray p,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red a,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red a:visited,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red p{color:#fff}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black a:focus,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray a:focus,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray a:focus,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red a:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black a:hover,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray a:hover,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray a:hover,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red a:hover{color:#ebebeb}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.black a:active,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.dk-gray a:active,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.md-gray a:active,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane.red a:active{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane .text-areas{padding:1.6em .4em .6em}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane p{font-size:16px;font-size:1.6rem;font-weight:300;line-height:140%}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane ol,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane p,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane ul{margin:1em 0 0}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane li{text-align:left;margin-left:-2em}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane li.align-center{margin-left:-3em;text-align:center}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane li.align-right{text-align:right}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a li,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a p{color:#2d2d2d}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a h2,.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a h2:visited{color:#b00}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a h2:focus{color:#028da9}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a h2:hover{color:#b00}.panel-pane.pane-bundle-tile-pane-plus-text-area .fieldable-panels-pane a h2:active{color:#2d2d2d}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon{display:block;padding:1.4em 1.4em 1em}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon .field--name-field-tile-background-img{display:table-cell;vertical-align:middle;width:25%}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon .field--name-field-tile-background-img img{width:100%}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon .field--name-field-tile-background-img+h2{display:table-cell;padding-left:.8em;vertical-align:middle;width:75%;text-align:left}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon .field--name-field-tile-background-img+h2+.text-areas{display:inline-block;width:100%;background:inherit}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon .text-areas{padding:0}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon-center{display:block;padding:2em 1em 1em}.panel-pane.pane-bundle-tile-pane-plus-text-area .tile-image-style-icon-center .field--name-field-tile-background-img{width:50%;max-width:110px;margin:0 auto}@media (min-width:47.5em){.tile-5 .panel-pane.pane-bundle-tile-pane-plus-text-area h2{font-size:19px;font-size:1.9rem}.tile-5 .panel-pane.pane-bundle-tile-pane-plus-text-area .field--name-field-tile-text-area li,.tile-5 .panel-pane.pane-bundle-tile-pane-plus-text-area .field--name-field-tile-text-area p{font-size:15px;font-size:1.5rem;line-height:130%}.tile-5 .panel-pane.pane-bundle-tile-pane-plus-text-area .text-areas{padding:1.2em .2em .6em}}#edit-field-tile-background-img .description{font-size:120%;line-height:130%;margin-top:10px}.l-content{min-height:4em}.l-footer-wrapper .l-region{margin-bottom:20px;text-align:left}.l-footer-wrapper .l-region--footer-1 p,.l-footer-wrapper .l-region--footer-3 p{font-size:13px;font-size:1.3rem;line-height:135%;margin:0}.l-footer-wrapper .l-region--footer-2{text-align:right}.l-footer-wrapper .l-region--footer-3{clear:both}.l-footer-wrapper a{font-weight:400}.l-footer-wrapper #osu-wordmark{margin-bottom:10px}.l-footer-wrapper #osu-wordmark img{max-width:300px}.l-footer-wrapper .osu-siteinfo-name{font-weight:600}.l-footer-wrapper .osu-siteinfo-address{float:left;font-style:normal}.l-footer-wrapper .osu-siteinfo-address .pipe{margin:0 2px;color:#b8b8b8}@media (max-width:47.4em){.l-page .l-footer-wrapper .l-region{text-align:center}.l-page .l-footer-wrapper .l-region p{font-size:17px;font-size:1.7rem}.l-page .l-footer-wrapper .l-region>*{float:none;text-align:center}.l-page .l-footer-wrapper .l-region ul{padding:0}.l-page .l-footer-wrapper .l-region ul li:first-child *{margin-left:0}}.footer-dk-gray .l-footer-wrapper{background:#2d2d2d;color:#fff}.footer-dk-gray .l-footer-wrapper a,.footer-dk-gray .l-footer-wrapper a:visited{color:#fff}.footer-dk-gray .l-footer-wrapper a:focus{color:#d4df48}.footer-dk-gray .l-footer-wrapper a:hover{color:#666}.footer-dk-gray .l-footer-wrapper a:active{color:#b00}.footer-dk-gray .l-footer-wrapper .pipe{color:#b8b8b8}.footer-md-gray .l-footer-wrapper{background:#666;color:#fff}.footer-md-gray .l-footer-wrapper a,.footer-md-gray .l-footer-wrapper a:visited{color:#fff}.footer-md-gray .l-footer-wrapper a:focus{color:#d4df48}.footer-md-gray .l-footer-wrapper a:hover{color:#ebebeb}.footer-md-gray .l-footer-wrapper a:active{color:#b00}.footer-md-gray .l-footer-wrapper .pipe{color:#ebebeb}.footer-md-gray .l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link{color:#666;background-color:#fff}.footer-md-gray .l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link:focus,.footer-md-gray .l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link:hover{color:#fff}.footer-lt-gray .l-footer-wrapper{background:#ebebeb;color:#474747}.footer-lt-gray .l-footer-wrapper a,.footer-lt-gray .l-footer-wrapper a:visited{color:#2d2d2d}.footer-lt-gray .l-footer-wrapper a:focus{color:#d4df48}.footer-lt-gray .l-footer-wrapper .pipe,.footer-lt-gray .l-footer-wrapper a:active,.footer-lt-gray .l-footer-wrapper a:hover{color:#b00}.footer-lt-gray .l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link{background-color:#2d2d2d}.footer-white .l-footer-wrapper{background:#fff;color:#666}.footer-white .l-footer-wrapper a,.footer-white .l-footer-wrapper a:visited{color:#666}.footer-white .l-footer-wrapper a:focus{color:#d4df48}.footer-white .l-footer-wrapper .pipe,.footer-white .l-footer-wrapper a:active,.footer-white .l-footer-wrapper a:hover{color:#b00}.l-footer-wrapper .osu-siteinfo-social{margin-top:0;padding-left:0;text-align:right}.l-footer-wrapper .osu-siteinfo-social li{list-style-type:none;display:inline-block}@media (min-width:47.5em) and (max-width:59em){.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(5):first-child:nth-child(4),.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(5):first-child~:nth-child(4){clear:both}.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(5):first-child:nth-child(n+4),.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(5):first-child~:nth-child(n+4){float:right}}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link{color:#fff;background-color:#666;margin:0 0 1em 1em;width:2.55em;padding:.62em 0 .46em;text-align:center;display:block}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link:hover{background-color:#000}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-facebook:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-facebook:hover{background-color:#3b5998}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-twitter:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-twitter:hover{background-color:#00aced}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-youtube:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-youtube:hover{background-color:#b00}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-googleplus:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-googleplus:hover{background-color:#dd4b39}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-photos:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-photos:hover{background-color:#ff0084}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-instagram:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-instagram:hover{background-color:#517fa4}.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-linkedin:focus,.l-footer-wrapper .osu-siteinfo-social li .siteinfo-social-link.link-linkedin:hover{background-color:#007bb6}.l-main.white{background:#fff}.l-main.lt-gray{background:#f5f5f5}.l-main{padding-bottom:30px}.node-type-ocio-landing-page .l-main{padding-bottom:0}.l-region--masthead{padding:20px 0}@media (min-width:47.5em){.l-footer-wrapper .osu-siteinfo-social{float:right}.l-footer-wrapper .osu-siteinfo-social li{float:left}.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(6):first-child:nth-child(4),.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(6):first-child~:nth-child(4),.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(7):first-child:nth-child(5),.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(7):first-child~:nth-child(5){clear:both}.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(7):first-child:nth-child(n+5),.l-footer-wrapper .osu-siteinfo-social li:nth-last-child(7):first-child~:nth-child(n+5){float:right}.l-region--masthead .l-constrained{width:100%;display:table}}#site-name{display:table-cell;vertical-align:middle;font-size:48px;font-size:4.8rem;max-width:500px}#site-name .site-name-prefix{display:block;font-size:.5em;font-weight:300;color:#666}#site-name .site-name-main{color:#2d2d2d;font-weight:600;display:block;line-height:1em}#site-name a{text-decoration:none;display:block}#site-name .site-name-slogan{font-size:.5em;font-weight:400;color:#666;margin-top:20px}#site-name.site-name-2-lines{font-size:44px;font-size:4.4rem}#site-name.site-name-3-lines{font-size:32px;font-size:3.2rem}#site-name.site-name-4-lines{font-size:30px;font-size:3rem}#site-logo{display:table-cell;vertical-align:middle;text-align:right}#site-logo img{height:140px;width:auto;margin-right:-.5em}@media (max-width:47.4em){#site-logo{display:none}}.l-region--masthead.white{background-color:#fff}.l-region--masthead.dk-gray{background-color:#2d2d2d}.l-region--masthead.dk-gray #site-name .site-name-main{color:#fff}.l-region--masthead.dk-gray #site-name .site-name-prefix,.l-region--masthead.dk-gray #site-name .site-name-slogan{color:#ebebeb}.l-region--masthead.md-gray{background-color:#666}.l-region--masthead.md-gray #site-name .site-name-main{color:#fff}.l-region--masthead.md-gray #site-name .site-name-prefix,.l-region--masthead.md-gray #site-name .site-name-slogan{color:#f3f3f3}.l-region--masthead.lt-gray{background-color:#ebebeb}.l-region--osu-navbar{clear:both;margin:0;padding:0;background:url(../images/osu-navbar/lt-gray/bg-navbar_red.png) left bottom repeat-x #eaeaea;overflow:hidden}#osu_navbar *{font-family:proximanova,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:13px;line-height:1.4;font-weight:400}#osu_navbar p{margin:0;padding:0}#osu_navbar .univ_info{float:left;padding:.9em 0 1.1em;margin-left:0}#osu_navbar .univ_links{float:right;clear:none;padding:1em 0 0;margin-top:-2px}#osu_navbar .univ_name a{height:16px;width:90px;display:block;text-indent:-9999px;background:url(../images/osu-navbar/lt-gray/osu_name.png) no-repeat;margin-left:0;overflow:hidden}#osu_navbar div.links{float:left;margin-bottom:10px}#osu_navbar div.links ul{margin:0;padding:0}#osu_navbar div.links ul li{list-style:none;float:left;margin-left:1em}#osu_navbar div.links ul li a{color:#333;text-decoration:none;background-position:0 0}#osu_navbar div.links ul li a:hover{text-decoration:underline}.osu-semantic{position:absolute;left:0;top:-500px;width:1px;height:1px;overflow:hidden}a.osu-semantic:active,a.osu-semantic:focus{position:absolute;left:0;top:0;overflow:visible}a#skip:active,a#skip:focus{position:absolute;top:0;left:25%;width:50%;text-align:center;padding:.5em 0 1.5em;display:block;color:#fff;z-index:999999999999999999;text-decoration:none;background:#666;background:rgba(0,0,0,.8);border:1px dotted #ccc;border-top:none;border-radius:0 0 6px 6px}.view,.views-exposed-form,.views-exposed-widgets .views-exposed-.views-exposed-widgets{position:relative}a#skip:active:hover,a#skip:focus:hover{background:#b00;background:rgba(187,0,0,.8)}.l-region--osu-navbar.dk-gray{background:url(../images/osu-navbar/dk-gray/bg-navbar_red.png) left bottom repeat-x #333}.l-region--osu-navbar.dk-gray #osu_navbar .univ_name a{background-image:url(../images/osu-navbar/dk-gray/osu_name.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a{color:#fff}@media (max-width:47.4em){#osu_navbar div.links ul{margin-top:-2px}#osu_navbar div.links ul li{list-style:none;float:left;margin-left:.5em}#osu_navbar div.links ul li a{height:23px;width:23px;display:block;overflow:hidden;text-indent:-999px}#osu_navbar div.links ul li a:hover{text-decoration:none}.l-region--osu-navbar #osu_navbar div.links ul li a.help,.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.help{background-image:url(../images/osu-navbar/lt-gray/resp-help.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.buckeyelink,.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.buckeyelink{background-image:url(../images/osu-navbar/lt-gray/resp-buckeyelink.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.map,.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.map{background-image:url(../images/osu-navbar/lt-gray/resp-map.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.findpeople,.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.findpeople{background-image:url(../images/osu-navbar/lt-gray/resp-findpeople.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.webmail,.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.webmail{background-image:url(../images/osu-navbar/lt-gray/resp-webmail.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.search,.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.search{background-image:url(../images/osu-navbar/lt-gray/resp-search.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.help{background-image:url(../images/osu-navbar/dk-gray/resp-help.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.buckeyelink{background-image:url(../images/osu-navbar/dk-gray/resp-buckeyelink.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.map{background-image:url(../images/osu-navbar/dk-gray/resp-map.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.findpeople{background-image:url(../images/osu-navbar/dk-gray/resp-findpeople.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.webmail{background-image:url(../images/osu-navbar/dk-gray/resp-webmail.png)}.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.search{background-image:url(../images/osu-navbar/dk-gray/resp-search.png)}}@media only screen and (max-width:720px) and (-webkit-min-device-pixel-ratio:2),only screen and (max-width:720px) and (min--moz-device-pixel-ratio:2),only screen and (max-width:720px) and (-o-min-device-pixel-ratio:2 / 1),only screen and (max-width:720px) and (min-device-pixel-ratio:2){.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a{background-size:23px}.l-region--osu-navbar.lt-gray #osu_navbar .univ_name a{background-size:contain}.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.help{background-image:url(../images/osu-navbar/lt-gray/resp-help@2x.png)}.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.buckeyelink{background-image:url(../images/osu-navbar/lt-gray/resp-buckeyelink@2x.png)}.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.map{background-image:url(../images/osu-navbar/lt-gray/resp-map@2x.png)}.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.findpeople{background-image:url(../images/osu-navbar/lt-gray/resp-findpeople@2x.png)}.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.webmail{background-image:url(../images/osu-navbar/lt-gray/resp-webmail@2x.png)}.l-region--osu-navbar.lt-gray #osu_navbar div.links ul li a.search{background-image:url(../images/osu-navbar/lt-gray/resp-search@2x.png)}.l-region--osu-navbar #osu_navbar div.links ul li .ui-accordion-content a,.l-region--osu-navbar #osu_navbar div.links ul li .ui-tabs-content a,.l-region--osu-navbar #osu_navbar div.links ul li a,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a,.ui-accordion-content .l-region--osu-navbar #osu_navbar div.links ul li a,.ui-tabs-content .l-region--osu-navbar #osu_navbar div.links ul li a{background-size:23px}.l-region--osu-navbar #osu_navbar .univ_name .ui-accordion-content a,.l-region--osu-navbar #osu_navbar .univ_name .ui-tabs-content a,.l-region--osu-navbar #osu_navbar .univ_name a,.l-region--osu-navbar.dk-gray #osu_navbar .univ_name a,.ui-accordion-content .l-region--osu-navbar #osu_navbar .univ_name a,.ui-tabs-content .l-region--osu-navbar #osu_navbar .univ_name a{background-size:contain}.l-region--osu-navbar #osu_navbar div.links ul li a.help,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.help{background-image:url(../images/osu-navbar/dk-gray/resp-help@2x.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.buckeyelink,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.buckeyelink{background-image:url(../images/osu-navbar/dk-gray/resp-buckeyelink@2x.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.map,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.map{background-image:url(../images/osu-navbar/dk-gray/resp-map@2x.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.findpeople,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.findpeople{background-image:url(../images/osu-navbar/dk-gray/resp-findpeople@2x.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.webmail,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.webmail{background-image:url(../images/osu-navbar/dk-gray/resp-webmail@2x.png)}.l-region--osu-navbar #osu_navbar div.links ul li a.search,.l-region--osu-navbar.dk-gray #osu_navbar div.links ul li a.search{background-image:url(../images/osu-navbar/dk-gray/resp-search@2x.png)}}@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min--moz-device-pixel-ratio:2),only screen and (-o-min-device-pixel-ratio:2 / 1),only screen and (min-device-pixel-ratio:2){.l-region--osu-navbar #osu_navbar .univ_name a{background-size:contain}.l-region--osu-navbar.lt-gray #osu_navbar .univ_name a{background-image:url(../images/osu-navbar/lt-gray/osu_name@2x.png)}.l-region--osu-navbar #osu_navbar .univ_name a,.l-region--osu-navbar.dk-gray #osu_navbar .univ_name a{background-image:url(../images/osu-navbar/dk-gray/osu_name@2x.png)}}.l-region--pre-footer-wrapper{line-height:0}.field--name-field-pre-footer-banner-image img{display:block;width:100%;margin:0}.node--article--teaser .field--name-field-featured-image,.section-tags a.feed-icon{display:none}.section-tags h1{font-weight:600}.section-tags .l-region--content{padding-bottom:40px}.section-tags .node-teaser{border-bottom:1px solid #c7c7c7}.page-user-login .l-main{padding-top:20px}.page-user-login h1{margin-bottom:20px}.page-user-login h2{font-family:proximanova,Helvetica,Arial,sans-serif}.page-user-login .login-box{background:#ebebeb;padding:20px 30px;margin-bottom:2em}.page-user-login .login-box h2{margin-top:0;margin-bottom:0;font-size:20px;font-weight:600}.page-user-login .login-box.osu h2{padding-bottom:10px}.page-user-login .login-box.osu a{margin-bottom:10px}.page-user-login .login-box.non-osu .ctools-collapsible-content{padding-top:2em}.page-user-login .login-box.non-osu #edit-actions{margin-top:20px}.user-profile{padding-bottom:20px}.user-profile .field--name-field-job-title{font-size:24px;font-size:2.4rem;font-weight:400;margin-bottom:30px}.user-profile .field--name-field-user-photo{float:right;margin:-40px 0 20px 30px}.user-profile .field--name-email{margin-top:20px}.field--name-field-user-photo img,.views-field-field-user-photo img{border:1px solid #8c8c8c}.view-wcm-news-client.view-display-id-teasers_pane{margin-bottom:10px;padding-bottom:40px;border-bottom:1px solid #c7c7c7}.view-wcm-news-client.view-display-id-teasers_pane .views-row{margin:30px 0;border-bottom:none}.view-wcm-news-client.view-display-id-teasers_pane .views-row.views-row-last{margin-bottom:0}@media (min-width:60em){.view-wcm-news-client.view-display-id-teasers_pane .views-row{width:95%}}.node--news-client-cached-article--teaser h3{font-size:30px;font-size:3rem}.node--news-client-cached-article--teaser .more-link{margin-top:10px;margin-bottom:0}.view-ocio-news-archive .field--name-title{margin-bottom:.6em}.view-ocio-news-archive .field--name-node-link{margin-top:1em}.view-ocio-news-archive .view-header .more-link{border-bottom:1px solid #b00;margin-bottom:1.4em;margin-top:0}.view-ocio-news-archive .view-header .more-link a{margin-top:-2em;font-weight:400;color:#2d2d2d;font-size:13px;float:right}.view-ocio-news-archive .view-header .more-link a:hover{text-decoration:none;color:#028da9}@media (min-width:47.5em){.node--article--teaser .field--name-field-featured-image{display:block;float:right;margin:0 0 40px 2em}}.node--article--teaser .more-link{float:left;margin-top:10px;margin-bottom:10px}.view-display-id-page .views-row,.view-display-id-teasers_pane .views-row{border-bottom:1px solid #c7c7c7;margin-bottom:30px}.view-display-id-page .views-row h2,.view-display-id-teasers_pane .views-row h2{font-size:32px;font-size:3.2rem;line-height:110%}.pane-ocio-news-archive-titles-pane .views-row{margin-bottom:.2em}.pane-ocio-news-archive-trio-image-pane h2.pane-title,.pane-ocio-news-archive-trio-pane h2.pane-title{font-size:28px;font-size:2.8rem;margin-bottom:.2em}.pane-ocio-news-archive-trio-image-pane .views-row,.pane-ocio-news-archive-trio-pane .views-row{margin-bottom:3em}.pane-ocio-news-archive-trio-image-pane .views-field-title h3,.pane-ocio-news-archive-trio-pane .views-field-title h3{font-size:22px;font-size:2.2rem;margin-top:.4em;line-height:120%;margin-bottom:.5em}.pane-ocio-news-archive-trio-image-pane .field--name-post-date,.pane-ocio-news-archive-trio-pane .field--name-post-date{font-weight:400;color:#666;font-size:15px;font-size:1.5rem}.pane-ocio-news-archive-trio-image-pane .views-field-field-ocio-body a,.pane-ocio-news-archive-trio-image-pane .views-field-field-ocio-body:hover,.pane-ocio-news-archive-trio-pane .views-field-field-ocio-body a,.pane-ocio-news-archive-trio-pane .views-field-field-ocio-body:hover{color:#2d2d2d;text-decoration:none}@media (min-width:47.5em){.pane-ocio-news-archive-trio-image-pane .views-row,.pane-ocio-news-archive-trio-pane .views-row{margin-bottom:1em;width:33.3%}.pane-ocio-news-archive-trio-image-pane .views-row:nth-child(3n+1),.pane-ocio-news-archive-trio-pane .views-row:nth-child(3n+1){float:left;padding-right:4%;clear:left}.pane-ocio-news-archive-trio-image-pane .views-row:nth-child(3n+2),.pane-ocio-news-archive-trio-pane .views-row:nth-child(3n+2){float:left;padding-left:2%;padding-right:2%}.pane-ocio-news-archive-trio-image-pane .views-row:nth-child(3n+3),.pane-ocio-news-archive-trio-pane .views-row:nth-child(3n+3){float:right;padding-left:4%}}.section-news .l-region--sidebar-2 h2.block__title{padding-top:20px}.view-display-id-archive_listing_block h3{font-size:18px;font-size:1.8rem;text-transform:uppercase;color:#666;margin-top:1.2em}.view-display-id-archive_listing_block .view-grouping-header{background:#d2d2d2;color:#2d2d2d;border-radius:0;border-color:#d2d2d2;font-weight:600;font-size:16px;font-size:1.6rem;margin-bottom:1px}.view-display-id-archive_listing_block .view-grouping-header:hover{background:#c2c2c2}.view-display-id-archive_listing_block .view-grouping-header:before{top:14px;left:12px}.view-display-id-archive_listing_block .view-grouping-content{margin-bottom:1px}.view-display-id-archive_listing_block .ui-accordion-header{background:#ebebeb!important;padding-left:2em!important;margin-top:1px!important}.view-display-id-archive_listing_block .ui-accordion-header a{font-size:16px;font-size:1.6rem;margin-left:16px}.view-display-id-archive_listing_block .ui-accordion-header.ui-state-hover{background-color:#d2d2d2!important}.view-display-id-archive_listing_block .ui-accordion-header .ui-accordion-header-icon{margin-left:18px}.view-display-id-archive_listing_block .ui-accordion .ui-accordion-content{padding:10px 30px 10px 32px!important;border:1px solid #ebebeb!important;background:#fff!important}.view-display-id-archive_listing_block .views-field-title{font-size:16px;font-size:1.6rem;margin-bottom:12px;line-height:120%}.view-display-id-archive_listing_block .views-field-title a.active{color:#b00;text-decoration:underline}.view-display-id-archive_listing_block .views-row-last .views-field-title{margin-bottom:0}.pane-ocio-news-archive-teasers-pane h2.pane-title{margin-bottom:30px}.l-main.lt-gray .view-display-id-archive_listing_block .view-grouping-header{background:#c2c2c2;border-color:#c2c2c2}.l-main.lt-gray .view-display-id-archive_listing_block .view-grouping-header:hover{background:#b8b8b8}.view-id-leadership_listing .views-field,.view-id-user_contact .views-field{font-size:15px;font-size:1.5rem;margin-bottom:5px;line-height:120%}.view-id-leadership_listing .views-field-realname h2,.view-id-leadership_listing .views-field-realname h3,.view-id-user_contact .views-field-realname h2,.view-id-user_contact .views-field-realname h3{font-size:21px;font-size:2.1rem}.view-id-leadership_listing .views-field-field-user-photo img,.view-id-user_contact .views-field-field-user-photo img{width:100%;height:auto}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group-header,.view-id-user_contact.view-display-id-panel_pane_1 .views-group-header,.view-id-wcm_media_gallery .views-group-header{margin-bottom:.4em;margin-top:1.4em;padding-bottom:.2em;color:#666}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group,.view-id-user_contact.view-display-id-panel_pane_1 .views-group,.view-id-wcm_media_gallery .views-group{clear:both}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row,.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row,.view-id-wcm_media_gallery .views-group .views-row{width:46%;margin-right:8%;float:left;margin-bottom:.75em;margin-top:.75em}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(2n+1),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(2n+1),.view-id-wcm_media_gallery .views-group .views-row:nth-child(2n+1){clear:left}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(2n+2),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(2n+2),.view-id-wcm_media_gallery .views-group .views-row:nth-child(2n+2){margin-right:0}@media (min-width:47.5em){.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row,.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(3n+1),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(3n+2),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(3n+3),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row,.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(3n+1),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(3n+2),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(3n+3),.view-id-wcm_media_gallery .views-group .views-row,.view-id-wcm_media_gallery .views-group .views-row:nth-child(3n+1),.view-id-wcm_media_gallery .views-group .views-row:nth-child(3n+2),.view-id-wcm_media_gallery .views-group .views-row:nth-child(3n+3){width:20.5%;margin-right:6%;margin-bottom:1em;margin-top:1em;float:left;clear:none}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+1),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+1),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+1){clear:both}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+4),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+4),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+4){margin-right:0}}@media (min-width:60em){.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row,.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+1),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+2),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+3),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+4),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row,.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+1),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+2),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+3),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+4),.view-id-wcm_media_gallery .views-group .views-row,.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+1),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+2),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+3),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+4){width:16%;margin-right:5%;float:left;clear:none}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(5n+1),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(5n+1),.view-id-wcm_media_gallery .views-group .views-row:nth-child(5n+1){clear:both}.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(5n+5),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(5n+5),.view-id-wcm_media_gallery .views-group .views-row:nth-child(5n+5){margin-right:0}}@media (min-width:82em){.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row,.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+1),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+2),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+3),.view-id-leadership_listing.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+4),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row,.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+1),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+2),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+3),.view-id-user_contact.view-display-id-panel_pane_1 .views-group .views-row:nth-child(4n+4),.view-id-wcm_media_gallery .views-group .views-row,.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+1),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+2),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+3),.view-id-wcm_media_gallery .views-group .views-row:nth-child(4n+4){margin-top:1.3em;margin-bottom:1.3em}}.pane-user-contact-panel-pane-2 .views-row{margin-top:20px;margin-bottom:30px}.pane-leadership-listing-panel-pane-2 .views-row{border-bottom:1px solid #ccc;padding:1em 0 0}.pane-leadership-listing-panel-pane-2 .views-row:after{content:"";display:table;clear:both}.pane-leadership-listing-panel-pane-2 .views-row.views-row-1{border-top:1px solid #ccc;margin-top:0}.pane-leadership-listing-panel-pane-2 .views-field-field-user-photo{margin-bottom:15px}.pane-leadership-listing-panel-pane-2 .views-field-field-user-photo img{width:100%;border:none}.pane-leadership-listing-panel-pane-2 .views-field-realname{font-size:32px;font-size:3.2rem;margin-top:0;margin-bottom:6px}.pane-leadership-listing-panel-pane-2 .views-field-field-job-title{font-size:20px;font-size:2rem;display:block;margin-bottom:8px}.pane-leadership-listing-panel-pane-2 .views-field-field-bio{margin-top:12px}.pane-leadership-listing-panel-pane-2 .more-link{margin-top:15px;font-size:14px}@media (min-width:47.5em){.pane-leadership-listing-panel-pane-2 .views-row{padding:1.5em 0 1em}.pane-leadership-listing-panel-pane-2 .views-row .views-field-field-user-photo{float:right;width:300px;margin:0 0 1em 2em}}@media (min-width:60em){.pane-leadership-listing-panel-pane-2 .views-row .views-field-field-user-photo{width:360px}}@media (min-width:82em){.pane-leadership-listing-panel-pane-2 .views-row{padding:1.8em 0 1em}.pane-leadership-listing-panel-pane-2 .views-row .text-grouping{width:58.5%}.pane-leadership-listing-panel-pane-2 .views-row .views-field-field-user-photo{width:39%;margin:0}.pane-leadership-listing-panel-pane-2 .views-row-odd .text-grouping{float:right}.pane-leadership-listing-panel-pane-2 .views-row-even .text-grouping,.pane-leadership-listing-panel-pane-2 .views-row-odd .views-field-field-user-photo{float:left}.pane-leadership-listing-panel-pane-2 .views-row-even .views-field-field-user-photo{float:right}}.views-table td.views-field *{margin:0}.views-exposed-widgets .views-exposed-widget .form-submit{margin-top:1.6em!important}.views-exposed-widgets .views-exposed-widget.views-submit-button{padding:0}.views-exposed-widgets .form-actions .description,.views-exposed-widgets .form-item .description{display:none}.view .ajax-progress,.views-exposed-form .ajax-progress{bottom:-1.75em;position:absolute;right:50%} \ No newline at end of file diff --git a/profiles/wcm_base/themes/wcm_omega/sass/base/_media.scss b/profiles/wcm_base/themes/wcm_omega/sass/base/_media.scss index df62d633fb0b92953b0730cc682a3cbe52ac77cd..192f086c0e04e88ced1f900b55f6711256e918a2 100644 --- a/profiles/wcm_base/themes/wcm_omega/sass/base/_media.scss +++ b/profiles/wcm_base/themes/wcm_omega/sass/base/_media.scss @@ -41,6 +41,9 @@ @if $type == "video" { width: 50%; } + @else { + max-width: 30%; + } } &.#{$prefix}-#{$type}#{$separator}right { @@ -51,6 +54,9 @@ @if $type == "video" { width: 50%; } + @else { + max-width: 30%; + } } &.#{$prefix}-#{$type}#{$separator}center { @@ -60,6 +66,10 @@ @if $type == "video" { width: 75%; } + @else { + max-width: 50%; + } + } &.#{$prefix}-#{$type}#{$separator}max { @@ -108,6 +118,7 @@ img, media { max-width: 100%; } + @include breakpoint($small, true) { .field { .media-element.media-youtube-video, @@ -122,6 +133,7 @@ img, media { margin: 0 auto; float: none; display: block; + max-width: 100%; } } } diff --git a/profiles/wcm_base/wcm_base.make b/profiles/wcm_base/wcm_base.make index a3c3920fb6292727ea4553354603c954b9110664..c516ab3b27df2535816e360e49b107e880dfdaf9 100644 --- a/profiles/wcm_base/wcm_base.make +++ b/profiles/wcm_base/wcm_base.make @@ -408,6 +408,11 @@ projects[wcm_news_client_display][download][type] = "git" projects[wcm_news_client_display][download][url] = git@code.osu.edu:ocio_odee_web/wcm_news_client_display.git projects[wcm_news_client_display][download][branch] = 7.x-1.x +projects[news_client][type] = module +projects[news_client][subdir] = custom +projects[news_client][download][type] = "git" +projects[news_client][download][url] = git@code.osu.edu:ocio_odee_web/news_client.git +projects[news_client][download][branch] = 7.x-1.x ;themes projects[ocio_omega_base][type] = theme @@ -489,7 +494,7 @@ projects[panopoly_pages][subdir] = panopoly projects[panopoly_search][version] = 1.43 projects[panopoly_search][subdir] = panopoly - +projects[panopoly_search][patch][2838075] = https://www.drupal.org/files/issues/panopoly_search-update-search-api-2863077-2.patch ; For running the automated tests.