Browse Source

a few more base modules

Bachir Soussi Chiadmi 7 years ago
parent
commit
027aa99b32
100 changed files with 11899 additions and 0 deletions
  1. 19 0
      base-profile.md
  2. 339 0
      sites/all/modules/contrib/admin/filter_perms/LICENSE.txt
  3. 13 0
      sites/all/modules/contrib/admin/filter_perms/filter_perms.info.yml
  4. 5 0
      sites/all/modules/contrib/admin/filter_perms/filter_perms.services.yml
  5. 261 0
      sites/all/modules/contrib/admin/filter_perms/src/Form/PermissionsForm.php
  6. 24 0
      sites/all/modules/contrib/admin/filter_perms/src/Form/PermissionsRoleSpecificForm.php
  7. 25 0
      sites/all/modules/contrib/admin/filter_perms/src/Routing/RouteSubscriber.php
  8. 339 0
      sites/all/modules/contrib/dev/devel/LICENSE.txt
  9. 51 0
      sites/all/modules/contrib/dev/devel/README.txt
  10. 25 0
      sites/all/modules/contrib/dev/devel/composer.json
  11. 8 0
      sites/all/modules/contrib/dev/devel/config/install/devel.settings.yml
  12. 9 0
      sites/all/modules/contrib/dev/devel/config/install/system.menu.devel.yml
  13. 43 0
      sites/all/modules/contrib/dev/devel/config/schema/devel.schema.yml
  14. 0 0
      sites/all/modules/contrib/dev/devel/css/devel-rtl.css
  15. 42 0
      sites/all/modules/contrib/dev/devel/css/devel.css
  16. 25 0
      sites/all/modules/contrib/dev/devel/devel.api.php
  17. 14 0
      sites/all/modules/contrib/dev/devel/devel.info.yml
  18. 30 0
      sites/all/modules/contrib/dev/devel/devel.install
  19. 5 0
      sites/all/modules/contrib/dev/devel/devel.libraries.yml
  20. 75 0
      sites/all/modules/contrib/dev/devel/devel.links.menu.yml
  21. 8 0
      sites/all/modules/contrib/dev/devel/devel.links.task.yml
  22. 626 0
      sites/all/modules/contrib/dev/devel/devel.module
  23. 14 0
      sites/all/modules/contrib/dev/devel/devel.permissions.yml
  24. 172 0
      sites/all/modules/contrib/dev/devel/devel.routing.yml
  25. 24 0
      sites/all/modules/contrib/dev/devel/devel.rules.inc
  26. 26 0
      sites/all/modules/contrib/dev/devel/devel.services.yml
  27. 42 0
      sites/all/modules/contrib/dev/devel/devel_generate/README.txt
  28. 25 0
      sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.batch.inc
  29. 13 0
      sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.info.yml
  30. 145 0
      sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.module
  31. 5 0
      sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.permissions.yml
  32. 2 0
      sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.routing.yml
  33. 4 0
      sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.services.yml
  34. 151 0
      sites/all/modules/contrib/dev/devel/devel_generate/drush/DevelGenerateUnishTest.php
  35. 196 0
      sites/all/modules/contrib/dev/devel/devel_generate/drush/devel_generate.drush.inc
  36. 86 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/Annotation/DevelGenerate.php
  37. 168 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/DevelGenerateBase.php
  38. 77 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/DevelGenerateBaseInterface.php
  39. 12 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/DevelGenerateException.php
  40. 62 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/DevelGeneratePermissions.php
  41. 31 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/DevelGeneratePluginManager.php
  42. 114 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/Form/DevelGenerateForm.php
  43. 506 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/ContentDevelGenerate.php
  44. 407 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/MenuDevelGenerate.php
  45. 267 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/TermDevelGenerate.php
  46. 191 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/UserDevelGenerate.php
  47. 175 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/VocabularyDevelGenerate.php
  48. 57 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/Routing/DevelGenerateRoutes.php
  49. 175 0
      sites/all/modules/contrib/dev/devel/devel_generate/src/Tests/DevelGenerateTest.php
  50. 14 0
      sites/all/modules/contrib/dev/devel/devel_generate/tests/modules/devel_generate_example/devel_generate_example.info.yml
  51. 1 0
      sites/all/modules/contrib/dev/devel/devel_generate/tests/modules/devel_generate_example/devel_generate_example.module
  52. 88 0
      sites/all/modules/contrib/dev/devel/devel_generate/tests/modules/devel_generate_example/src/Plugin/DevelGenerate/ExampleDevelGenerate.php
  53. 93 0
      sites/all/modules/contrib/dev/devel/devel_generate/tests/src/DevelGenerateManagerTest.php
  54. 42 0
      sites/all/modules/contrib/dev/devel/devel_node_access/README.txt
  55. 3 0
      sites/all/modules/contrib/dev/devel/devel_node_access/config/install/devel_node_access.settings.yml
  56. 15 0
      sites/all/modules/contrib/dev/devel/devel_node_access/config/schema/devel_node_access.schema.yml
  57. 5 0
      sites/all/modules/contrib/dev/devel/devel_node_access/css/devel_node_access.module.css
  58. 81 0
      sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.api.php
  59. 16 0
      sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.info.yml
  60. 7 0
      sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.install
  61. 64 0
      sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.js
  62. 7 0
      sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.libraries.yml
  63. 269 0
      sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.module
  64. 4 0
      sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.permissions.yml
  65. 135 0
      sites/all/modules/contrib/dev/devel/devel_node_access/src/Form/DnaForm.php
  66. 1263 0
      sites/all/modules/contrib/dev/devel/devel_node_access/src/Plugin/Block/DnaBlock.php
  67. 274 0
      sites/all/modules/contrib/dev/devel/drush/devel.drush.inc
  68. 38 0
      sites/all/modules/contrib/dev/devel/drush/develDrushTest.php
  69. 105 0
      sites/all/modules/contrib/dev/devel/drush/phpstorm.drush.inc
  70. 37 0
      sites/all/modules/contrib/dev/devel/kint/README.txt
  71. 13 0
      sites/all/modules/contrib/dev/devel/kint/kint.info.yml
  72. 65 0
      sites/all/modules/contrib/dev/devel/kint/kint.module
  73. 4 0
      sites/all/modules/contrib/dev/devel/kint/kint.permissions.yml
  74. 5 0
      sites/all/modules/contrib/dev/devel/kint/kint.services.yml
  75. 3 0
      sites/all/modules/contrib/dev/devel/kint/kint/.gitignore
  76. 836 0
      sites/all/modules/contrib/dev/devel/kint/kint/Kint.class.php
  77. 20 0
      sites/all/modules/contrib/dev/devel/kint/kint/LICENCE
  78. 141 0
      sites/all/modules/contrib/dev/devel/kint/kint/README.md
  79. 29 0
      sites/all/modules/contrib/dev/devel/kint/kint/composer.json
  80. 94 0
      sites/all/modules/contrib/dev/devel/kint/kint/config.default.php
  81. 335 0
      sites/all/modules/contrib/dev/devel/kint/kint/decorators/plain.php
  82. 319 0
      sites/all/modules/contrib/dev/devel/kint/kint/decorators/rich.php
  83. 176 0
      sites/all/modules/contrib/dev/devel/kint/kint/examples/overview.php
  84. 19 0
      sites/all/modules/contrib/dev/devel/kint/kint/inc/kintObject.class.php
  85. 608 0
      sites/all/modules/contrib/dev/devel/kint/kint/inc/kintParser.class.php
  86. 102 0
      sites/all/modules/contrib/dev/devel/kint/kint/inc/kintVariableData.class.php
  87. 150 0
      sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/classmethods.php
  88. 49 0
      sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/classstatics.php
  89. 400 0
      sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/color.php
  90. 69 0
      sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/fspath.php
  91. 19 0
      sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/json.php
  92. 60 0
      sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/microtime.php
  93. 22 0
      sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/objectiterateable.php
  94. 24 0
      sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/splobjectstorage.php
  95. 29 0
      sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/timestamp.php
  96. 25 0
      sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/xml.php
  97. 47 0
      sites/all/modules/contrib/dev/devel/kint/kint/parsers/objects/closure.php
  98. 35 0
      sites/all/modules/contrib/dev/devel/kint/kint/parsers/objects/smarty.php
  99. 70 0
      sites/all/modules/contrib/dev/devel/kint/kint/parsers/objects/splfileinfo.php
  100. 437 0
      sites/all/modules/contrib/dev/devel/kint/kint/view/base.js

+ 19 - 0
base-profile.md

@@ -16,3 +16,22 @@ drupal 8 base
 [a tester : configuration synchronizer](https://www.drupal.org/project/config_sync)
 
 [features](https://www.drupal.org/project/features)
+
+[filter permissions](https://www.drupal.org/project/filter_perms)
+
+### dev
+
+[devel](https://www.drupal.org/project/devel)
+
+### mail
+
+[maillog](https://www.drupal.org/project/maillog)
+
+### theme
+
+[extlink](https://www.drupal.org/project/extlink)
+
+
+### users
+
+[profile](https://www.drupal.org/project/profile)

+ 339 - 0
sites/all/modules/contrib/admin/filter_perms/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.

+ 13 - 0
sites/all/modules/contrib/admin/filter_perms/filter_perms.info.yml

@@ -0,0 +1,13 @@
+type: module
+name: 'Filter permissions'
+description: 'Provides role and module filters to simplify the user permissions page.'
+package: 'Administration'
+# core: 8.x
+dependencies:
+ - user
+
+# Information added by Drupal.org packaging script on 2016-07-27
+version: '8.x-1.x-dev'
+core: '8.x'
+project: 'filter_perms'
+datestamp: 1469646196

+ 5 - 0
sites/all/modules/contrib/admin/filter_perms/filter_perms.services.yml

@@ -0,0 +1,5 @@
+services:
+  filter_perms.route_subscriber:
+    class: Drupal\filter_perms\Routing\RouteSubscriber
+    tags:
+      - { name: event_subscriber }

+ 261 - 0
sites/all/modules/contrib/admin/filter_perms/src/Form/PermissionsForm.php

@@ -0,0 +1,261 @@
+<?php
+
+namespace Drupal\filter_perms\Form;
+
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
+use Drupal\user\Form\UserPermissionsForm;
+use Drupal\user\PermissionHandlerInterface;
+use Drupal\user\RoleStorageInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides an enhanced user permissions administration form.
+ */
+class PermissionsForm extends UserPermissionsForm {
+
+  /**
+   * Indicates that all options should be user for filter.
+   */
+  const ALL_OPTIONS = '-1';
+
+  /**
+   * The expirable key value store.
+   *
+   * @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
+   */
+  protected $keyValueExpirable;
+
+  /**
+   * Constructs a new PermissionsForm.
+   *
+   * @param \Drupal\user\PermissionHandlerInterface $permission_handler
+   *   The permission handler.
+   * @param \Drupal\user\RoleStorageInterface $role_storage
+   *   The role storage.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   * @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable
+   *   The key value expirable factory.
+   */
+  public function __construct(PermissionHandlerInterface $permission_handler, RoleStorageInterface $role_storage, ModuleHandlerInterface $module_handler, KeyValueStoreExpirableInterface $key_value_expirable) {
+    parent::__construct($permission_handler, $role_storage, $module_handler);
+
+    $this->keyValueExpirable = $key_value_expirable;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('user.permissions'),
+      $container->get('entity.manager')->getStorage('user_role'),
+      $container->get('module_handler'),
+      $container->get('keyvalue.expirable')->get('filter_perms_list')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    // Render role/permission overview:
+    $hide_descriptions = system_admin_compact_mode();
+
+    $form['system_compact_link'] = array(
+      '#id' => FALSE,
+      '#type' => 'system_compact_link',
+    );
+
+    $permissions = $this->permissionHandler->getPermissions();
+
+    $providers = array();
+    foreach ($permissions as $permission) {
+      $providers[$permission['provider']] = $permission['provider'];
+    }
+
+    $roles = $this->getRoles();
+
+    $defined_roles = array();
+    foreach ($roles as $role_name => $role) {
+      $defined_roles[$role_name] = $role->label();
+    }
+
+    $filter = $this->getFilterSettings();
+
+    $form['filters'] = array(
+      '#type' => 'details',
+      '#title' => $this->t('Permission Filters'),
+      '#open' => TRUE,
+    );
+    $form['filters']['container'] = array(
+      '#type' => 'container',
+      '#attributes' => array('class' => array('form--inline', 'clearfix')),
+    );
+    // Displays all user roles.
+    $form['filters']['container']['roles'] = array(
+      '#title' => $this->t('Roles to display'),
+      '#type' => 'select',
+      '#options' => array(self::ALL_OPTIONS => '--All Roles') + $defined_roles,
+      '#default_value' => $filter['roles'],
+      '#size' => 8,
+      '#multiple' => TRUE,
+    );
+    // Displays all modules which define permissions.
+    $form['filters']['container']['modules'] = array(
+      '#title' => $this->t('Modules to display'),
+      '#type' => 'select',
+      '#options' => array(self::ALL_OPTIONS => '--All Modules') + $providers,
+      '#default_value' => $filter['modules'],
+      '#size' => 8,
+      '#multiple' => TRUE,
+    );
+    $form['filters']['action'] = array('#type' => 'actions');
+    $form['filters']['action']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => $this->t('Filter Permissions'),
+      '#submit' => array('::submitFormFilter'),
+    );
+
+    $role_names = $role_permissions = $admin_roles = array();
+
+    foreach ($roles as $role_name => $role) {
+      if (in_array(self::ALL_OPTIONS, $filter['roles']) || in_array($role_name, $filter['roles'])) {
+        // Retrieve role names for columns.
+        $role_names[$role_name] = $role->label();
+        // Fetch permissions for the roles.
+        $role_permissions[$role_name] = $role->getPermissions();
+        $admin_roles[$role_name] = $role->isAdmin();
+      }
+    }
+
+    // Store $role_names for use when saving the data.
+    $form['role_names'] = array(
+      '#type' => 'value',
+      '#value' => $role_names,
+    );
+
+    $permissions_by_provider = array();
+    foreach ($permissions as $permission_name => $permission) {
+      if (in_array(self::ALL_OPTIONS, $filter['modules']) || in_array($permission['provider'], $filter['modules'])) {
+        $permissions_by_provider[$permission['provider']][$permission_name] = $permission;
+      }
+    }
+
+    $form['permissions'] = array(
+      '#type' => 'table',
+      '#header' => array($this->t('Permission')),
+      '#id' => 'permissions',
+      '#attributes' => ['class' => ['permissions', 'js-permissions']],
+      '#sticky' => TRUE,
+      '#empty' => $this->t('Please select at least one value from both the Roles and Modules select boxes above and then click the "Filter Permissions" button.'),
+    );
+
+    // Only build the rest of the form if there are any filter settings.
+    if (empty($role_names) || empty($permissions_by_provider)) {
+      return $form;
+    }
+
+    foreach ($role_names as $name) {
+      $form['permissions']['#header'][] = array(
+        'data' => $name,
+        'class' => array('checkbox'),
+      );
+    }
+
+    foreach ($permissions_by_provider as $provider => $permissions) {
+      // Module name.
+      $form['permissions'][$provider] = array(array(
+        '#wrapper_attributes' => array(
+          'colspan' => count($role_names) + 1,
+          'class' => array('module'),
+          'id' => 'module-' . $provider,
+        ),
+        '#markup' => $this->moduleHandler->getName($provider),
+      ));
+      foreach ($permissions as $perm => $perm_item) {
+        // Fill in default values for the permission.
+        $perm_item += array(
+          'description' => '',
+          'restrict access' => FALSE,
+          'warning' => !empty($perm_item['restrict access']) ? $this->t('Warning: Give to trusted roles only; this permission has security implications.') : '',
+        );
+        $form['permissions'][$perm]['description'] = array(
+          '#type' => 'inline_template',
+          '#template' => '<div class="permission"><span class="title">{{ title }}</span>{% if description or warning %}<div class="description">{% if warning %}<em class="permission-warning">{{ warning }}</em> {% endif %}{{ description }}</div>{% endif %}</div>',
+          '#context' => array(
+            'title' => $perm_item['title'],
+          ),
+        );
+        // Show the permission description.
+        if (!$hide_descriptions) {
+          $form['permissions'][$perm]['description']['#context']['description'] = $perm_item['description'];
+          $form['permissions'][$perm]['description']['#context']['warning'] = $perm_item['warning'];
+        }
+        foreach ($role_names as $rid => $name) {
+          $form['permissions'][$perm][$rid] = array(
+            '#title' => $name . ': ' . $perm_item['title'],
+            '#title_display' => 'invisible',
+            '#wrapper_attributes' => array(
+              'class' => array('checkbox'),
+            ),
+            '#type' => 'checkbox',
+            '#default_value' => in_array($perm, $role_permissions[$rid]) ? 1 : 0,
+            '#attributes' => array('class' => array('rid-' . $rid, 'js-rid-' . $rid)),
+            '#parents' => array($rid, $perm),
+          );
+          // Show a column of disabled but checked checkboxes.
+          if ($admin_roles[$rid]) {
+            $form['permissions'][$perm][$rid]['#disabled'] = TRUE;
+            $form['permissions'][$perm][$rid]['#default_value'] = TRUE;
+          }
+        }
+      }
+    }
+
+    $form['actions'] = array('#type' => 'actions');
+    $form['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => $this->t('Save permissions'),
+      '#button_type' => 'primary',
+    );
+
+    $form['#attached']['library'][] = 'user/drupal.user.permissions';
+
+    return $form;
+  }
+
+  /**
+   * Saves the roles and modules selection.
+   */
+  public function submitFormFilter(array &$form, FormStateInterface $form_state) {
+    $this->saveFilterSettings($form_state->getValue('roles'), $form_state->getValue('modules'));
+  }
+
+  /**
+   * Saves the filter settings for the current user.
+   *
+   * @param array $roles
+   *   The roles to filter by.
+   * @param array $modules
+   *   The modules to filter by.
+   */
+  protected function saveFilterSettings(array $roles, array $modules) {
+    $values = array('roles' => $roles, 'modules' => $modules);
+    $this->keyValueExpirable->setWithExpire($this->currentUser()->id(), $values, 3600);
+  }
+
+  /**
+   * Retrieve the filter settings for the current user.
+   *
+   * @return array
+   *   The filter setting for the current user.
+   */
+  protected function getFilterSettings() {
+    $default = array('roles' => array(), 'modules' => array());
+    return $this->keyValueExpirable->get($this->currentUser()->id(), $default);
+  }
+
+}

+ 24 - 0
sites/all/modules/contrib/admin/filter_perms/src/Form/PermissionsRoleSpecificForm.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace Drupal\filter_perms\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\user\RoleInterface;
+
+/**
+ * Provides the user permissions administration form for a specific role.
+ */
+class PermissionsRoleSpecificForm extends PermissionsForm {
+
+  /**
+   * {@inheritdoc}
+   *
+   * @param \Drupal\user\RoleInterface $user_role
+   *   The user role used for this form.
+   */
+  public function buildForm(array $form, FormStateInterface $form_state, RoleInterface $user_role = NULL) {
+    $this->saveFilterSettings((array) $user_role->id(), (array) self::ALL_OPTIONS);
+    return $this->redirect('user.admin_permissions');
+  }
+
+}

+ 25 - 0
sites/all/modules/contrib/admin/filter_perms/src/Routing/RouteSubscriber.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace Drupal\filter_perms\Routing;
+
+use Drupal\Core\Routing\RouteSubscriberBase;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * Listens to the dynamic route events.
+ */
+class RouteSubscriber extends RouteSubscriberBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function alterRoutes(RouteCollection $collection) {
+    if ($route = $collection->get('user.admin_permissions')) {
+      $route->setDefault('_form', '\Drupal\filter_perms\Form\PermissionsForm');
+    }
+    if ($route = $collection->get('entity.user_role.edit_permissions_form')) {
+      $route->setDefault('_form', '\Drupal\filter_perms\Form\PermissionsRoleSpecificForm');
+    }
+  }
+
+}

+ 339 - 0
sites/all/modules/contrib/dev/devel/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.

+ 51 - 0
sites/all/modules/contrib/dev/devel/README.txt

@@ -0,0 +1,51 @@
+Devel
+==========
+Devel module contains helper functions and pages for Drupal developers and inquisitive admins:
+
+ - A block for running custom PHP on a page
+ - A block for quickly accessing devel pages
+ - A block for masquerading as other users (useful for testing)
+ - A mail-system class which redirects outbound email to files
+ - Drush commands such as fn-hook, fn-event, ...
+ - Docs at https://api.drupal.org/api/devel
+ - more
+
+This module is safe to use on a production site. Just be sure to only grant
+'access development information' permission to developers.
+
+Devel Kint
+===================
+Provides a dpr() function, which pretty prints variables.
+Useful during development. Also see similar helpers like dpm(), dvm().
+
+Webprofiler
+==============
+Adds a debug bar at bottom of all pages with tons of useful information like a query list,
+cache hit/miss data, memory profiling, page speed, php info, session info, etc.
+
+Devel Generate
+=================
+Bulk creates nodes, users, comment, terms for development. Has Drush integration.
+
+Devel Node Access
+=================
+Prints the node_access records for a given node. Also offers hook_node_access_explain for all node access modules to implement.
+
+Devel Generate Extensions
+=========================
+Devel Images Provider [http://drupal.org/project/devel_image_provider] allows to configure external providers for images.
+
+Drush Unit Testing
+==================
+See develDrushTest.php for an example of unit testing of the Drush integration.
+This uses Drush's own test framework, based on PHPUnit. To run the tests, use
+run-tests-drush.sh. You may pass in any arguments that are valid for `phpunit`.
+
+Author/Maintainers
+======================
+- Moshe Weitzman <weitzman at tejasa DOT com> http://www.acquia.com
+- Hans Salvisberg <drupal at salvisberg DOT com>
+- Pedro Cambra https://drupal.org/user/122101/contact http://www.ymbra.com/
+- Juan Pablo Novillo https://www.drupal.org/u/juampynr
+- lussoluca https://www.drupal.org/u/lussoluca
+- willzyx https://www.drupal.org/u/willzyx

+ 25 - 0
sites/all/modules/contrib/dev/devel/composer.json

@@ -0,0 +1,25 @@
+{
+  "name": "drupal/devel",
+  "description": "Various blocks, pages, and functions for developers.",
+  "type": "drupal-module",
+  "homepage": "http://drupal.org/project/devel",
+  "authors": [
+    {
+      "name": "Moshe Weitzman",
+      "email": "weitzman@tejasa.com",
+      "homepage": "https://github.com/weitzman",
+      "role": "Maintainer"
+    }
+  ],
+  "support": {
+    "issues": "http://drupal.org/project/devel",
+    "irc": "irc://irc.freenode.org/drupal-contribute",
+    "source": "http://cgit.drupalcode.org/devel"
+  },
+  "license": "GPL-2.0+",
+  "minimum-stability": "dev",
+  "require": { },
+  "suggest": {
+    "symfony/var-dumper": "Pretty print complex values better with var-dumper available"
+  }
+}

+ 8 - 0
sites/all/modules/contrib/dev/devel/config/install/devel.settings.yml

@@ -0,0 +1,8 @@
+page_alter: FALSE
+raw_names: FALSE
+error_handlers:
+  1: 1
+rebuild_theme: FALSE
+debug_mail_file_format: '%to-%subject-%datetime.mail.txt'
+debug_mail_directory: 'temporary://devel-mails'
+devel_dumper: 'default'

+ 9 - 0
sites/all/modules/contrib/dev/devel/config/install/system.menu.devel.yml

@@ -0,0 +1,9 @@
+id: devel
+label: 'Development'
+description: 'Links related to Devel module.'
+langcode: en
+locked: true
+dependencies:
+  enforced:
+    module:
+      - devel

+ 43 - 0
sites/all/modules/contrib/dev/devel/config/schema/devel.schema.yml

@@ -0,0 +1,43 @@
+# Schema for the configuration files of the Devel module.
+
+devel.settings:
+  type: config_object
+  label: 'Devel settings'
+  mapping:
+    page_alter:
+      type: boolean
+      label: 'Page alter'
+    raw_names:
+      type: boolean
+      label: 'Raw names'
+    error_handlers:
+      label: 'Error handlers'
+      type: sequence
+      sequence:
+        type: integer
+    rebuild_theme:
+      type: boolean
+      label: 'Rebuild theme information'
+    debug_mail_file_format:
+      type: string
+      label: 'Mail debug file format'
+    debug_mail_directory:
+      type: string
+      label: 'Mail debug directory'
+    devel_dumper:
+      type: string
+      label: 'Devel variable dumper'
+
+block.settings.devel_switch_user:
+  type: block_settings
+  label: 'Switch user block'
+  mapping:
+    list_size:
+      type: integer
+      label: 'List size'
+    include_anon:
+      type: boolean
+      label: 'Include Anonymous user'
+    show_form:
+      type: boolean
+      label: 'Show search form'

+ 0 - 0
sites/all/modules/contrib/dev/devel/css/devel-rtl.css


+ 42 - 0
sites/all/modules/contrib/dev/devel/css/devel.css

@@ -0,0 +1,42 @@
+/**
+ * Dumpers
+ */
+.devel-dumper .details-wrapper{
+  max-height: 450px;
+  margin-right: 3px;
+  overflow: auto;
+}
+
+/**
+ * Switch User block
+ */
+#content .block-devel-switch-user ul.links,
+#footer .block-devel-switch-user ul.links {
+  margin-left: 0;
+  padding-left: 0;
+}
+
+#content .block-devel-switch-user ul.links li,
+#footer .block-devel-switch-user ul.links li {
+  display: inline-block;
+  margin-left: 0;
+  margin-right: 1.5em;
+  padding-right: 0;
+}
+
+#footer .block-devel-switch-user ul.links li a {
+  margin: 0;
+  padding: 0;
+  border: none;
+}
+
+#content #devel-switch-user-form .form-item-username,
+#footer #devel-switch-user-form .form-item-username {
+  float: left;
+  margin-right: 2em;
+}
+
+#content #devel-switch-user-form .button-primary,
+#footer #devel-switch-user-form .button-primary {
+  margin-top: 1em;
+}

+ 25 - 0
sites/all/modules/contrib/dev/devel/devel.api.php

@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Hooks for the devel module.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Alter devel dumper information declared by other modules.
+ *
+ * @param $info
+ *   Devel dumper information to alter.
+ */
+function hook_devel_dumper_info_alter(&$info) {
+  $info['default']['label'] = 'Altered label';
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */

+ 14 - 0
sites/all/modules/contrib/dev/devel/devel.info.yml

@@ -0,0 +1,14 @@
+type: module
+name: Devel
+description: 'Various blocks, pages, and functions for developers.'
+package: Development
+# core: 8.x
+configure: devel.admin_settings
+tags:
+ - developer
+
+# Information added by Drupal.org packaging script on 2016-09-03
+version: '8.x-1.0-alpha1+23-dev'
+core: '8.x'
+project: 'devel'
+datestamp: 1472897643

+ 30 - 0
sites/all/modules/contrib/dev/devel/devel.install

@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the devel module.
+ */
+
+/**
+ * Set the default devel dumper plugin.
+ */
+function devel_update_8001() {
+  $kint_enabled = \Drupal::moduleHandler()->moduleExists('kint');
+
+  $default_dumper = $kint_enabled ? 'kint' : 'default';
+
+  // Set the default dumper plugin to kint if kint module is available.
+  \Drupal::configFactory()->getEditable('devel.settings')
+    ->set('devel_dumper', $default_dumper)
+    ->save(TRUE);
+}
+
+/**
+ * Add enforced dependencies to system.menu.devel
+ */
+function devel_update_8002() {
+  $config = \Drupal::configFactory()->getEditable('system.menu.devel');
+  $dependencies = $config->get('dependencies');
+  $dependencies['enforced']['module'][] = 'devel';
+  $config->set('dependencies', $dependencies)->save(TRUE);
+}

+ 5 - 0
sites/all/modules/contrib/dev/devel/devel.libraries.yml

@@ -0,0 +1,5 @@
+devel:
+  version: 0
+  css:
+    theme:
+      css/devel.css: {}

+ 75 - 0
sites/all/modules/contrib/dev/devel/devel.links.menu.yml

@@ -0,0 +1,75 @@
+devel.admin_settings:
+  title: 'Devel settings'
+  description: 'Helper functions, pages, and blocks to assist Drupal developers. The devel blocks can be managed via the block administration page.'
+  route_name: devel.admin_settings
+  parent: 'system.admin_config_development'
+devel.admin_settings_link:
+  title: 'Devel settings'
+  description: 'Helper functions, pages, and blocks to assist Drupal developers. The devel blocks can be managed via the block administration page.'
+  route_name: devel.admin_settings
+  menu_name: devel
+devel.configs_list:
+  title: 'Config editor'
+  description: 'Edit configuration.'
+  route_name: devel.configs_list
+  menu_name: devel
+devel.reinstall:
+  title: 'Reinstall Modules'
+  route_name: devel.reinstall
+  menu_name: devel
+  class: \Drupal\devel\Plugin\Menu\DestinationMenuLink
+devel.menu_rebuild:
+  title: 'Rebuild Menu'
+  route_name: devel.menu_rebuild
+  menu_name: devel
+  class: \Drupal\devel\Plugin\Menu\DestinationMenuLink
+devel.menu_item:
+  title: 'Menu Item'
+  route_name: devel.menu_item
+  menu_name: devel
+  class: \Drupal\devel\Plugin\Menu\MenuItemMenuLink
+devel.state_system_page:
+  title: 'State editor'
+  description: 'Edit state system values.'
+  route_name: devel.state_system_page
+  menu_name: devel
+devel.theme_registry:
+  title: 'Theme registry'
+  route_name: devel.theme_registry
+  menu_name: devel
+devel.entity_info_page:
+  title: 'Entity Info'
+  route_name: devel.entity_info_page
+#  parent: 'system.admin_config_development'
+  menu_name: devel
+devel.field_info_page:
+  title: 'Field Info'
+  route_name: devel.field_info_page
+#  parent: 'system.admin_config_development'
+  menu_name: devel
+devel.phpinfo:
+  title: 'PHPinfo()'
+  route_name: system.php
+  menu_name: devel
+devel.execute_php:
+  title: 'Execute PHP'
+  route_name: devel.execute_php
+  menu_name: devel
+devel.session:
+  title: 'View Session'
+  route_name: devel.session
+  menu_name: devel
+devel.elements_page:
+  title: 'Element Info'
+  route_name: devel.elements_page
+  menu_name: devel
+devel.cache_clear:
+  title: 'Cache clear'
+  route_name: devel.cache_clear
+  menu_name: devel
+  class: \Drupal\devel\Plugin\Menu\DestinationMenuLink
+devel.run_cron:
+  title: 'Run cron'
+  route_name: devel.run_cron
+  menu_name: devel
+  class: \Drupal\devel\Plugin\Menu\DestinationMenuLink

+ 8 - 0
sites/all/modules/contrib/dev/devel/devel.links.task.yml

@@ -0,0 +1,8 @@
+devel.entities:
+  class: \Drupal\Core\Menu\LocalTaskDefault
+  deriver: \Drupal\devel\Plugin\Derivative\DevelLocalTask
+devel.admin_settings:
+  title: 'Settings'
+  route_name: devel.admin_settings
+  base_route: devel.admin_settings
+  weight: 0

+ 626 - 0
sites/all/modules/contrib/dev/devel/devel.module

@@ -0,0 +1,626 @@
+<?php
+
+/**
+ * @file
+ * This module holds functions useful for Drupal development.
+ * Please contribute!
+ */
+
+define('DEVEL_ERROR_HANDLER_NONE', 0);
+define('DEVEL_ERROR_HANDLER_STANDARD', 1);
+define('DEVEL_ERROR_HANDLER_BACKTRACE_KINT', 2);
+define('DEVEL_ERROR_HANDLER_BACKTRACE_DPM', 4);
+
+define('DEVEL_MIN_TEXTAREA', 50);
+
+use Drupal\comment\CommentInterface;
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Query\AlterableInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Logger\RfcLogLevel;
+use Drupal\Core\Render\Element;
+use Drupal\Core\Utility\Error;
+
+/**
+ * Implements hook_help().
+ */
+function devel_help($route_name) {
+  switch ($route_name) {
+    case 'devel.reinstall':
+      $output = '<p>' . t('<strong>Warning</strong> - will delete your module tables and configuration.') . '</p>';
+      $output .= '<p>' . t('Uninstall and then install the selected modules. <code>hook_uninstall()</code> and <code>hook_install()</code> will be executed and the schema version number will be set to the most recent update number.') . '</p>';
+      return $output;
+
+    case 'devel/session':
+      return '<p>' . t('Here are the contents of your <code>$_SESSION</code> variable.') . '</p>';
+
+    case 'devel.state_system_page':
+      return '<p>' . t('This is a list of state variables and their values. For more information read online documentation of <a href=":documentation">State API in Drupal 8</a>.', array(':documentation' => "https://www.drupal.org/developing/api/8/state")) . '</p>';
+
+  }
+}
+
+/**
+ * Implements hook_entity_type_alter().
+ */
+function devel_entity_type_alter(array &$entity_types) {
+  /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
+  foreach ($entity_types as $entity_type_id => $entity_type) {
+    if ($entity_type->hasViewBuilderClass() && $entity_type->hasLinkTemplate('canonical')) {
+      $entity_type->setLinkTemplate('devel-render', "/devel/$entity_type_id/{{$entity_type_id}}/render");
+    }
+    if (($entity_type->getFormClass('default') || $entity_type->getFormClass('edit')) && $entity_type->hasLinkTemplate('edit-form')) {
+      $entity_type->setLinkTemplate('devel-load', "/devel/$entity_type_id/{{$entity_type_id}}");
+    }
+  }
+}
+
+/**
+ * Implements hook_entity_operation().
+ */
+function devel_entity_operation(EntityInterface $entity) {
+  $operations = array();
+  if (\Drupal::currentUser()->hasPermission('access devel information')) {
+    if ($entity->hasLinkTemplate('devel-load')) {
+      $operations['devel'] = array(
+        'title' => t('Devel'),
+        'weight' => 100,
+        'url' => $entity->toUrl('devel-load'),
+      );
+    }
+    elseif ($entity->hasLinkTemplate('devel-render')) {
+      $operations['devel'] = array(
+        'title' => t('Devel'),
+        'weight' => 100,
+        'url' => $entity->toUrl('devel-render'),
+      );
+    }
+  }
+  return $operations;
+}
+
+/**
+ * Sets message.
+ */
+function devel_set_message($msg, $type = NULL) {
+  if (function_exists('drush_log')) {
+    drush_log($msg, $type);
+  }
+  else {
+    drupal_set_message($msg, $type, TRUE);
+  }
+}
+
+/**
+ * Gets error handlers.
+ */
+function devel_get_handlers() {
+  $error_handlers = \Drupal::config('devel.settings')->get('error_handlers');
+  if (!empty($error_handlers)) {
+    unset($error_handlers[DEVEL_ERROR_HANDLER_NONE]);
+  }
+  return $error_handlers;
+}
+
+/**
+ * Sets a new error handler or restores the prior one.
+ */
+function devel_set_handler($handlers) {
+  if (empty($handlers)) {
+    restore_error_handler();
+  }
+  elseif (count($handlers) == 1 && isset($handlers[DEVEL_ERROR_HANDLER_STANDARD])) {
+    // Do nothing.
+  }
+  else {
+    set_error_handler('backtrace_error_handler');
+  }
+}
+
+/**
+ * Displays backtrace showing the route of calls to the current error.
+ *
+ * @param int $error_level
+ *   The level of the error raised.
+ * @param string $message
+ *   The error message.
+ * @param string $filename
+ *   The filename that the error was raised in.
+ * @param int $line
+ *   The line number the error was raised at.
+ * @param array $context
+ *   An array that points to the active symbol table at the point the error
+ *   occurred.
+ */
+function backtrace_error_handler($error_level, $message, $filename, $line, $context) {
+  // Hide stack trace and parameters from unqualified users.
+  if (!\Drupal::currentUser()->hasPermission('access devel information')) {
+    // Do what core does in bootstrap.inc and errors.inc.
+    // (We need to duplicate the core code here rather than calling it
+    // to avoid having the backtrace_error_handler() on top of the call stack.)
+    if ($error_level & error_reporting()) {
+      $types = drupal_error_levels();
+      list($severity_msg, $severity_level) = $types[$error_level];
+      $backtrace = debug_backtrace();
+      $caller = Error::getLastCaller($backtrace);
+
+      // We treat recoverable errors as fatal.
+      _drupal_log_error(array(
+        '%type' => isset($types[$error_level]) ? $severity_msg : 'Unknown error',
+        '@message' => $message,
+        '%function' => $caller['function'],
+        '%file' => $caller['file'],
+        '%line' => $caller['line'],
+        'severity_level' => $severity_level,
+        'backtrace' => $backtrace,
+      ), $error_level == E_RECOVERABLE_ERROR);
+    }
+
+    return;
+  }
+
+  // Don't respond to the error if it was suppressed with a '@'
+  if (error_reporting() == 0) {
+    return;
+  }
+
+  // Don't respond to warning caused by ourselves.
+  if (preg_match('#Cannot modify header information - headers already sent by \\([^\\)]*[/\\\\]devel[/\\\\]#', $message)) {
+    return;
+  }
+
+  if ($error_level & error_reporting()) {
+    // Only write each distinct NOTICE message once, as repeats do not give any
+    // further information and can choke the page output.
+    if ($error_level == E_NOTICE) {
+      static $written = array();
+      if (!empty($written[$line][$filename][$message])) {
+        return;
+      }
+      $written[$line][$filename][$message] = TRUE;
+    }
+
+    $types = drupal_error_levels();
+    list($severity_msg, $severity_level) = $types[$error_level];
+
+    $backtrace = debug_backtrace();
+    $caller = Error::getLastCaller($backtrace);
+    $variables = array(
+      '%type' => isset($types[$error_level]) ? $severity_msg : 'Unknown error',
+      '@message' => $message,
+      '%function' => $caller['function'],
+      '%file' => $caller['file'],
+      '%line' => $caller['line'],
+    );
+    $msg = t('%type: @message in %function (line %line of %file).', $variables);
+
+    // Show message if error_level is ERROR_REPORTING_DISPLAY_SOME or higher.
+    // (This is Drupal's error_level, which is different from $error_level,
+    // and we purposely ignore the difference between _SOME and _ALL,
+    // see #970688!)
+    if (\Drupal::config('system.logging')->get('error_level') != 'hide') {
+      $error_handlers = devel_get_handlers();
+      if (!empty($error_handlers[DEVEL_ERROR_HANDLER_STANDARD])) {
+        drupal_set_message($msg, ($severity_level <= RfcLogLevel::NOTICE ? 'error' : 'warning'), TRUE);
+      }
+      if (!empty($error_handlers[DEVEL_ERROR_HANDLER_BACKTRACE_KINT])) {
+        print kprint_r(ddebug_backtrace(TRUE, 1), $return = TRUE, $msg);
+      }
+      if (!empty($error_handlers[DEVEL_ERROR_HANDLER_BACKTRACE_DPM])) {
+        dpm(ddebug_backtrace(TRUE, 1), $msg, 'warning');
+      }
+    }
+
+    \Drupal::logger('php')->log($severity_level, $msg);
+  }
+}
+
+/**
+ * Implements hook_page_attachments_alter().
+ */
+function devel_page_attachments_alter(&$page) {
+  if (\Drupal::currentUser()->hasPermission('access devel information') && \Drupal::config('devel.settings')->get('page_alter')) {
+    dpm($page, 'page');
+  }
+}
+
+/**
+ * Prints an object using either Kint (if enabled) or devel_print_object().
+ *
+ * @param array|object $object
+ *   An array or object to print.
+ * @param string $prefix
+ * @todo: this parameter is not needed with Kint.
+ *   Prefix for output items.
+ *
+ * @deprecated in Devel 8.x-dev, will be removed before Devel 8.0.
+ *   Use kpr() or devel.dumper service instead.
+ *
+ * @TODO remove in https://www.drupal.org/node/2703343
+ */
+function kdevel_print_object($object, $prefix = NULL) {
+  return kpr($object, TRUE, $prefix);
+}
+
+/**
+ * Wrapper for DevelDumperManager::dump().
+ *
+ * Calls the http://www.firephp.org/ fb() function if it is found.
+ *
+ * @see \Drupal\devel\DevelDumperManager::dump()
+ */
+function dfb() {
+  $args = func_get_args();
+  \Drupal::service('devel.dumper')->dump($args, NULL, 'firephp');
+}
+
+/**
+ * Wrapper for DevelDumperManager::dump().
+ *
+ * Calls dfb() to output a backtrace.
+ *
+ * @see \Drupal\devel\DevelDumperManager::dump()
+ */
+function dfbt($label) {
+  \Drupal::service('devel.dumper')->dump(FirePHP::TRACE, $label, 'firephp');
+}
+
+/**
+ * Wrapper for DevelDumperManager::dump().
+ *
+ * Wrapper for ChromePHP Class log method.
+ *
+ * @see \Drupal\devel\DevelDumperManager::dump()
+ */
+function dcp() {
+  $args = func_get_args();
+  \Drupal::service('devel.dumper')->dump($args, NULL, 'chromephp');
+}
+
+if (!function_exists('dd')) {
+  /**
+   * Wrapper for DevelDumperManager::debug().
+   *
+   * @see \Drupal\devel\DevelDumperManager::debug()
+   */
+  function dd($data, $label = NULL) {
+    return \Drupal::service('devel.dumper')->debug($data, $label, 'default');
+  }
+}
+
+/**
+ * Wrapper for DevelDumperManager::message().
+ *
+ * Prints a variable to the 'message' area of the page.
+ *
+ * Uses drupal_set_message().
+ *
+ * @param $input
+ *   An arbitrary value to output.
+ * @param string $name
+ *   Optional name for identifying the output.
+ * @param string $type
+ *   Optional message type for drupal_set_message(), defaults to 'status'.
+ *
+ * @return input
+ *   The unaltered input value.
+ *
+ * @see \Drupal\devel\DevelDumperManager::message()
+ */
+function dpm($input, $name = NULL, $type = 'status') {
+  \Drupal::service('devel.dumper')->message($input, $name, $type);
+  return $input;
+}
+
+/**
+ * Wrapper for DevelDumperManager::message().
+ *
+ * Displays a Variable::export() variable to the 'message' area of the page.
+ *
+ * Uses drupal_set_message().
+ *
+ * @param $input
+ *   An arbitrary value to output.
+ * @param string $name
+ *   Optional name for identifying the output.
+ *
+ * @return input
+ *   The unaltered input value.
+ *
+ * @see \Drupal\devel\DevelDumperManager::message()
+ */
+function dvm($input, $name = NULL) {
+  \Drupal::service('devel.dumper')->message($input, $name, 'status', 'drupal_variable');
+  return $input;
+}
+
+/**
+ * An alias for dpm(), for historic reasons.
+ */
+function dsm($input, $name = NULL) {
+  return dpm($input, $name);
+}
+
+/**
+ * Wrapper for DevelDumperManager::dumpOrExport().
+ *
+ * An alias for the devel.dumper service. Saves carpal tunnel syndrome.
+ *
+ * @see \Drupal\devel\DevelDumperManager::dumpOrExport()
+ */
+function dpr($input, $export = FALSE, $name = NULL) {
+  return \Drupal::service('devel.dumper')->dumpOrExport($input, $name, $export, 'default');
+}
+
+/**
+ * Wrapper for DevelDumperManager::dumpOrExport().
+ *
+ * An alias for devel_dump(). Saves carpal tunnel syndrome.
+ *
+ * @see \Drupal\devel\DevelDumperManager::dumpOrExport()
+ */
+function kpr($input, $export = FALSE, $name = NULL) {
+  return \Drupal::service('devel.dumper')->dumpOrExport($input, $name, $export);
+}
+
+/**
+ * Kint print.
+ *
+ * @deprecated in Devel 8.x-dev, will be removed before Devel 8.0.
+ *   Use kpr() or devel.dumper service instead.
+ *
+ * @TODO remove in https://www.drupal.org/node/2703343
+ */
+function kprint_r($input, $export = FALSE, $name = NULL, $function = 'print_r') {
+  return kpr($input, $export, $name);
+}
+
+/**
+ * Wrapper for DevelDumperManager::dumpOrExport().
+ *
+ * Like dpr(), but uses Variable::export() instead.
+ *
+ * @see \Drupal\devel\DevelDumperManager::dumpOrExport()
+ */
+function dvr($input, $export = FALSE, $name = NULL) {
+  return \Drupal::service('devel.dumper')->dumpOrExport($input, $name, $export, 'drupal_variable');
+}
+
+/**
+ * Prints the arguments passed into the current function.
+ */
+function dargs($always = TRUE) {
+  static $printed;
+  if ($always || !$printed) {
+    $bt = debug_backtrace();
+    print kdevel_print_object($bt[1]['args']);
+    $printed = TRUE;
+  }
+}
+
+/**
+ * Prints a SQL string from a DBTNG Select object. Includes quoted arguments.
+ *
+ * @param object $query
+ *   An object that implements the SelectInterface interface.
+ * @param boolean $return
+ *   Whether to return the string. Default is FALSE, meaning to print it
+ *   and return $query instead.
+ * @param string $name
+ *   Optional name for identifying the output.
+ *
+ * @return object|string
+ *   The $query object, or the query string if $return was TRUE.
+ */
+function dpq($query, $return = FALSE, $name = NULL) {
+  if (\Drupal::currentUser()->hasPermission('access devel information')) {
+    if (method_exists($query, 'preExecute')) {
+      $query->preExecute();
+    }
+    $sql = (string) $query;
+    $quoted = array();
+    $connection = Database::getConnection();
+    foreach ((array) $query->arguments() as $key => $val) {
+      $quoted[$key] = is_null($val) ? 'NULL' : $connection->quote($val);
+    }
+    $sql = strtr($sql, $quoted);
+    if ($return) {
+      return $sql;
+    }
+    dpm($sql, $name);
+  }
+  return ($return ? NULL : $query);
+}
+
+/**
+ * Prints a renderable array element to the screen using kprint_r().
+ *
+ * #pre_render and/or #post_render pass-through callback for kprint_r().
+ *
+ * @todo Investigate appending to #suffix.
+ * @todo Investigate label derived from #id, #title, #name, and #theme.
+ */
+function devel_render() {
+  $args = func_get_args();
+  // #pre_render and #post_render pass the rendered $element as last argument.
+  kprint_r(end($args));
+  // #pre_render and #post_render expect the first argument to be returned.
+  return reset($args);
+}
+
+/**
+ * Prints the function call stack.
+ *
+ * @param $return
+ *   Pass TRUE to return the formatted backtrace rather than displaying it in
+ *   the browser via kprint_r().
+ * @param $pop
+ *   How many items to pop from the top of the stack; useful when calling from
+ *   an error handler.
+ * @param $options
+ *   Options to pass on to PHP's debug_backtrace().
+ *
+ * @return string|NULL
+ *   The formatted backtrace, if requested, or NULL.
+ *
+ * @see http://php.net/manual/en/function.debug-backtrace.php
+ */
+function ddebug_backtrace($return = FALSE, $pop = 0, $options = DEBUG_BACKTRACE_PROVIDE_OBJECT) {
+  if (\Drupal::currentUser()->hasPermission('access devel information')) {
+    $backtrace = debug_backtrace($options);
+    while ($pop-- > 0) {
+      array_shift($backtrace);
+    }
+    $counter = count($backtrace);
+    $path = $backtrace[$counter - 1]['file'];
+    $path = substr($path, 0, strlen($path) - 10);
+    $paths[$path] = strlen($path) + 1;
+    $paths[DRUPAL_ROOT] = strlen(DRUPAL_ROOT) + 1;
+    $nbsp = "\xC2\xA0";
+
+    // Show message if error_level is ERROR_REPORTING_DISPLAY_SOME or higher.
+    // (This is Drupal's error_level, which is different from $error_level,
+    // and we purposely ignore the difference between _SOME and _ALL,
+    // see #970688!)
+    if (\Drupal::config('system.logging')->get('error_level') != 'hide') {
+      while (!empty($backtrace)) {
+        $call = array();
+        if (isset($backtrace[0]['file'])) {
+          $call['file'] = $backtrace[0]['file'];
+          foreach ($paths as $path => $len) {
+            if (strpos($backtrace[0]['file'], $path) === 0) {
+              $call['file'] = substr($backtrace[0]['file'], $len);
+            }
+          }
+          $call['file'] .= ':' . $backtrace[0]['line'];
+        }
+        if (isset($backtrace[1])) {
+          if (isset($backtrace[1]['class'])) {
+            $function = $backtrace[1]['class'] . $backtrace[1]['type'] . $backtrace[1]['function'] . '()';
+          }
+          else {
+            $function = $backtrace[1]['function'] . '()';
+          }
+          $backtrace[1] += array('args' => array());
+          foreach ($backtrace[1]['args'] as $key => $value) {
+            $call['args'][$key] = $value;
+          }
+        }
+        else {
+          $function = 'main()';
+          $call['args'] = $_GET;
+        }
+        $nicetrace[($counter <= 10 ? $nbsp : '') . --$counter . ': ' . $function] = $call;
+        array_shift($backtrace);
+      }
+      if ($return) {
+        return $nicetrace;
+      }
+      kprint_r($nicetrace);
+    }
+  }
+}
+
+/*
+ * Migration-related functions.
+ */
+
+/**
+ * Regenerates the data in node_comment_statistics table.
+ * Technique - http://www.artfulsoftware.com/infotree/queries.php?&bw=1280#101
+ *
+ * @return void
+ */
+function devel_rebuild_node_comment_statistics() {
+  // Empty table.
+  db_truncate('node_comment_statistics')->execute();
+
+  // TODO: DBTNG. Ignore keyword is Mysql only? Is only used in the rare case
+  // when two comments on the same node share same timestamp.
+  $sql = "
+    INSERT IGNORE INTO {node_comment_statistics} (nid, cid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) (
+      SELECT c.nid, c.cid, c.created, c.name, c.uid, c2.comment_count FROM {comment} c
+      JOIN (
+        SELECT c.nid, MAX(c.created) AS created, COUNT(*) AS comment_count FROM {comment} c WHERE status = 1 GROUP BY c.nid
+      ) AS c2 ON c.nid = c2.nid AND c.created = c2.created
+    )";
+  db_query($sql, array(':published' => CommentInterface::PUBLISHED));
+
+  // Insert records into the node_comment_statistics for nodes that are missing.
+  $query = db_select('node', 'n');
+  $query->leftJoin('node_comment_statistics', 'ncs', 'ncs.nid = n.nid');
+  $query->addField('n', 'changed', 'last_comment_timestamp');
+  $query->addField('n', 'uid', 'last_comment_uid');
+  $query->addField('n', 'nid');
+  $query->addExpression('0', 'comment_count');
+  $query->addExpression('NULL', 'last_comment_name');
+  $query->isNull('ncs.comment_count');
+
+  db_insert('node_comment_statistics', array('return' => Database::RETURN_NULL))
+    ->from($query)
+    ->execute();
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * Adds mouse-over hints on the Permissions page to display
+ * language-independent machine names and module base names.
+ *
+ * @see \Drupal\user\Form\UserPermissionsForm::buildForm()
+ */
+function devel_form_user_admin_permissions_alter(&$form, FormStateInterface $form_state) {
+  if (\Drupal::currentUser()->hasPermission('access devel information') && \Drupal::config('devel.settings')->get('raw_names')) {
+    foreach (Element::children($form['permissions']) as $key) {
+      if (isset($form['permissions'][$key][0])) {
+        $form['permissions'][$key][0]['#wrapper_attributes']['title'] = $key;
+      }
+      elseif(isset($form['permissions'][$key]['description'])) {
+        $form['permissions'][$key]['description']['#wrapper_attributes']['title']  = $key;
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * Adds mouse-over hints on the Modules page to display module base names.
+ *
+ * @see \Drupal\system\Form\ModulesListForm::buildForm()
+ * @see theme_system_modules_details()
+ */
+function devel_form_system_modules_alter(&$form, FormStateInterface $form_state) {
+  if (\Drupal::currentUser()->hasPermission('access devel information') && \Drupal::config('devel.settings')->get('raw_names', FALSE) && isset($form['modules']) && is_array($form['modules'])) {
+    foreach (Element::children($form['modules']) as $group) {
+      if (is_array($form['modules'][$group])) {
+        foreach (Element::children($form['modules'][$group]) as $key) {
+          if (isset($form['modules'][$group][$key]['name']['#markup'])) {
+            $form['modules'][$group][$key]['name']['#markup'] = '<span title="' . $key . '">' . $form['modules'][$group][$key]['name']['#markup'] . '</span>';
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_query_TAG_alter().
+ *
+ * Makes debugging entity query much easier.
+ *
+ * Example usage:
+ * @code
+ * $query = \Drupal::entityQuery('node');
+ * $query->condition('status', NODE_PUBLISHED);
+ * $query->addTag('debug');
+ * $query->execute();
+ * @endcode
+ */
+function devel_query_debug_alter(AlterableInterface $query) {
+  if (!$query->hasTag('debug-semaphore')) {
+    $query->addTag('debug-semaphore');
+    dpq($query);
+  }
+}

+ 14 - 0
sites/all/modules/contrib/dev/devel/devel.permissions.yml

@@ -0,0 +1,14 @@
+access devel information:
+  description: 'View developer output like variable printouts, query log, etc.'
+  title: 'Access developer information'
+  restrict access: TRUE
+
+execute php code:
+  title: 'Execute PHP code'
+  description: 'Run arbitrary PHP from a block.'
+  restrict access: TRUE
+
+switch users:
+  title: 'Switch users'
+  description: 'Become any user on the site with just a click.'
+  restrict access: TRUE

+ 172 - 0
sites/all/modules/contrib/dev/devel/devel.routing.yml

@@ -0,0 +1,172 @@
+devel.admin_settings:
+  path: '/admin/config/development/devel'
+  defaults:
+    _form: '\Drupal\devel\Form\SettingsForm'
+    _title: 'Devel settings'
+  requirements:
+    _permission: 'administer site configuration'
+
+devel.reinstall:
+  path: '/devel/reinstall'
+  defaults:
+    _form: '\Drupal\devel\Form\DevelReinstall'
+    _title: 'Reinstall modules'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'administer site configuration'
+
+devel.menu_rebuild:
+  path: '/devel/menu/reset'
+  defaults:
+    _form: '\Drupal\devel\Form\DevelRebuildMenus'
+    _title: 'Rebuild menus'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'administer site configuration'
+
+devel.configs_list:
+  path: '/devel/config/{filter}'
+  options:
+    _admin_route: TRUE
+  defaults:
+    _form: '\Drupal\devel\Form\ConfigsList'
+    _title: 'Config editor'
+    filter: ''
+  requirements:
+    _permission: 'administer site configuration'
+
+devel.config_edit:
+  path: '/devel/config/edit/{config_name}'
+  defaults:
+    _form: '\Drupal\devel\Form\ConfigEditor'
+    _title: 'Edit configuration object: !config_name'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'administer site configuration'
+
+devel.state_system_page:
+  path: '/devel/state'
+  defaults:
+    _controller: '\Drupal\devel\Controller\DevelController::stateSystemPage'
+    _title: 'State editor'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'access devel information'
+
+devel.system_state_edit:
+  path: '/devel/state/edit/{state_name}'
+  defaults:
+    _form: '\Drupal\devel\Form\SystemStateEdit'
+    _title: 'Edit state variable: @state_name'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'administer site configuration'
+
+devel.menu_item:
+  path: '/devel/menu/item'
+  defaults:
+    _controller: '\Drupal\devel\Controller\DevelController::menuItem'
+    _title: 'Menu item'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'access devel information'
+
+devel.theme_registry:
+  path: '/devel/theme/registry'
+  defaults:
+    _controller: '\Drupal\devel\Controller\DevelController::themeRegistry'
+    _title: 'Theme registry'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'access devel information'
+
+devel.entity_info_page:
+  path: '/devel/entity/info'
+  defaults:
+    _controller: '\Drupal\devel\Controller\DevelController::entityInfoPage'
+    _title: 'Entity info'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'access devel information'
+
+devel.field_info_page:
+  path: '/devel/field/info'
+  defaults:
+    _controller: '\Drupal\devel\Controller\DevelController::fieldInfoPage'
+    _title: 'Field info'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'access devel information'
+
+devel.execute_php:
+  path: '/devel/php'
+  defaults:
+    _form: '\Drupal\devel\Form\ExecutePHP'
+    _title: 'Execute PHP code'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'execute php code'
+
+devel.session:
+  path: '/devel/session'
+  defaults:
+    _controller: '\Drupal\devel\Controller\DevelController::session'
+    _title: 'Session viewer'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'access devel information'
+
+devel.switch:
+  path: '/devel/switch/{name}'
+  defaults:
+    _controller: '\Drupal\devel\Controller\SwitchUserController::switchUser'
+    _title: 'Switch user'
+    name: ''
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'switch users'
+    _csrf_token: 'TRUE'
+
+devel.elements_page:
+  path: '/devel/elements'
+  defaults:
+    _controller: '\Drupal\devel\Controller\DevelController::elementsPage'
+    _title: 'Element Info'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'access devel information'
+
+devel.cache_clear:
+  path: '/devel/cache/clear'
+  defaults:
+    _controller: '\Drupal\devel\Controller\DevelController::cacheClear'
+    _title: 'Clear cache'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'access devel information'
+    _csrf_token: 'TRUE'
+
+devel.run_cron:
+  path: '/devel/run-cron'
+  defaults:
+    _controller: '\Drupal\system\CronController::runManually'
+    _title: 'Run cron'
+  options:
+    _admin_route: TRUE
+  requirements:
+    _permission: 'administer site configuration'
+    _csrf_token: 'TRUE'

+ 24 - 0
sites/all/modules/contrib/dev/devel/devel.rules.inc

@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * Implements hook_rules_action_info().
+ */
+function devel_rules_action_info() {
+  return array(
+    'devel_debug' => array(
+      'base' => 'devel_rules_debug_action',
+      'label' => t('Debug value'),
+      'group' => t('Devel'),
+      'parameter' => array(
+        'value' => array('type' => 'unknown', 'label' => t('Value to debug')),
+      ),
+    ),
+  );
+}
+
+/**
+ * Rules action for debugging values.
+ */
+function devel_rules_debug_action($value) {
+  dpm($value);
+}

+ 26 - 0
sites/all/modules/contrib/dev/devel/devel.services.yml

@@ -0,0 +1,26 @@
+services:
+  devel.event_subscriber:
+    class: Drupal\devel\EventSubscriber\DevelEventSubscriber
+    arguments: ['@config.factory', '@current_user', '@module_handler', '@url_generator']
+    tags:
+      - { name: event_subscriber }
+
+  plugin.manager.devel_dumper:
+    class: Drupal\devel\DevelDumperPluginManager
+    parent: default_plugin_manager
+
+  devel.dumper:
+    class: Drupal\devel\DevelDumperManager
+    arguments: ['@config.factory', '@current_user', '@plugin.manager.devel_dumper']
+
+  devel.route_subscriber:
+    class: Drupal\devel\Routing\RouteSubscriber
+    arguments: ['@entity_type.manager']
+    tags:
+      - { name: event_subscriber }
+
+  devel.twig.debug_extension:
+    class: Drupal\devel\Twig\Extension\Debug
+    arguments: ['@devel.dumper']
+    tags:
+      - { name: twig.extension }

+ 42 - 0
sites/all/modules/contrib/dev/devel/devel_generate/README.txt

@@ -0,0 +1,42 @@
+This module creates the "DevelGenerate" plugin type.
+
+All you need to do to provide a new instance for "DevelGenerate" plugin type
+is to create your class extending "DevelGenerateBase" and following the next steps.
+
+1 - Declaring your plugin with annotations:
+
+/**
+ * Provides a ExampleDevelGenerate plugin.
+ *
+ * @DevelGenerate(
+ *   id = "example",
+ *   label = @Translation("example"),
+ *   description = @Translation("Generate a given number of example elements. Optionally delete current example elements."),
+ *   url = "example",
+ *   permission = "administer example",
+ *   settings = {
+ *     "num" = 50,
+ *     "kill" = FALSE,
+ *     "another_property" = "default_value"
+ *   }
+ * )
+ */
+
+2 - Implement "settingsForm" method to create a form using the properties from annotations.
+
+3 - Implement "handleDrushParams" method. It should return an array of values.
+
+4 - Implement "generateElements" method. You can write here your business logic
+using the array of values.
+
+Notes:
+
+You can alter existing properties for every plugin implementing hook_devel_generate_info_alter.
+
+DevelGenerateBaseInterface details base wrapping methods that most DevelGenerate implementations
+will want to directly inherit from Drupal\devel_generate\DevelGenerateBase.
+
+DevelGenerateFieldBaseInterface details base wrapping methods that most class implementations
+for supporting new field types will want to directly inherit from Drupal\devel_generate\DevelGenerateFieldBase.
+So to give support for a new field type should be enough to create a class called
+"DevelGenerateFieldNewfieldtype" extending DevelGenerateFieldBase and to implement "generateValues" method.

+ 25 - 0
sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.batch.inc

@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * Wrapping function for invoking the right
+ * method responsible for handle a given batch operation.
+ * Available for every DevelGeneratePlugin.
+ */
+function devel_generate_operation(Drupal\devel_generate\DevelGenerateBaseInterface $class, $method, $vars, &$context) {
+  return $class->$method($vars, $context);
+}
+
+/**
+ * Common finish batch function available for
+ * every DevelGeneratePlugin.
+ */
+function devel_generate_batch_finished($success, $results, $operations) {
+
+  if ($success) {
+    $message = t('Finished @num elements created successfully.', array('@num' => $results['num']));
+  }
+  else {
+    $message = t('Finished with an error.');
+  }
+  drupal_set_message($message);
+}

+ 13 - 0
sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.info.yml

@@ -0,0 +1,13 @@
+type: module
+name: 'Devel generate'
+description: 'Generate dummy users, nodes, menus, taxonomy terms...'
+package: Development
+# core: 8.x
+tags:
+ - developer
+
+# Information added by Drupal.org packaging script on 2016-09-03
+version: '8.x-1.0-alpha1+23-dev'
+core: '8.x'
+project: 'devel'
+datestamp: 1472897643

+ 145 - 0
sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.module

@@ -0,0 +1,145 @@
+<?php
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
+use Drupal\Component\Utility\Random;
+use Drupal\devel_generate\DevelGenerateBase;
+use Drupal\node\NodeInterface;
+
+/**
+ * Implements hook_menu_links_discovered_alter().
+ */
+function devel_generate_menu_links_discovered_alter(&$links) {
+  $devel_generate_plugins = $devel_generate_manager = \Drupal::service('plugin.manager.develgenerate')->getDefinitions();
+  foreach ($devel_generate_plugins as $id => $plugin) {
+    $label = $plugin['label'];
+    $links["devel_generate.$id"] = array(
+      'title' => "Generate $label",
+      'parent' => 'system.admin_config_development',
+      'description' => $plugin['description'],
+      'route_name' => "devel_generate.$id",
+    );
+  }
+}
+
+/**
+ * Implements hook_entity_insert().
+ *
+ * Inserts nodes properly based on generation options.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *  The base node created on submit. Inspects $node->devel_generate.
+ */
+function devel_generate_entity_insert(EntityInterface $entity) {
+  if ($entity->getEntityTypeId() != 'node' || !isset($entity->devel_generate)) {
+    return;
+  }
+  /** @var \Drupal\node\NodeInterface $entity */
+  $results = $entity->devel_generate;
+
+  if (!empty($results['max_comments'])) {
+    foreach ($entity->getFieldDefinitions() as $field_name => $field_definition) {
+      if ($field_definition->getType() == 'comment' && $entity->get($field_name)->status == CommentItemInterface::OPEN) {
+        // Add comments for each comment field on entity.
+        devel_generate_add_comments($entity, $field_definition, $results['users'], $results['max_comments'], $results['title_length']);
+      }
+    }
+  }
+
+  // Add an url alias. Cannot happen before save because we don't know the nid.
+  if (!empty($results['add_alias'])) {
+    $path = array(
+      'source' => '/node/' . $entity->id(),
+      'alias' => '/node-' . $entity->id() . '-' . $entity->bundle(),
+    );
+    \Drupal::service('path.alias_storage')->save($path['source'], $path['alias']);
+  }
+
+  // Add node statistics.
+  if (!empty($results['add_statistics']) && \Drupal::moduleHandler()->moduleExists('statistics')) {
+    devel_generate_add_statistics($entity);
+  }
+}
+
+/**
+ * Create comments and add them to a node.
+ *
+ * @param \Drupal\node\NodeInterface $node
+ *   Node to add comments to.
+ * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
+ *   The field storage definition.
+ * @param array $users
+ *   Array of users to assign comment authors.
+ * @param int $max_comments
+ *   Max number of comments to generate per node.
+ * @param int $title_length
+ *   Max length of the title of the comments.
+ */
+function devel_generate_add_comments(NodeInterface $node, FieldDefinitionInterface $field_definition, $users, $max_comments, $title_length = 8) {
+  $parents = array();
+  $field_name = $field_definition->getName();
+  $num_comments = mt_rand(1, $max_comments);
+  for ($i = 1; $i <= $num_comments; $i++) {
+    switch ($i % 3) {
+      case 0:
+        // No parent.
+      case 1:
+        // Top level parent.
+        $parents = \Drupal::entityQuery('comment')
+          ->condition('pid', 0)
+          ->condition('entity_id', $node->id())
+          ->condition('entity_type', 'node')
+          ->condition('field_name', $field_name)
+          ->range(0, 1)
+          ->execute();
+        break;
+      case 2:
+        // Non top level parent.
+        $parents = \Drupal::entityQuery('comment')
+          ->condition('pid', 0, '>')
+          ->condition('entity_id', $node->id())
+          ->condition('entity_type', 'node')
+          ->condition('field_name', $field_name)
+          ->range(0, 1)
+          ->execute();
+        break;
+    }
+    $random = new Random();
+    $stub = array(
+      'entity_type' => $node->getEntityTypeId(),
+      'entity_id' => $node->id(),
+      'field_name' => $field_name,
+      'name' => 'devel generate',
+      'mail' => 'devel_generate@example.com',
+      'timestamp' => mt_rand($node->getCreatedTime(), REQUEST_TIME),
+      'subject' => substr($random->sentences(mt_rand(2, $title_length), TRUE), 0, 63),
+      'uid' => $users[array_rand($users)],
+      'langcode' => $node->language()->getId(),
+    );
+    if ($parents) {
+      $stub['pid'] = current($parents);
+    }
+    $comment = entity_create('comment', $stub);
+
+    //Populate all core fields on behalf of field.module
+    DevelGenerateBase::populateFields($comment);
+    $comment->save();
+  }
+}
+
+/**
+ * Generate statistics information for a node.
+ *
+ * @param \Drupal\node\NodeInterface $node
+ *   A node object.
+ */
+function devel_generate_add_statistics(NodeInterface $node) {
+  $statistic = array(
+    'nid' => $node->id(),
+    'totalcount' => mt_rand(0, 500),
+    'timestamp' => REQUEST_TIME - mt_rand(0, $node->getCreatedTime()),
+  );
+  $statistic['daycount'] = mt_rand(0, $statistic['totalcount']);
+  db_insert('node_counter')->fields($statistic)->execute();
+}

+ 5 - 0
sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.permissions.yml

@@ -0,0 +1,5 @@
+administer devel_generate:
+  title: 'Administer devel_generate'
+
+permission_callbacks:
+  - \Drupal\devel_generate\DevelGeneratePermissions::permissions

+ 2 - 0
sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.routing.yml

@@ -0,0 +1,2 @@
+route_callbacks:
+  - '\Drupal\devel_generate\Routing\DevelGenerateRoutes::routes'

+ 4 - 0
sites/all/modules/contrib/dev/devel/devel_generate/devel_generate.services.yml

@@ -0,0 +1,4 @@
+services:
+  plugin.manager.develgenerate:
+    class: Drupal\devel_generate\DevelGeneratePluginManager
+    parent: default_plugin_manager

+ 151 - 0
sites/all/modules/contrib/dev/devel/devel_generate/drush/DevelGenerateUnishTest.php

@@ -0,0 +1,151 @@
+<?php
+
+namespace Unish;
+
+if (class_exists('Unish\CommandUnishTestCase')) {
+
+  /**
+   * Tests for devel_generate drush commands.
+   *
+   * @group devel_generate
+   */
+  class DevelGenerateUnishTest extends CommandUnishTestCase {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setUp() {
+      if (UNISH_DRUPAL_MAJOR_VERSION < 8) {
+        $this->markTestSkipped('Devel Generate Tests only available on D8+.');
+      }
+
+      if (!$this->getSites()) {
+        $this->setUpDrupal(1, TRUE, UNISH_DRUPAL_MAJOR_VERSION, 'standard');
+
+        // Symlink the devel module into the sandbox.
+        $devel_directory = dirname(dirname(__DIR__));
+        symlink($devel_directory, $this->webroot() . '/modules/devel');
+
+        // Enable the devel_generate modules.
+        $this->drush('pm-enable', ['devel_generate'], $this->getOptions());
+      }
+
+    }
+
+    /**
+     * Tests devel generate terms.
+     */
+    public function testDevelGenerateTerms() {
+      $this->drush('pm-enable', ['taxonomy'], $this->getOptions());
+
+      $this->drush('generate-terms', [], $this->getOptions(), NULL, NULL, static::EXIT_ERROR);
+      $this->assertContains('Please provide a vocabulary machine name.', $this->getErrorOutput());
+
+      $this->drush('generate-terms', ['unknown'], $this->getOptions(), NULL, NULL, static::EXIT_ERROR);
+      $this->assertContains('Invalid vocabulary name: unknown', $this->getErrorOutput());
+
+      $this->drush('generate-terms', ['tags', 'NaN'], $this->getOptions(), NULL, NULL, static::EXIT_ERROR);
+      $this->assertContains('Invalid number of terms: NaN', $this->getErrorOutput());
+
+      $eval_term_count = "return \\Drupal::entityQuery('taxonomy_term')->count()->execute();";
+      $eval_options = $this->getOptions() + ['format' => 'string'];
+
+      $this->drush('generate-terms', ['tags'], $this->getOptions());
+      $this->assertContains('Created the following new terms:', $this->getErrorOutput());
+      $this->drush('php-eval', [$eval_term_count], $eval_options);
+      $this->assertEquals(10, $this->getOutput());
+
+      $this->drush('generate-terms', ['tags', '1'], $this->getOptions());
+      $this->assertContains('Created the following new terms:', $this->getErrorOutput());
+      $this->drush('php-eval', [$eval_term_count], $eval_options);
+      $this->assertEquals(11, $this->getOutput());
+
+      $this->drush('generate-terms', ['tags', '1'], $this->getOptions(TRUE));
+      $this->assertContains('Deleted existing terms.', $this->getErrorOutput());
+      $this->assertContains('Created the following new terms:', $this->getErrorOutput());
+      $this->drush('php-eval', [$eval_term_count], $eval_options);
+      $this->assertEquals(1, $this->getOutput());
+
+      $this->drush('gent', ['tags', '1'], $this->getOptions());
+      $this->assertContains('Created the following new terms:', $this->getErrorOutput());
+    }
+
+    /**
+     * Tests devel generate contents.
+     */
+    public function testDevelGenerateContents() {
+      $this->drush('pm-enable', ['node'], $this->getOptions());
+
+      $eval_content_count = "return \\Drupal::entityQuery('node')->count()->execute();";
+      $eval_options = $this->getOptions() + ['format' => 'string'];
+
+      // Try to generate 10 content of type "page" or "article"
+      $this->drush('generate-content', [10], $this->getOptions(), NULL, NULL, static::EXIT_SUCCESS);
+      $this->assertContains('Finished creating 10 nodes', $this->getErrorOutput());
+      $this->drush('php-eval', [$eval_content_count], $eval_options);
+      $this->assertEquals(10, $this->getOutput());
+
+      // Try to generate 1 content of type "page" or "article"
+      $this->drush('generate-content', [1], $this->getOptions(), NULL, NULL, static::EXIT_SUCCESS);
+      $this->assertContains('1 node created.', $this->getErrorOutput());
+      $this->drush('php-eval', [$eval_content_count], $eval_options);
+      $this->assertEquals(11, $this->getOutput());
+
+      // Try to generate 5 content of type "page" or "article", removing all
+      // previous contents.
+      $this->drush('generate-content', [5], $this->getOptions(TRUE), NULL, NULL, static::EXIT_SUCCESS);
+      $this->assertContains('Finished creating 5 nodes', $this->getErrorOutput());
+      $this->drush('php-eval', [$eval_content_count], $eval_options);
+      $this->assertEquals(5, $this->getOutput());
+
+      // Try to generate other 5 content with "crappy" type. Output should
+      // remains 5.
+      $generate_content_wrong_ct = $this->getOptions(TRUE) + ['types' => 'crappy'];
+      $this->drush('generate-content', [5], $generate_content_wrong_ct, NULL, NULL, static::EXIT_ERROR);
+      $this->assertContains('One or more content types have been entered that don', $this->getErrorOutput());
+      $this->drush('php-eval', [$eval_content_count], $eval_options);
+      $this->assertEquals(5, $this->getOutput());
+
+      // Try to generate other 5 content with empty types. Output should
+      // remains 5.
+      $generate_content_no_types = $this->getOptions(TRUE) + ['types' => ''];
+      $this->drush('generate-content', [5], $generate_content_no_types, NULL, NULL, static::EXIT_ERROR);
+      $this->assertContains('No content types available', $this->getErrorOutput());
+      $this->drush('php-eval', [$eval_content_count], $eval_options);
+      $this->assertEquals(5, $this->getOutput());
+
+      // Try to generate other 5 content without any types. Output should
+      // remains 5.
+      $generate_content_no_types = $this->getOptions(TRUE) + ['types' => NULL];
+      $this->drush('generate-content', [5], $generate_content_no_types, NULL, NULL, static::EXIT_ERROR);
+      $this->assertContains('Wrong syntax or no content type selected. The correct syntax uses', $this->getErrorOutput());
+      $this->drush('php-eval', [$eval_content_count], $eval_options);
+      $this->assertEquals(5, $this->getOutput());
+    }
+
+    /**
+     * Default drush options.
+     *
+     * @param bool $kill
+     *   Whether add kill option.
+     *
+     * @return array
+     *   An array containing the default options for drush commands.
+     */
+    protected function getOptions($kill = FALSE) {
+      $options = [
+        'yes' => NULL,
+        'root' => $this->webroot(),
+        'uri' => key($this->getSites()),
+      ];
+
+      if($kill) {
+        $options['kill'] = NULL;
+      }
+
+      return $options;
+    }
+
+  }
+
+}

+ 196 - 0
sites/all/modules/contrib/dev/devel/devel_generate/drush/devel_generate.drush.inc

@@ -0,0 +1,196 @@
+<?php
+
+/**
+ * @file
+ *  Generate content, taxonomy, menu, and users via drush framework.
+ */
+use Drupal\devel_generate\DevelGenerateBaseInterface;
+use Drupal\devel_generate\DevelGeneratePluginManager;
+
+/**
+ * Implementation of hook_drush_command().
+ */
+function devel_generate_drush_command() {
+  $items['generate-users'] = array(
+    'callback' => 'drush_devel_generate',
+    'callback arguments' => array(
+      'plugin_id' => 'user',
+    ),
+    'description' => 'Create users.',
+    'arguments' => array(
+      'num' => 'Number of users to generate.',
+    ),
+    'options' => array(
+      'kill' => 'Delete all users before generating new ones.',
+      'roles' => 'A comma delimited list of role IDs which should be granted to the new users. No need to specify authenticated user role.',
+      'pass' => 'Specify a password to be set for all generated users.',
+    ),
+    'aliases' => array('genu'),
+  );
+  $items['generate-terms'] = array(
+    'callback' => 'drush_devel_generate',
+    'callback arguments' => array(
+      'plugin_id' => 'term',
+    ),
+    'description' => 'Create terms in specified vocabulary.',
+    'arguments' => array(
+      'machine_name' => 'Vocabulary machine name into which new terms will be inserted.',
+      'num' => 'Number of terms to insert. Defaults to 10.',
+    ),
+    'options' => array(
+      'kill' => 'Delete all terms in specified vocabulary before generating.',
+      'feedback' => 'An integer representing interval for insertion rate logging. Defaults to 1000',
+      'pipe' => 'Returns the list of generated terms, one per line.',
+    ),
+    'aliases' => array('gent'),
+
+  );
+  $items['generate-vocabs'] = array(
+    'callback' => 'drush_devel_generate',
+    'callback arguments' => array(
+      'plugin_id' => 'vocabulary',
+    ),
+    'description' => 'Create vocabularies.',
+    'arguments' => array(
+      'num' => 'Number of vocabularies to create. Defaults to 1.',
+    ),
+    'options' => array(
+      'kill' => 'Delete all vocabularies before generating.',
+      'pipe' => 'Returns the list of generated vocabularies, one per line.',
+    ),
+    'aliases' => array('genv'),
+  );
+  $items['generate-content'] = array(
+    'callback' => 'drush_devel_generate',
+    'callback arguments' => array(
+      'plugin_id' => 'content',
+    ),
+    'description' => 'Create content.',
+    'drupal dependencies' => array('devel_generate'),
+    'arguments' => array(
+      'num' => 'Number of nodes to generate.',
+      'max_comments' => 'Maximum number of comments to generate.',
+    ),
+    'options' => array(
+      'kill' => 'Delete all content before generating new content.',
+      'types' => 'A comma delimited list of content types to create. Defaults to page,article.',
+      'feedback' => 'An integer representing interval for insertion rate logging. Defaults to 1000',
+      'skip-fields' => 'A comma delimited list of fields to omit when generating random values',
+      'languages' => 'A comma-separated list of language codes',
+    ),
+    'aliases' => array('genc'),
+  );
+  $items['generate-menus'] = array(
+    'callback' => 'drush_devel_generate',
+    'callback arguments' => array(
+      'plugin_id' => 'menu',
+    ),
+    'description' => 'Create menus and menu items.',
+    'drupal dependencies' => array('devel_generate'), // Remove these once devel.module is moved down a directory. http://drupal.org/node/925246
+    'arguments' => array(
+      'number_menus' => 'Number of menus to generate. Defaults to 2.',
+      'number_links' => 'Number of links to generate. Defaults to 50.',
+      'max_depth' => 'Max link depth. Defaults to 3',
+      'max_width' => 'Max width of first level of links. Defaults to 8.',
+    ),
+    'options' => array(
+      'kill' => 'Delete all previously generated menus and links before generating new menus and links.',
+      'pipe' => 'Returns the list of generated menus, one per line.',
+    ),
+    'aliases' => array('genm'),
+  );
+  return $items;
+}
+
+/**
+ * Implements drush_hook_COMMAND_validate().
+ */
+function drush_devel_generate_generate_users_validate() {
+
+  //Array of "Callback arguments" and "command line args".
+  $params = func_get_args();
+  _drush_plugin_validate($params);
+}
+
+/**
+ * Implements drush_hook_COMMAND_validate().
+ */
+function drush_devel_generate_generate_terms_validate() {
+
+  //Array of "Callback arguments" and "command line args".
+  $params = func_get_args();
+  _drush_plugin_validate($params);
+}
+
+/**
+ * Implements drush_hook_COMMAND_validate().
+ */
+function drush_devel_generate_generate_vocabs_validate() {
+
+  //Array of "Callback arguments" and "command line args".
+  $params = func_get_args();
+  _drush_plugin_validate($params);
+}
+
+/**
+ * Implements drush_hook_COMMAND_validate().
+ */
+function drush_devel_generate_generate_content_validate() {
+
+  //Array of "Callback arguments" and "command line args".
+  $params = func_get_args();
+  _drush_plugin_validate($params);
+}
+
+/**
+ * Implements drush_hook_COMMAND_validate().
+ */
+function drush_devel_generate_generate_menus_validate() {
+
+  //Array of "Callback arguments" and "command line args".
+  $params = func_get_args();
+  _drush_plugin_validate($params);
+}
+
+/**
+ * Helper function which returns an array with a plugin instance
+ * for a given id and the validated values ready to be used by
+ * the generate() function of the plugin.
+ */
+function _drush_plugin_validate($params) {
+
+  $instance_and_values = &drupal_static('drush_devel_generate_generate_validate');
+  //Getting plugin_id and leaving the command line args
+  $plugin_id = array_shift($params);
+
+  if (!isset($instance_and_values[$plugin_id])) {
+
+    /** @var DevelGeneratePluginManager $manager */
+    $manager = \Drupal::service('plugin.manager.develgenerate');
+
+    /** @var DevelGenerateBaseInterface $instance */
+    $instance = $manager->createInstance($plugin_id, array());
+
+    //Plugin instance suit params in order to fit for generateElements
+    $values = $instance->validateDrushParams($params);
+    $instance_and_values[$plugin_id]['instance'] = $instance;
+    $instance_and_values[$plugin_id]['values'] = $values;
+  }
+
+  return $instance_and_values[$plugin_id];
+}
+
+/**
+ * Command callback. Generate a number of elements.
+ */
+function drush_devel_generate() {
+  $params = func_get_args();
+  $plugin_id = array_shift($params);
+  $instance_and_values = drupal_static('drush_devel_generate_generate_validate');
+
+  /** @var DevelGenerateBaseInterface $instance */
+  $instance = $instance_and_values[$plugin_id]['instance'];
+  $values = $instance_and_values[$plugin_id]['values'];
+  $instance->generate($values);
+
+}

+ 86 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/Annotation/DevelGenerate.php

@@ -0,0 +1,86 @@
+<?php
+
+namespace Drupal\devel_generate\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines a DevelGenerate annotation object.
+ *
+ * DevelGenerate handle the bulk creation of entites.
+ *
+ * Additional annotation keys for DevelGenerate can be defined in
+ * hook_devel_generate_info_alter().
+ *
+ * @Annotation
+ *
+ * @see \Drupal\devel_generate\DevelGeneratePluginManager
+ * @see \Drupal\devel_generate\DevelGenerateBaseInterface
+ */
+class DevelGenerate extends Plugin {
+
+  /**
+   * The plugin ID.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The human-readable name of the DevelGenerate type.
+   *
+   * @ingroup plugin_translatable
+   *
+   * @var \Drupal\Core\Annotation\Translation
+   */
+  public $label;
+
+  /**
+   * A short description of the DevelGenerate type.
+   *
+   * @ingroup plugin_translatable
+   *
+   * @var \Drupal\Core\Annotation\Translation
+   */
+  public $description;
+
+  /**
+   * A url to access the plugin settings form.
+   *
+   * @var string
+   */
+  public $url;
+
+  /**
+   * The permission required to access the plugin settings form.
+   *
+   * @var string
+   */
+  public $permission;
+
+  /**
+   * The name of the DevelGenerate class.
+   *
+   * This is not provided manually, it will be added by the discovery mechanism.
+   *
+   * @var string
+   */
+  public $class;
+
+  /**
+   * An array whose keys are the names of the settings available to the
+   * DevelGenerate settingsForm, and whose values are the default values for those settings.
+   *
+   * @var array
+   */
+  public $settings = array();
+
+  /**
+   * An array whose keys are the settings available to the
+   * DevelGenerate drush command: "suffix", "alias", "options" and "args".
+   *
+   * @var array
+   */
+  public $drushSettings = array();
+
+}

+ 168 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/DevelGenerateBase.php

@@ -0,0 +1,168 @@
+<?php
+
+namespace Drupal\devel_generate;
+
+use Drupal\Component\Utility\Random;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\PluginBase;
+
+/**
+ * Provides a base DevelGenerate plugin implementation.
+ */
+abstract class DevelGenerateBase extends PluginBase implements DevelGenerateBaseInterface {
+
+  /**
+   * The plugin settings.
+   *
+   * @var array
+   */
+  protected $settings = array();
+
+  /**
+   * The random data generator.
+   *
+   * @var \Drupal\Component\Utility\Random
+   */
+  protected $random;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSetting($key) {
+    // Merge defaults if we have no value for the key.
+    if (!array_key_exists($key, $this->settings)) {
+      $this->settings = $this->getDefaultSettings();
+    }
+    return isset($this->settings[$key]) ? $this->settings[$key] : NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefaultSettings() {
+    $definition = $this->getPluginDefinition();
+    return $definition['settings'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSettings() {
+    return $this->settings;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    return array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function settingsFormValidate(array $form, FormStateInterface $form_state) {
+    // Validation is optional.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function generate(array $values) {
+    $this->generateElements($values);
+    $this->setMessage('Generate process complete.');
+  }
+
+  /**
+   * Business logic relating with each DevelGenerate plugin
+   *
+   * @param array $values
+   *   The input values from the settings form.
+   */
+  protected function generateElements(array $values) {
+
+  }
+
+  /**
+   * Populate the fields on a given entity with sample values.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity to be enriched with sample field values.
+   */
+  public static function populateFields(EntityInterface $entity) {
+    /** @var \Drupal\field\FieldConfigInterface[] $instances */
+    $instances = entity_load_multiple_by_properties('field_config', array('entity_type' => $entity->getEntityType()->id(), 'bundle' => $entity->bundle()));
+
+    if ($skips = function_exists('drush_get_option') ? drush_get_option('skip-fields', '') : @$_REQUEST['skip-fields']) {
+      foreach (explode(',', $skips) as $skip) {
+        unset($instances[$skip]);
+      }
+    }
+
+    foreach ($instances as $instance) {
+      $field_storage = $instance->getFieldStorageDefinition();
+      $max = $cardinality = $field_storage->getCardinality();
+      if ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
+        // Just an arbitrary number for 'unlimited'
+        $max = rand(1, 3);
+      }
+      $field_name = $field_storage->getName();
+      $entity->$field_name->generateSampleItems($max);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleDrushParams($args) {
+
+  }
+
+  /**
+   * Set a message for either drush or the web interface.
+   *
+   * @param string $msg
+   *   The message to display.
+   * @param string $type
+   *   (optional) The message type, as defined by drupal_set_message(). Defaults
+   *   to 'status'
+   */
+  protected function setMessage($msg, $type = 'status') {
+    $function = 'drupal_set_message';
+    if (function_exists('drush_log')) {
+      $function = 'drush_log';
+      $msg = strip_tags($msg);
+    }
+    $function($msg, $type);
+  }
+
+  /**
+   * Check if a given param is a number.
+   *
+   * @param mixed $number
+   *   The parameter to check.
+   *
+   * @return bool
+   *   TRUE if the parameter is a number, FALSE otherwise.
+   */
+  public static function isNumber($number) {
+    if ($number == NULL) return FALSE;
+    if (!is_numeric($number)) return FALSE;
+    return TRUE;
+  }
+
+  /**
+   * Returns the random data generator.
+   *
+   * @return \Drupal\Component\Utility\Random
+   *   The random data generator.
+   */
+  protected function getRandom() {
+    if (!$this->random) {
+      $this->random = new Random();
+    }
+    return $this->random;
+  }
+}

+ 77 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/DevelGenerateBaseInterface.php

@@ -0,0 +1,77 @@
+<?php
+
+namespace Drupal\devel_generate;
+
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Base interface definition for "DevelGenerate" plugins.
+ *
+ * This interface details base wrapping methods that most DevelGenerate implementations
+ * will want to directly inherit from Drupal\devel_generate\DevelGenerateBase.
+ *
+ * DevelGenerate impementationa plugins should developing settingsForm() and generateElements()
+ * to achieve its own behaviour.
+ *
+ */
+interface DevelGenerateBaseInterface extends PluginInspectionInterface {
+
+  /**
+   * Returns the array of settings, including defaults for missing settings.
+   *
+   * @return array
+   *   The array of settings.
+   */
+  function getSetting($key);
+
+  /**
+   * Returns the default settings for the plugin.
+   *
+   * @return array
+   *   The array of default setting values, keyed by setting names.
+   */
+  function getDefaultSettings();
+
+  /**
+   * Returns the current settings for the plugin.
+   *
+   * @return array
+   *   The array of current setting values, keyed by setting names.
+   */
+  function getSettings();
+
+  /**
+   * Returns the form for the plugin.
+   *
+   * @return array
+   *   The array of default setting values, keyed by setting names.
+   */
+  function settingsForm(array $form, FormStateInterface $form_state);
+
+  /**
+   * Form validation handler.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   */
+  function settingsFormValidate(array $form, FormStateInterface $form_state);
+
+  /**
+   * Execute the instructions in common for all DevelGenerate plugin
+   *
+   * @param array $values
+   *   The input values from the settings form.
+   */
+  function generate(array $values);
+
+  /**
+   * Responsible for validating Drush params.
+   *
+   * @Return an array of values ready to be used for generateElements()
+   */
+  function validateDrushParams($args);
+
+}

+ 12 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/DevelGenerateException.php

@@ -0,0 +1,12 @@
+<?php
+
+namespace Drupal\devel_generate;
+
+use Drupal\Component\Plugin\Exception;
+
+/**
+ * DevelGenerateException extending Generic Plugin exception class.
+ */
+class DevelGenerateException extends \Exception {
+
+}

+ 62 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/DevelGeneratePermissions.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace Drupal\devel_generate;
+
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides dynamic permissions of the filter module.
+ */
+class DevelGeneratePermissions implements ContainerInjectionInterface {
+
+  /**
+   * The plugin manager.
+   *
+   * @var \Drupal\devel_generate\DevelGeneratePluginManager;
+   */
+  protected $develGeneratePluginManager;
+
+  /**
+   * Constructs a new DevelGeneratePermissions instance.
+   *
+   * @param \Drupal\devel_generate\DevelGeneratePluginManager $develGeneratePluginManager
+   *   The plugin manager.
+   */
+  public function __construct(DevelGeneratePluginManager $develGeneratePluginManager) {
+    $this->develGeneratePluginManager = $develGeneratePluginManager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static($container->get('plugin.manager.develgenerate'));
+  }
+
+  /*
+   * A permissions callback.
+   *
+   * @see devel_generate.permissions.yml.
+   *
+   * @return array
+   */
+  function permissions() {
+    $devel_generate_plugins = $this->develGeneratePluginManager->getDefinitions();
+    foreach ($devel_generate_plugins as $plugin) {
+
+      $permission = $plugin['permission'];
+      $permissions[$permission] = array(
+        'title' => t($permission),
+      );
+    }
+
+//    $permissions = array(
+//      'administer devel_generate' => array(
+//        'title' => t('Administer devel generate'),
+//      ),
+//    );
+    return $permissions;
+  }
+
+}

+ 31 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/DevelGeneratePluginManager.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace Drupal\devel_generate;
+
+use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+
+/**
+ * Plugin type manager for DevelGenerate plugins.
+ */
+Class DevelGeneratePluginManager extends DefaultPluginManager {
+
+  /**
+   * Constructs a DevelGeneratePluginManager object.
+   *
+   * @param \Traversable $namespaces
+   *   An object that implements \Traversable which contains the root paths
+   *   keyed by the corresponding namespace to look for plugin implementations.
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+   *   Cache backend instance to use.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke the alter hook with.
+   */
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Plugin/DevelGenerate', $namespaces, $module_handler, NULL, 'Drupal\devel_generate\Annotation\DevelGenerate');
+    $this->alterInfo('devel_generate_info');
+    $this->setCacheBackend($cache_backend, 'devel_generate_plugins');
+  }
+
+}

+ 114 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/Form/DevelGenerateForm.php

@@ -0,0 +1,114 @@
+<?php
+
+namespace Drupal\devel_generate\Form;
+
+use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\devel_generate\DevelGenerateException;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Defines a form that allows privileged users to generate entities.
+ */
+class DevelGenerateForm extends FormBase {
+
+  /**
+   * The manager to be used for instantiating plugins.
+   *
+   * @var \Drupal\Component\Plugin\PluginManagerInterface
+   */
+  protected $develGenerateManager;
+
+  /**
+   * Constructs a new DevelGenerateForm object.
+   *
+   * @param \Drupal\Component\Plugin\PluginManagerInterface $devel_generate_manager
+   *   The manager to be used for instantiating plugins.
+   */
+  public function __construct(PluginManagerInterface $devel_generate_manager) {
+    $this->develGenerateManager = $devel_generate_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('plugin.manager.develgenerate')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'devel_generate_form_' . $this->getPluginIdFromRequest();
+  }
+
+  /**
+   * Returns the value of the param _plugin_id for the current request.
+   *
+   * @see \Drupal\devel_generate\Routing\DevelGenerateRouteSubscriber
+   */
+  protected function getPluginIdFromRequest() {
+    $request = $this->getRequest();
+    return $request->get('_plugin_id');
+  }
+
+  /**
+   * Returns a DevelGenerate plugin instance for a given plugin id.
+   *
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   *
+   * @return \Drupal\devel_generate\DevelGenerateBaseInterface
+   *   A DevelGenerate plugin instance.
+   */
+  public function getPluginInstance($plugin_id) {
+    $instance = $this->develGenerateManager->createInstance($plugin_id, array());
+    return $instance;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    $plugin_id = $this->getPluginIdFromRequest();
+    $instance = $this->getPluginInstance($plugin_id);
+    $form = $instance->settingsForm($form, $form_state);
+    $form['actions'] = array('#type' => 'actions');
+    $form['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => $this->t('Generate'),
+      '#button_type' => 'primary',
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state) {
+    $plugin_id = $this->getPluginIdFromRequest();
+    $instance = $this->getPluginInstance($plugin_id);
+    $instance->settingsFormValidate($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    try {
+      $plugin_id = $this->getPluginIdFromRequest();
+      $instance = $this->getPluginInstance($plugin_id);
+      $instance->generate($form_state->getValues());
+    }
+    catch (DevelGenerateException $e) {
+      $this->logger('DevelGenerate', $this->t('Failed to generate elements due to "%error".', array('%error' => $e->getMessage())));
+      drupal_set_message($this->t('Failed to generate elements due to "%error".', array('%error' => $e->getMessage())));
+    }
+  }
+
+}

+ 506 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/ContentDevelGenerate.php

@@ -0,0 +1,506 @@
+<?php
+
+namespace Drupal\devel_generate\Plugin\DevelGenerate;
+
+use Drupal\comment\CommentManagerInterface;
+use Drupal\Component\Render\FormattableMarkup;
+use Drupal\Core\Datetime\DateFormatterInterface;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Language\LanguageInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Routing\UrlGeneratorInterface;
+use Drupal\devel_generate\DevelGenerateBase;
+use Drupal\field\Entity\FieldConfig;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a ContentDevelGenerate plugin.
+ *
+ * @DevelGenerate(
+ *   id = "content",
+ *   label = @Translation("content"),
+ *   description = @Translation("Generate a given number of content. Optionally delete current content."),
+ *   url = "content",
+ *   permission = "administer devel_generate",
+ *   settings = {
+ *     "num" = 50,
+ *     "kill" = FALSE,
+ *     "max_comments" = 0,
+ *     "title_length" = 4
+ *   }
+ * )
+ */
+class ContentDevelGenerate extends DevelGenerateBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The node storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $nodeStorage;
+
+  /**
+   * The node type storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $nodeTypeStorage;
+
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * The comment manager service.
+   *
+   * @var \Drupal\comment\CommentManagerInterface
+   */
+  protected $commentManager;
+
+  /**
+   * The language manager.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface
+   */
+  protected $languageManager;
+
+  /**
+   * The url generator service.
+   *
+   * @var \Drupal\Core\Routing\UrlGeneratorInterface
+   */
+  protected $urlGenerator;
+
+  /**
+   * The date formatter service.
+   *
+   * @var \Drupal\Core\Datetime\DateFormatterInterface
+   */
+  protected $dateFormatter;
+
+  /**
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin ID for the plugin instance.
+   * @param array $plugin_definition
+   * @param \Drupal\Core\Entity\EntityStorageInterface $node_storage
+   *   The node storage.
+   * @param \Drupal\Core\Entity\EntityStorageInterface $node_type_storage
+   *   The node type storage.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   * @param \Drupal\comment\CommentManagerInterface $comment_manager
+   *   The comment manager service.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager.
+   * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
+   *   The url generator service.
+   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
+   *   The date formatter service.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityStorageInterface $node_storage, EntityStorageInterface $node_type_storage, ModuleHandlerInterface $module_handler, CommentManagerInterface $comment_manager = NULL, LanguageManagerInterface $language_manager, UrlGeneratorInterface $url_generator, DateFormatterInterface $date_formatter) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->moduleHandler = $module_handler;
+    $this->nodeStorage = $node_storage;
+    $this->nodeTypeStorage = $node_type_storage;
+    $this->commentManager = $comment_manager;
+    $this->languageManager = $language_manager;
+    $this->urlGenerator = $url_generator;
+    $this->dateFormatter = $date_formatter;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    $entity_manager = $container->get('entity.manager');
+    return new static(
+      $configuration, $plugin_id, $plugin_definition,
+      $entity_manager->getStorage('node'),
+      $entity_manager->getStorage('node_type'),
+      $container->get('module_handler'),
+      $container->has('comment.manager') ? $container->get('comment.manager') : NULL,
+      $container->get('language_manager'),
+      $container->get('url_generator'),
+      $container->get('date.formatter')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    $types = $this->nodeTypeStorage->loadMultiple();
+
+    if (empty($types)) {
+      $create_url = $this->urlGenerator->generateFromRoute('node.type_add');
+      $this->setMessage($this->t('You do not have any content types that can be generated. <a href=":create-type">Go create a new content type</a>', array(':create-type' => $create_url)), 'error', FALSE);
+      return;
+    }
+
+    $options = array();
+
+    foreach ($types as $type) {
+      $options[$type->id()] = array(
+        'type' => array('#markup' => $type->label()),
+      );
+      if ($this->commentManager) {
+        $comment_fields = $this->commentManager->getFields('node');
+        $map = array($this->t('Hidden'), $this->t('Closed'), $this->t('Open'));
+
+        $fields = array();
+        foreach ($comment_fields as $field_name => $info) {
+          // Find all comment fields for the bundle.
+          if (in_array($type->id(), $info['bundles'])) {
+            $instance = FieldConfig::loadByName('node', $type->id(), $field_name);
+            $default_value = $instance->getDefaultValueLiteral();
+            $default_mode = reset($default_value);
+            $fields[] = new FormattableMarkup('@field: @state', array(
+              '@field' => $instance->label(),
+              '@state' => $map[$default_mode['status']],
+            ));
+          }
+        }
+        // @todo Refactor display of comment fields.
+        if (!empty($fields)) {
+          $options[$type->id()]['comments'] = array(
+            'data' => array(
+              '#theme' => 'item_list',
+              '#items' => $fields,
+            ),
+          );
+        }
+        else {
+          $options[$type->id()]['comments'] = $this->t('No comment fields');
+        }
+      }
+    }
+
+    $header = array(
+      'type' => $this->t('Content type'),
+    );
+    if ($this->commentManager) {
+      $header['comments'] = array(
+        'data' => $this->t('Comments'),
+        'class' => array(RESPONSIVE_PRIORITY_MEDIUM),
+      );
+    }
+
+    $form['node_types'] = array(
+      '#type' => 'tableselect',
+      '#header' => $header,
+      '#options' => $options,
+    );
+
+    $form['kill'] = array(
+      '#type' => 'checkbox',
+      '#title' => $this->t('<strong>Delete all content</strong> in these content types before generating new content.'),
+      '#default_value' => $this->getSetting('kill'),
+    );
+    $form['num'] = array(
+      '#type' => 'number',
+      '#title' => $this->t('How many nodes would you like to generate?'),
+      '#default_value' => $this->getSetting('num'),
+      '#required' => TRUE,
+      '#min' => 0,
+    );
+
+    $options = array(1 => $this->t('Now'));
+    foreach (array(3600, 86400, 604800, 2592000, 31536000) as $interval) {
+      $options[$interval] = $this->dateFormatter->formatInterval($interval, 1) . ' ' . $this->t('ago');
+    }
+    $form['time_range'] = array(
+      '#type' => 'select',
+      '#title' => $this->t('How far back in time should the nodes be dated?'),
+      '#description' => $this->t('Node creation dates will be distributed randomly from the current time, back to the selected time.'),
+      '#options' => $options,
+      '#default_value' => 604800,
+    );
+
+    $form['max_comments'] = array(
+      '#type' => $this->moduleHandler->moduleExists('comment') ? 'number' : 'value',
+      '#title' => $this->t('Maximum number of comments per node.'),
+      '#description' => $this->t('You must also enable comments for the content types you are generating. Note that some nodes will randomly receive zero comments. Some will receive the max.'),
+      '#default_value' => $this->getSetting('max_comments'),
+      '#min' => 0,
+      '#access' => $this->moduleHandler->moduleExists('comment'),
+    );
+    $form['title_length'] = array(
+      '#type' => 'number',
+      '#title' => $this->t('Maximum number of words in titles'),
+      '#default_value' => $this->getSetting('title_length'),
+      '#required' => TRUE,
+      '#min' => 1,
+      '#max' => 255,
+    );
+    $form['add_alias'] = array(
+      '#type' => 'checkbox',
+      '#disabled' => !$this->moduleHandler->moduleExists('path'),
+      '#description' => $this->t('Requires path.module'),
+      '#title' => $this->t('Add an url alias for each node.'),
+      '#default_value' => FALSE,
+    );
+    $form['add_statistics'] = array(
+      '#type' => 'checkbox',
+      '#title' => $this->t('Add statistics for each node (node_counter table).'),
+      '#default_value' => TRUE,
+      '#access' => $this->moduleHandler->moduleExists('statistics'),
+    );
+
+    $options = array();
+    // We always need a language.
+    $languages = $this->languageManager->getLanguages(LanguageInterface::STATE_ALL);
+    foreach ($languages as $langcode => $language) {
+      $options[$langcode] = $language->getName();
+    }
+
+    $form['add_language'] = array(
+      '#type' => 'select',
+      '#title' => $this->t('Set language on nodes'),
+      '#multiple' => TRUE,
+      '#description' => $this->t('Requires locale.module'),
+      '#options' => $options,
+      '#default_value' => array(
+        $this->languageManager->getDefaultLanguage()->getId(),
+      ),
+    );
+
+    $form['#redirect'] = FALSE;
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function settingsFormValidate(array $form, FormStateInterface $form_state) {
+    if (!array_filter($form_state->getValue('node_types'))) {
+      $form_state->setErrorByName('node_types', $this->t('Please select at least one content type'));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function generateElements(array $values) {
+    if ($values['num'] <= 50 && $values['max_comments'] <= 10) {
+      $this->generateContent($values);
+    }
+    else {
+      $this->generateBatchContent($values);
+    }
+  }
+
+  /**
+   * Method responsible for creating content when
+   * the number of elements is less than 50.
+   */
+  private function generateContent($values) {
+    $values['node_types'] = array_filter($values['node_types']);
+    if (!empty($values['kill']) && $values['node_types']) {
+      $this->contentKill($values);
+    }
+
+    if (!empty($values['node_types'])) {
+      // Generate nodes.
+      $this->develGenerateContentPreNode($values);
+      $start = time();
+      for ($i = 1; $i <= $values['num']; $i++) {
+        $this->develGenerateContentAddNode($values);
+        if (function_exists('drush_log') && $i % drush_get_option('feedback', 1000) == 0) {
+          $now = time();
+          drush_log(dt('Completed @feedback nodes (@rate nodes/min)', array('@feedback' => drush_get_option('feedback', 1000), '@rate' => (drush_get_option('feedback', 1000) * 60) / ($now - $start))), 'ok');
+          $start = $now;
+        }
+      }
+    }
+    $this->setMessage($this->formatPlural($values['num'], '1 node created.', 'Finished creating @count nodes'));
+  }
+
+  /**
+   * Method responsible for creating content when
+   * the number of elements is greater than 50.
+   */
+  private function generateBatchContent($values) {
+    // Setup the batch operations and save the variables.
+    $operations[] = array('devel_generate_operation', array($this, 'batchContentPreNode', $values));
+
+    // Add the kill operation.
+    if ($values['kill']) {
+      $operations[] = array('devel_generate_operation', array($this, 'batchContentKill', $values));
+    }
+
+    // Add the operations to create the nodes.
+    for ($num = 0; $num < $values['num']; $num ++) {
+      $operations[] = array('devel_generate_operation', array($this, 'batchContentAddNode', $values));
+    }
+
+    // Start the batch.
+    $batch = array(
+      'title' => $this->t('Generating Content'),
+      'operations' => $operations,
+      'finished' => 'devel_generate_batch_finished',
+      'file' => drupal_get_path('module', 'devel_generate') . '/devel_generate.batch.inc',
+    );
+    batch_set($batch);
+  }
+
+  public function batchContentPreNode($vars, &$context) {
+    $context['results'] = $vars;
+    $context['results']['num'] = 0;
+    $this->develGenerateContentPreNode($context['results']);
+  }
+
+  public function batchContentAddNode($vars, &$context) {
+    $this->develGenerateContentAddNode($context['results']);
+    $context['results']['num']++;
+  }
+
+  public function batchContentKill($vars, &$context) {
+    $this->contentKill($context['results']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateDrushParams($args) {
+    $add_language = drush_get_option('languages');
+    if (!empty($add_language)) {
+      $add_language = explode(',', str_replace(' ', '', $add_language));
+      // Intersect with the enabled languages to make sure the language args
+      // passed are actually enabled.
+      $values['values']['add_language'] = array_intersect($add_language, array_keys($this->languageManager->getLanguages(LanguageInterface::STATE_ALL)));
+    }
+
+    $values['kill'] = drush_get_option('kill');
+    $values['title_length'] = 6;
+    $values['num'] = array_shift($args);
+    $values['max_comments'] = array_shift($args);
+    $all_types = array_keys(node_type_get_names());
+    $default_types = array_intersect(array('page', 'article'), $all_types);
+    $selected_types = _convert_csv_to_array(drush_get_option('types', $default_types));
+
+    // Validates the input format for content types option.
+    if (drush_get_option('types', $default_types) === TRUE) {
+      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Wrong syntax or no content type selected. The correct syntax uses "=", eg.: --types=page,article'));
+    }
+
+    if (empty($selected_types)) {
+      return drush_set_error('DEVEL_GENERATE_NO_CONTENT_TYPES', dt('No content types available'));
+    }
+
+    $values['node_types'] = array_combine($selected_types, $selected_types);
+    $node_types = array_filter($values['node_types']);
+
+    if (!empty($values['kill']) && empty($node_types)) {
+      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Please provide content type (--types) in which you want to delete the content.'));
+    }
+
+    // Checks for any missing content types before generating nodes.
+    if (array_diff($node_types, $all_types)) {
+      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('One or more content types have been entered that don\'t exist on this site'));
+    }
+
+    return $values;
+  }
+
+  /**
+   * Deletes all nodes of given node types.
+   *
+   * @param array $values
+   *   The input values from the settings form.
+   */
+  protected function contentKill($values) {
+    $nids = $this->nodeStorage->getQuery()
+      ->condition('type', $values['node_types'], 'IN')
+      ->execute();
+
+    if (!empty($nids)) {
+      $nodes = $this->nodeStorage->loadMultiple($nids);
+      $this->nodeStorage->delete($nodes);
+      $this->setMessage($this->t('Deleted %count nodes.', array('%count' => count($nids))));
+    }
+  }
+
+  /**
+   * Return the same array passed as parameter
+   * but with an array of uids for the key 'users'.
+   */
+  protected function develGenerateContentPreNode(&$results) {
+    // Get user id.
+    $users = $this->getUsers();
+    $users = array_merge($users, array('0'));
+    $results['users'] = $users;
+  }
+
+  /**
+   * Create one node. Used by both batch and non-batch code branches.
+   */
+  protected function develGenerateContentAddNode(&$results) {
+    if (!isset($results['time_range'])) {
+      $results['time_range'] = 0;
+    }
+    $users = $results['users'];
+
+    $node_type = array_rand(array_filter($results['node_types']));
+    $uid = $users[array_rand($users)];
+
+    $node = $this->nodeStorage->create(array(
+      'nid' => NULL,
+      'type' => $node_type,
+      'title' => $this->getRandom()->sentences(mt_rand(1, $results['title_length']), TRUE),
+      'uid' => $uid,
+      'revision' => mt_rand(0, 1),
+      'status' => TRUE,
+      'promote' => mt_rand(0, 1),
+      'created' => REQUEST_TIME - mt_rand(0, $results['time_range']),
+      'langcode' => $this->getLangcode($results),
+    ));
+
+    // A flag to let hook_node_insert() implementations know that this is a
+    // generated node.
+    $node->devel_generate = $results;
+
+    // Populate all fields with sample values.
+    $this->populateFields($node);
+
+    // See devel_generate_node_insert() for actions that happen before and after
+    // this save.
+    $node->save();
+  }
+
+  /**
+   * Determine language based on $results.
+   */
+  protected function getLangcode($results) {
+    if (isset($results['add_language'])) {
+      $langcodes = $results['add_language'];
+      $langcode = $langcodes[array_rand($langcodes)];
+    }
+    else {
+      $langcode = $this->languageManager->getDefaultLanguage()->getId();
+    }
+    return $langcode;
+  }
+
+  /**
+   * Retrive 50 uids from the database.
+   */
+  protected function getUsers() {
+    $users = array();
+    $result = db_query_range("SELECT uid FROM {users}", 0, 50);
+    foreach ($result as $record) {
+      $users[] = $record->uid;
+    }
+    return $users;
+  }
+
+}

+ 407 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/MenuDevelGenerate.php

@@ -0,0 +1,407 @@
+<?php
+
+namespace Drupal\devel_generate\Plugin\DevelGenerate;
+
+use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Menu\MenuLinkTreeInterface;
+use Drupal\Core\Menu\MenuTreeParameters;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\devel_generate\DevelGenerateBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a MenuDevelGenerate plugin.
+ *
+ * @DevelGenerate(
+ *   id = "menu",
+ *   label = @Translation("menus"),
+ *   description = @Translation("Generate a given number of menus and menu links. Optionally delete current menus."),
+ *   url = "menu",
+ *   permission = "administer devel_generate",
+ *   settings = {
+ *     "num_menus" = 2,
+ *     "num_links" = 50,
+ *     "title_length" = 12,
+ *     "max_width" = 6,
+ *     "kill" = FALSE,
+ *   }
+ * )
+ */
+class MenuDevelGenerate extends DevelGenerateBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The menu tree service.
+   *
+   * @var \Drupal\Core\Menu\MenuLinkTreeInterface
+   */
+  protected $menuLinkTree;
+
+  /**
+   * The menu storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $menuStorage;
+
+  /**
+   * The menu link storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $menuLinkContentStorage;
+
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * Constructs a MenuDevelGenerate object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin ID for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
+   *   The menu tree service.
+   * @param \Drupal\Core\Entity\EntityStorageInterface $menu_storage
+   *   The menu storage.
+   * @param \Drupal\Core\Entity\EntityStorageInterface $menu_link_storage
+   *   The menu storage.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, MenuLinkTreeInterface $menu_tree, EntityStorageInterface $menu_storage, EntityStorageInterface $menu_link_storage, ModuleHandlerInterface $module_handler) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->menuLinkTree = $menu_tree;
+    $this->menuStorage = $menu_storage;
+    $this->menuLinkContentStorage = $menu_link_storage;
+    $this->moduleHandler = $module_handler;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    $entity_manager = $container->get('entity.manager');
+    return new static(
+      $configuration, $plugin_id, $plugin_definition,
+      $container->get('menu.link_tree'),
+      $entity_manager->getStorage('menu'),
+      $entity_manager->getStorage('menu_link_content'),
+      $container->get('module_handler')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    $menu_enabled = $this->moduleHandler->moduleExists('menu_ui');
+    if ($menu_enabled) {
+      $menus = array('__new-menu__' => $this->t('Create new menu(s)')) + menu_ui_get_menus();
+    }
+    else {
+      $menus = menu_list_system_menus();
+    }
+    $form['existing_menus'] = array(
+      '#type' => 'checkboxes',
+      '#title' => $this->t('Generate links for these menus'),
+      '#options' => $menus,
+      '#default_value' => array('__new-menu__'),
+      '#required' => TRUE,
+    );
+    if ($menu_enabled) {
+      $form['num_menus'] = array(
+        '#type' => 'number',
+        '#title' => $this->t('Number of new menus to create'),
+        '#default_value' => $this->getSetting('num_menus'),
+        '#min' => 0,
+        '#states' => array(
+          'visible' => array(
+            ':input[name="existing_menus[__new-menu__]"]' => array('checked' => TRUE),
+          ),
+        ),
+      );
+    }
+    $form['num_links'] = array(
+      '#type' => 'number',
+      '#title' => $this->t('Number of links to generate'),
+      '#default_value' => $this->getSetting('num_links'),
+      '#required' => TRUE,
+      '#min' => 0,
+    );
+    $form['title_length'] = array(
+      '#type' => 'number',
+      '#title' => $this->t('Maximum number of characters in menu and menu link names'),
+      '#description' => $this->t('The minimum length is 2.'),
+      '#default_value' => $this->getSetting('title_length'),
+      '#required' => TRUE,
+      '#min' => 2,
+      '#max' => 128,
+    );
+    $form['link_types'] = array(
+      '#type' => 'checkboxes',
+      '#title' => $this->t('Types of links to generate'),
+      '#options' => array(
+        'node' => $this->t('Nodes'),
+        'front' => $this->t('Front page'),
+        'external' => $this->t('External'),
+      ),
+      '#default_value' => array('node', 'front', 'external'),
+      '#required' => TRUE,
+    );
+    $form['max_depth'] = array(
+      '#type' => 'select',
+      '#title' => $this->t('Maximum link depth'),
+      '#options' => range(0, $this->menuLinkTree->maxDepth()),
+      '#default_value' => floor($this->menuLinkTree->maxDepth() / 2),
+      '#required' => TRUE,
+    );
+    unset($form['max_depth']['#options'][0]);
+    $form['max_width'] = array(
+      '#type' => 'number',
+      '#title' => $this->t('Maximum menu width'),
+      '#default_value' => $this->getSetting('max_width'),
+      '#description' => $this->t('Limit the width of the generated menu\'s first level of links to a certain number of items.'),
+      '#required' => TRUE,
+      '#min' => 0,
+    );
+    $form['kill'] = array(
+      '#type' => 'checkbox',
+      '#title' => $this->t('Delete existing custom generated menus and menu links before generating new ones.'),
+      '#default_value' => $this->getSetting('kill'),
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function generateElements(array $values) {
+    // If the create new menus checkbox is off, set the number of new menus to 0.
+    if (!isset($values['existing_menus']['__new-menu__']) || !$values['existing_menus']['__new-menu__']) {
+      $values['num_menus'] = 0;
+    }
+    else {
+      // Unset the aux menu to avoid attach menu new items.
+      unset($values['existing_menus']['__new-menu__']);
+    }
+
+    // Delete custom menus.
+    if ($values['kill']) {
+      $this->deleteMenus();
+      $this->setMessage($this->t('Deleted existing menus and links.'));
+    }
+
+    // Generate new menus.
+    $new_menus = $this->generateMenus($values['num_menus'], $values['title_length']);
+    if (!empty($new_menus)) {
+      $this->setMessage($this->t('Created the following new menus: @menus', array('@menus' => implode(', ', $new_menus))));
+    }
+
+    // Generate new menu links.
+    $menus = $new_menus;
+    if (isset($values['existing_menus'])) {
+      $menus = $menus + $values['existing_menus'];
+    }
+    $new_links = $this->generateLinks($values['num_links'], $menus, $values['title_length'], $values['link_types'], $values['max_depth'], $values['max_width']);
+    $this->setMessage($this->t('Created @count new menu links.', array('@count' => count($new_links))));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateDrushParams($args) {
+
+    $link_types = array('node', 'front', 'external');
+    $values = array(
+      'num_menus' => array_shift($args),
+      'num_links' => array_shift($args),
+      'kill' => drush_get_option('kill'),
+      'pipe' => drush_get_option('pipe'),
+      'link_types' => array_combine($link_types, $link_types),
+    );
+
+    $max_depth = array_shift($args);
+    $max_width = array_shift($args);
+    $values['max_depth'] = $max_depth ? $max_depth : 3;
+    $values['max_width'] = $max_width ? $max_width : 8;
+    $values['title_length'] = $this->getSetting('title_length');
+    $values['existing_menus']['__new-menu__'] = TRUE;
+
+    if ($this->isNumber($values['num_menus']) == FALSE) {
+      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid number of menus'));
+    }
+    if ($this->isNumber($values['num_links']) == FALSE) {
+      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid number of links'));
+    }
+    if ($this->isNumber($values['max_depth']) == FALSE || $values['max_depth'] > 9 || $values['max_depth'] < 1) {
+      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid maximum link depth. Use a value between 1 and 9'));
+    }
+    if ($this->isNumber($values['max_width']) == FALSE || $values['max_width'] < 1) {
+      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid maximum menu width. Use a positive numeric value.'));
+    }
+
+    return $values;
+  }
+
+  /**
+   * Deletes custom generated menus.
+   */
+  protected function deleteMenus() {
+    if ($this->moduleHandler->moduleExists('menu_ui')) {
+      $menu_ids = array();
+      foreach (menu_ui_get_menus(FALSE) as $menu => $menu_title) {
+        if (strpos($menu, 'devel-') === 0) {
+          $menu_ids[] = $menu;
+        }
+      }
+
+      if ($menu_ids) {
+        $menus = $this->menuStorage->loadMultiple($menu_ids);
+        $this->menuStorage->delete($menus);
+      }
+    }
+
+    // Delete menu links generated by devel.
+    $link_ids = $this->menuLinkContentStorage->getQuery()
+      ->condition('menu_name', 'devel', '<>')
+      ->condition('link__options', '%' . db_like('s:5:"devel";b:1') . '%', 'LIKE')
+      ->execute();
+
+    if ($link_ids) {
+      $links = $this->menuLinkContentStorage->loadMultiple($link_ids);
+      $this->menuLinkContentStorage->delete($links);
+    }
+
+  }
+
+  /**
+   * Generates new menus.
+   *
+   * @param int $num_menus
+   *   Number of menus to create.
+   * @param int $title_length
+   *   (optional) Maximum length per menu name.
+   *
+   * @return array
+   *   Array containing the generated vocabularies id.
+   */
+  protected function generateMenus($num_menus, $title_length = 12) {
+    $menus = array();
+
+    if ($this->moduleHandler->moduleExists('menu_ui')) {
+      for ($i = 1; $i <= $num_menus; $i++) {
+        $name = $this->getRandom()->word(mt_rand(2, max(2, $title_length)));
+
+        $menu = $this->menuStorage->create(array(
+          'label' => $name,
+          'id' => 'devel-' . Unicode::strtolower($name),
+          'description' => $this->t('Description of @name', array('@name' => $name)),
+        ));
+
+        $menu->save();
+        $menus[$menu->id()] = $menu->label();
+      }
+    }
+
+    return $menus;
+  }
+
+  /**
+   * Generates menu links in a tree structure.
+   */
+  protected function generateLinks($num_links, $menus, $title_length, $link_types, $max_depth, $max_width) {
+    $links = array();
+    $menus = array_keys(array_filter($menus));
+    $link_types = array_keys(array_filter($link_types));
+
+    $nids = array();
+    for ($i = 1; $i <= $num_links; $i++) {
+      // Pick a random menu.
+      $menu_name = $menus[array_rand($menus)];
+      // Build up our link.
+      $link_title = $this->getRandom()->word(mt_rand(2, max(2, $title_length)));
+      $link = $this->menuLinkContentStorage->create(array(
+        'menu_name' => $menu_name,
+        'weight' => mt_rand(-50, 50),
+        'title' => $link_title,
+        'bundle' => 'menu_link_content',
+        'description' => $this->t('Description of @title.', array('@title' => $link_title)),
+      ));
+      $link->link->options = array('devel' => TRUE);
+
+      // For the first $max_width items, make first level links.
+      if ($i <= $max_width) {
+        $depth = 0;
+      }
+      else {
+        // Otherwise, get a random parent menu depth.
+        $depth = mt_rand(1, max(1, $max_depth - 1));
+      }
+      // Get a random parent link from the proper depth.
+      do {
+        $parameters = new MenuTreeParameters();
+        $parameters->setMinDepth($depth);
+        $parameters->setMaxDepth($depth);
+        $tree = $this->menuLinkTree->load($menu_name, $parameters);
+
+        if ($tree) {
+          $link->parent = array_rand($tree);
+        }
+        $depth--;
+      } while (!$link->parent && $depth > 0);
+
+      $link_type = array_rand($link_types);
+      switch ($link_types[$link_type]) {
+        case 'node':
+          // Grab a random node ID.
+          $select = db_select('node_field_data', 'n')
+            ->fields('n', array('nid', 'title'))
+            ->condition('n.status', 1)
+            ->range(0, 1)
+            ->orderRandom();
+          // Don't put a node into the menu twice.
+          if (!empty($nids[$menu_name])) {
+            $select->condition('n.nid', $nids[$menu_name], 'NOT IN');
+          }
+          $node = $select->execute()->fetchAssoc();
+          if (isset($node['nid'])) {
+            $nids[$menu_name][] = $node['nid'];
+            $link->link->uri = 'entity:node/' . $node['nid'];
+            $link->title = $node['title'];
+            break;
+          }
+
+        case 'external':
+          $link->link->uri = 'http://www.example.com/';
+          break;
+
+        case 'front':
+          $link->link->uri = 'internal:/<front>';
+          break;
+
+        default:
+          $link->devel_link_type = $link_type;
+          break;
+      }
+
+      $link->save();
+
+      $links[$link->id()] = $link->link_title;
+    }
+
+    return $links;
+  }
+
+}

+ 267 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/TermDevelGenerate.php

@@ -0,0 +1,267 @@
+<?php
+
+namespace Drupal\devel_generate\Plugin\DevelGenerate;
+
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\devel_generate\DevelGenerateBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a TermDevelGenerate plugin.
+ *
+ * @DevelGenerate(
+ *   id = "term",
+ *   label = @Translation("terms"),
+ *   description = @Translation("Generate a given number of terms. Optionally delete current terms."),
+ *   url = "term",
+ *   permission = "administer devel_generate",
+ *   settings = {
+ *     "num" = 10,
+ *     "title_length" = 12,
+ *     "kill" = FALSE,
+ *   }
+ * )
+ */
+class TermDevelGenerate extends DevelGenerateBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The vocabulary storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $vocabularyStorage;
+
+  /**
+   * The term storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $termStorage;
+
+  /**
+   * Constructs a new TermDevelGenerate object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityStorageInterface $vocabulary_storage
+   *   The vocabulary storage.
+   * @param \Drupal\Core\Entity\EntityStorageInterface $term_storage
+   *   The term storage.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $vocabulary_storage, EntityStorageInterface $term_storage) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->vocabularyStorage = $vocabulary_storage;
+    $this->termStorage = $term_storage;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    $entity_manager = $container->get('entity.manager');
+    return new static(
+      $configuration, $plugin_id, $plugin_definition,
+      $entity_manager->getStorage('taxonomy_vocabulary'),
+      $entity_manager->getStorage('taxonomy_term')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    $options = array();
+    foreach ($this->vocabularyStorage->loadMultiple() as $vocabulary) {
+      $options[$vocabulary->id()] = $vocabulary->label();
+    }
+    $form['vids'] = array(
+      '#type' => 'select',
+      '#multiple' => TRUE,
+      '#title' => $this->t('Vocabularies'),
+      '#required' => TRUE,
+      '#default_value' => 'tags',
+      '#options' => $options,
+      '#description' => $this->t('Restrict terms to these vocabularies.'),
+    );
+    $form['num'] = array(
+      '#type' => 'number',
+      '#title' => $this->t('Number of terms?'),
+      '#default_value' => $this->getSetting('num'),
+      '#required' => TRUE,
+      '#min' => 0,
+    );
+    $form['title_length'] = array(
+      '#type' => 'number',
+      '#title' => $this->t('Maximum number of characters in term names'),
+      '#default_value' => $this->getSetting('title_length'),
+      '#required' => TRUE,
+      '#min' => 2,
+      '#max' => 255,
+    );
+    $form['kill'] = array(
+      '#type' => 'checkbox',
+      '#title' => $this->t('Delete existing terms in specified vocabularies before generating new terms.'),
+      '#default_value' => $this->getSetting('kill'),
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function generateElements(array $values) {
+    if ($values['kill']) {
+      $this->deleteVocabularyTerms($values['vids']);
+      $this->setMessage($this->t('Deleted existing terms.'));
+    }
+
+    $vocabs = $this->vocabularyStorage->loadMultiple($values['vids']);
+    $new_terms = $this->generateTerms($values['num'], $vocabs, $values['title_length']);
+    if (!empty($new_terms)) {
+      $this->setMessage($this->t('Created the following new terms: @terms', array('@terms' => implode(', ', $new_terms))));
+    }
+  }
+
+  /**
+   * Deletes all terms of given vocabularies.
+   *
+   * @param array $vids
+   *   Array of vocabulary vid.
+   */
+  protected function deleteVocabularyTerms($vids) {
+    $tids = $this->vocabularyStorage->getToplevelTids($vids);
+    $terms = $this->termStorage->loadMultiple($tids);
+    $this->termStorage->delete($terms);
+  }
+
+  /**
+   * Generates taxonomy terms for a list of given vocabularies.
+   *
+   * @param int $records
+   *   Number of terms to create in total.
+   * @param \Drupal\taxonomy\TermInterface[] $vocabs
+   *   List of vocabularies to populate.
+   * @param int $maxlength
+   *   (optional) Maximum length per term.
+   *
+   * @return array
+   *   The list of names of the created terms.
+   */
+  protected function generateTerms($records, $vocabs, $maxlength = 12) {
+    $terms = array();
+
+    // Insert new data:
+    $max = db_query('SELECT MAX(tid) FROM {taxonomy_term_data}')->fetchField();
+    $start = time();
+    for ($i = 1; $i <= $records; $i++) {
+      $name = $this->getRandom()->word(mt_rand(2, $maxlength));
+
+      $values = array(
+        'name' => $name,
+        'description' => 'description of ' . $name,
+        'format' => filter_fallback_format(),
+        'weight' => mt_rand(0, 10),
+        'langcode' => Language::LANGCODE_NOT_SPECIFIED,
+      );
+
+      switch ($i % 2) {
+        case 1:
+          $vocab = $vocabs[array_rand($vocabs)];
+          $values['vid'] = $vocab->id();
+          $values['parent'] = array(0);
+          break;
+
+        default:
+          while (TRUE) {
+            // Keep trying to find a random parent.
+            $candidate = mt_rand(1, $max);
+            $query = db_select('taxonomy_term_data', 't');
+            $parent = $query
+              ->fields('t', array('tid', 'vid'))
+              ->condition('t.vid', array_keys($vocabs), 'IN')
+              ->condition('t.tid', $candidate, '>=')
+              ->range(0, 1)
+              ->execute()
+              ->fetchAssoc();
+            if ($parent['tid']) {
+              break;
+            }
+          }
+          $values['parent'] = array($parent['tid']);
+          // Slight speedup due to this property being set.
+          $values['vid'] = $parent['vid'];
+          break;
+      }
+
+      $term = $this->termStorage->create($values);
+
+      // Populate all fields with sample values.
+      $this->populateFields($term);
+      $term->save();
+
+      $max++;
+
+      if (function_exists('drush_log')) {
+        $feedback = drush_get_option('feedback', 1000);
+        if ($i % $feedback == 0) {
+          $now = time();
+          drush_log(dt('Completed @feedback terms (@rate terms/min)', array('@feedback' => $feedback, '@rate' => $feedback * 60 / ($now - $start))), 'ok');
+          $start = $now;
+        }
+      }
+
+      // Limit memory usage. Only report first 20 created terms.
+      if ($i < 20) {
+        $terms[] = $term->label();
+      }
+
+      unset($term);
+    }
+
+    return $terms;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateDrushParams($args) {
+    $vocabulary_name = array_shift($args);
+    $number = array_shift($args);
+
+    if ($number === NULL) {
+      $number = 10;
+    }
+
+    if (!$vocabulary_name) {
+      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Please provide a vocabulary machine name.'));
+    }
+
+    if (!$this->isNumber($number)) {
+      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid number of terms: @num', array('@num' => $number)));
+    }
+
+    // Try to convert machine name to a vocabulary id.
+    if (!$vocabulary = $this->vocabularyStorage->load($vocabulary_name)) {
+      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid vocabulary name: @name', array('@name' => $vocabulary_name)));
+    }
+
+    $values = [
+      'num' => $number,
+      'kill' => drush_get_option('kill'),
+      'title_length' => 12,
+      'vids' => [$vocabulary->id()],
+    ];
+
+    return $values;
+  }
+
+}

+ 191 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/UserDevelGenerate.php

@@ -0,0 +1,191 @@
+<?php
+
+namespace Drupal\devel_generate\Plugin\DevelGenerate;
+
+use Drupal\Core\Datetime\DateFormatterInterface;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\devel_generate\DevelGenerateBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a UserDevelGenerate plugin.
+ *
+ * @DevelGenerate(
+ *   id = "user",
+ *   label = @Translation("users"),
+ *   description = @Translation("Generate a given number of users. Optionally delete current users."),
+ *   url = "user",
+ *   permission = "administer devel_generate",
+ *   settings = {
+ *     "num" = 50,
+ *     "kill" = FALSE,
+ *     "pass" = ""
+ *   }
+ * )
+ */
+class UserDevelGenerate extends DevelGenerateBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The user storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $userStorage;
+
+  /**
+   * The date formatter service.
+   *
+   * @var \Drupal\Core\Datetime\DateFormatterInterface
+   */
+  protected $dateFormatter;
+
+  /**
+   * Constructs a new UserDevelGenerate object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage
+   *   The user storage.
+   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
+   *   The date formatter service.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $entity_storage, DateFormatterInterface $date_formatter) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->userStorage = $entity_storage;
+    $this->dateFormatter = $date_formatter;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration, $plugin_id, $plugin_definition,
+      $container->get('entity.manager')->getStorage('user'),
+      $container->get('date.formatter')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    $form['num'] = array(
+      '#type' => 'number',
+      '#title' => $this->t('How many users would you like to generate?'),
+      '#default_value' => $this->getSetting('num'),
+      '#required' => TRUE,
+      '#min' => 0,
+    );
+
+    $form['kill'] = array(
+      '#type' => 'checkbox',
+      '#title' => $this->t('Delete all users (except user id 1) before generating new users.'),
+      '#default_value' => $this->getSetting('kill'),
+    );
+
+    $options = user_role_names(TRUE);
+    unset($options[DRUPAL_AUTHENTICATED_RID]);
+    $form['roles'] = array(
+      '#type' => 'checkboxes',
+      '#title' => $this->t('Which roles should the users receive?'),
+      '#description' => $this->t('Users always receive the <em>authenticated user</em> role.'),
+      '#options' => $options,
+    );
+
+    $form['pass'] = array(
+      '#type' => 'textfield',
+      '#title' => $this->t('Password to be set'),
+      '#default_value' => $this->getSetting('pass'),
+      '#size' => 32,
+      '#description' => $this->t('Leave this field empty if you do not need to set a password'),
+    );
+
+    $options = array(1 => $this->t('Now'));
+    foreach (array(3600, 86400, 604800, 2592000, 31536000) as $interval) {
+      $options[$interval] = $this->dateFormatter->formatInterval($interval, 1) . ' ' . $this->t('ago');
+    }
+    $form['time_range'] = array(
+      '#type' => 'select',
+      '#title' => $this->t('How old should user accounts be?'),
+      '#description' => $this->t('User ages will be distributed randomly from the current time, back to the selected time.'),
+      '#options' => $options,
+      '#default_value' => 604800,
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function generateElements(array $values) {
+    $num = $values['num'];
+    $kill = $values['kill'];
+    $pass = $values['pass'];
+    $age = $values['time_range'];
+    $roles = array_filter($values['roles']);
+
+    if ($kill) {
+      $uids = $this->userStorage->getQuery()
+        ->condition('uid', 1, '>')
+        ->execute();
+      $users = $this->userStorage->loadMultiple($uids);
+      $this->userStorage->delete($users);
+
+      $this->setMessage($this->formatPlural(count($uids), '1 user deleted', '@count users deleted.'));
+    }
+
+    if ($num > 0) {
+      $names = array();
+      while (count($names) < $num) {
+        $name = $this->getRandom()->word(mt_rand(6, 12));
+        $names[$name] = '';
+      }
+
+      if (empty($roles)) {
+        $roles = array(DRUPAL_AUTHENTICATED_RID);
+      }
+      foreach ($names as $name => $value) {
+        $account = $this->userStorage->create(array(
+          'uid' => NULL,
+          'name' => $name,
+          'pass' => $pass,
+          'mail' => $name . '@example.com',
+          'status' => 1,
+          'created' => REQUEST_TIME - mt_rand(0, $age),
+          'roles' => array_values($roles),
+          // A flag to let hook_user_* know that this is a generated user.
+          'devel_generate' => TRUE,
+        ));
+
+        // Populate all fields with sample values.
+        $this->populateFields($account);
+        $account->save();
+      }
+    }
+    $this->setMessage($this->t('@num_users created.', array('@num_users' => $this->formatPlural($num, '1 user', '@count users'))));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateDrushParams($args) {
+    $values = array(
+      'num' => array_shift($args),
+      'roles' => drush_get_option('roles') ? explode(',', drush_get_option('roles')) : array(),
+      'kill' => drush_get_option('kill'),
+      'pass' => drush_get_option('pass', NULL),
+      'time_range' => 0,
+    );
+    return $values;
+  }
+
+}

+ 175 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/Plugin/DevelGenerate/VocabularyDevelGenerate.php

@@ -0,0 +1,175 @@
+<?php
+
+namespace Drupal\devel_generate\Plugin\DevelGenerate;
+
+use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\devel_generate\DevelGenerateBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a VocabularyDevelGenerate plugin.
+ *
+ * @DevelGenerate(
+ *   id = "vocabulary",
+ *   label = @Translation("vocabularies"),
+ *   description = @Translation("Generate a given number of vocabularies. Optionally delete current vocabularies."),
+ *   url = "vocabs",
+ *   permission = "administer devel_generate",
+ *   settings = {
+ *     "num" = 1,
+ *     "title_length" = 12,
+ *     "kill" = FALSE
+ *   }
+ * )
+ */
+class VocabularyDevelGenerate extends DevelGenerateBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The vocabulary storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $vocabularyStorage;
+
+  /**
+   * Constructs a new VocabularyDevelGenerate object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage
+   *   The vocabulary storage.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $entity_storage) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->vocabularyStorage = $entity_storage;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration, $plugin_id, $plugin_definition,
+      $container->get('entity.manager')->getStorage('taxonomy_vocabulary')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    $form['num'] = array(
+      '#type' => 'number',
+      '#title' => $this->t('Number of vocabularies?'),
+      '#default_value' => $this->getSetting('num'),
+      '#required' => TRUE,
+      '#min' => 0,
+    );
+    $form['title_length'] = array(
+      '#type' => 'number',
+      '#title' => $this->t('Maximum number of characters in vocabulary names'),
+      '#default_value' => $this->getSetting('title_length'),
+      '#required' => TRUE,
+      '#min' => 2,
+      '#max' => 255,
+    );
+    $form['kill'] = array(
+      '#type' => 'checkbox',
+      '#title' => $this->t('Delete existing vocabularies before generating new ones.'),
+      '#default_value' => $this->getSetting('kill'),
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function generateElements(array $values) {
+    if ($values['kill']) {
+      $this->deleteVocabularies();
+      $this->setMessage($this->t('Deleted existing vocabularies.'));
+    }
+
+    $new_vocs = $this->generateVocabularies($values['num'], $values['title_length']);
+    if (!empty($new_vocs)) {
+      $this->setMessage($this->t('Created the following new vocabularies: @vocs', array('@vocs' => implode(', ', $new_vocs))));
+    }
+  }
+
+  /**
+   * Deletes all vocabularies.
+   */
+  protected function deleteVocabularies() {
+    $vocabularies = $this->vocabularyStorage->loadMultiple();
+    $this->vocabularyStorage->delete($vocabularies);
+  }
+
+  /**
+   * Generates vocabularies.
+   *
+   * @param int $records
+   *   Number of vocabularies to create.
+   * @param int $maxlength
+   *   (optional) Maximum length for vocabulary name.
+   *
+   * @return array
+   *   Array containing the generated vocabularies id.
+   */
+  protected function generateVocabularies($records, $maxlength = 12) {
+    $vocabularies = array();
+
+    // Insert new data:
+    for ($i = 1; $i <= $records; $i++) {
+      $name = $this->getRandom()->word(mt_rand(2, $maxlength));
+
+      $vocabulary = $this->vocabularyStorage->create(array(
+        'name' => $name,
+        'vid' => Unicode::strtolower($name),
+        'langcode' => Language::LANGCODE_NOT_SPECIFIED,
+        'description' => "Description of $name",
+        'hierarchy' => 1,
+        'weight' => mt_rand(0, 10),
+        'multiple' => 1,
+        'required' => 0,
+        'relations' => 1,
+      ));
+
+      // Populate all fields with sample values.
+      $this->populateFields($vocabulary);
+      $vocabulary->save();
+
+      $vocabularies[] = $vocabulary->id();
+      unset($vocabulary);
+    }
+
+    return $vocabularies;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateDrushParams($args) {
+    $values = array(
+      'num' => array_shift($args),
+      'kill' => drush_get_option('kill'),
+      'title_length' => 12,
+    );
+
+    if ($this->isNumber($values['num']) == FALSE) {
+      return drush_set_error('DEVEL_GENERATE_INVALID_INPUT', dt('Invalid number of vocabularies: @num.', array('@num' => $values['num'])));
+    }
+
+    return $values;
+  }
+
+}

+ 57 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/Routing/DevelGenerateRoutes.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace Drupal\devel_generate\Routing;
+
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Component\Plugin\PluginManagerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Provides dynamic routes for devel_generate.
+ */
+class DevelGenerateRoutes implements ContainerInjectionInterface {
+
+  /**
+   * Constructs a new devel_generate route subscriber.
+   *
+   * @param \Drupal\Component\Plugin\PluginManagerInterface $devel_generate_manager
+   *   The DevelGeneratePluginManager.
+   */
+  public function __construct(PluginManagerInterface $devel_generate_manager) {
+    $this->DevelGenerateManager = $devel_generate_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('plugin.manager.develgenerate')
+    );
+  }
+
+  public function routes() {
+    $devel_generate_plugins = $this->DevelGenerateManager->getDefinitions();
+
+    $routes = array();
+    foreach ($devel_generate_plugins as $id => $plugin) {
+      $label = $plugin['label'];
+      $type_url_str = str_replace('_', '-', $plugin['url']);
+      $routes["devel_generate.$id"] = new Route(
+        "admin/config/development/generate/$type_url_str",
+        array(
+          '_form' => '\Drupal\devel_generate\Form\DevelGenerateForm',
+          '_title' => "Generate $label",
+          '_plugin_id' => $id,
+        ),
+        array(
+          '_permission' => $plugin['permission'],
+        )
+      );
+    }
+
+    return $routes;
+  }
+
+}

+ 175 - 0
sites/all/modules/contrib/dev/devel/devel_generate/src/Tests/DevelGenerateTest.php

@@ -0,0 +1,175 @@
+<?php
+
+namespace Drupal\devel_generate\Tests;
+
+use Drupal\comment\Tests\CommentTestTrait;
+use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Language\Language;
+use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
+use Drupal\node\Entity\Node;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests the logic to generate data.
+ *
+ * @group devel_generate
+ */
+class DevelGenerateTest extends WebTestBase {
+
+  use CommentTestTrait;
+  use EntityReferenceTestTrait;
+
+  /**
+   * Vocabulary for testing.
+   *
+   * @var \Drupal\taxonomy\VocabularyInterface
+   */
+  protected $vocabulary;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('menu_ui', 'node', 'comment', 'taxonomy', 'path', 'devel_generate');
+
+  /**
+   * Prepares the testing environment
+   */
+  public function setUp() {
+    parent::setUp();
+
+    // Create Basic page and Article node types.
+    if ($this->profile != 'standard') {
+      $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic Page'));
+      $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+      $this->addDefaultCommentField('node', 'article');
+    }
+
+    // Creating a vocabulary to associate taxonomy terms generated.
+    $this->vocabulary = entity_create('taxonomy_vocabulary', array(
+      'name' => $this->randomMachineName(),
+      'description' => $this->randomMachineName(),
+      'vid' => Unicode::strtolower($this->randomMachineName()),
+      'langcode' => Language::LANGCODE_NOT_SPECIFIED,
+      'weight' => mt_rand(0, 10),
+    ));
+    $this->vocabulary->save();
+
+    // Creates a field of an entity reference field storage on article.
+    $field_name = 'taxonomy_' . $this->vocabulary->id();
+
+    $handler_settings = array(
+      'target_bundles' => array(
+        $this->vocabulary->id() => $this->vocabulary->id(),
+      ),
+      'auto_create' => TRUE,
+    );
+    $this->createEntityReferenceField('node', 'article', $field_name, NULL, 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
+
+    entity_get_form_display('node', 'article', 'default')
+      ->setComponent($field_name, array(
+        'type' => 'options_select',
+      ))
+      ->save();
+
+    entity_get_display('node', 'article', 'default')
+      ->setComponent($field_name, array(
+        'type' => 'entity_reference_label',
+      ))
+      ->save();
+
+    $admin_user = $this->drupalCreateUser(array('administer devel_generate'));
+    $this->drupalLogin($admin_user);
+  }
+
+  /**
+   * Tests generate commands
+   */
+  public function testDevelGenerate() {
+    // Creating users.
+    $edit = array(
+      'num' => 4,
+    );
+    $this->drupalPostForm('admin/config/development/generate/user', $edit, t('Generate'));
+    $this->assertText(t('4 users created.'));
+    $this->assertText(t('Generate process complete.'));
+
+    // Tests that if no content types are selected an error message is shown.
+    $edit = array(
+      'num' => 4,
+      'title_length' => 4,
+    );
+    $this->drupalPostForm('admin/config/development/generate/content', $edit, t('Generate'));
+    $this->assertText(t('Please select at least one content type'));
+
+    // Creating content.
+    // First we create a node in order to test the Delete content checkbox.
+    $this->drupalCreateNode(array('type' => 'article'));
+
+    $edit = array(
+      'num' => 4,
+      'kill' => TRUE,
+      'node_types[article]' => TRUE,
+      'time_range' => 604800,
+      'max_comments' => 3,
+      'title_length' => 4,
+      'add_alias' => 1,
+    );
+    $this->drupalPostForm('admin/config/development/generate/content', $edit, t('Generate'));
+    $this->assertText(t('Deleted 1 nodes.'));
+    $this->assertText(t('Finished creating 4 nodes'));
+    $this->assertText(t('Generate process complete.'));
+
+    // Tests that nodes have been created in the generation process.
+    $nodes = Node::loadMultiple();
+    $this->assert(count($nodes) == 4, 'Nodes generated successfully.');
+
+    // Tests url alias for the generated nodes.
+    foreach ($nodes as $node) {
+      $alias = 'node-' . $node->id() . '-' . $node->bundle();
+      $this->drupalGet($alias);
+      $this->assertResponse('200');
+      $this->assertText($node->getTitle(), 'Generated url alias for the node works.');
+    }
+
+    // Creating terms.
+    $edit = array(
+      'vids[]' => $this->vocabulary->id(),
+      'num' => 5,
+      'title_length' => 12,
+    );
+    $this->drupalPostForm('admin/config/development/generate/term', $edit, t('Generate'));
+    $this->assertText(t('Created the following new terms: '));
+    $this->assertText(t('Generate process complete.'));
+
+    // Creating vocabularies.
+    $edit = array(
+      'num' => 5,
+      'title_length' => 12,
+      'kill' => TRUE,
+    );
+    $this->drupalPostForm('admin/config/development/generate/vocabs', $edit, t('Generate'));
+    $this->assertText(t('Created the following new vocabularies: '));
+    $this->assertText(t('Generate process complete.'));
+
+    // Creating menus.
+    $edit = array(
+      'num_menus' => 5,
+      'num_links' => 7,
+      'title_length' => 12,
+      'link_types[node]' => 1,
+      'link_types[front]' => 1,
+      'link_types[external]' => 1,
+      'max_depth' => 4,
+      'max_width' => 6,
+      'kill' => 1,
+    );
+    $this->drupalPostForm('admin/config/development/generate/menu', $edit, t('Generate'));
+    $this->assertText(t('Created the following new menus: '));
+    $this->assertText(t('Created 7 new menu links'));
+    $this->assertText(t('Generate process complete.'));
+  }
+
+}

+ 14 - 0
sites/all/modules/contrib/dev/devel/devel_generate/tests/modules/devel_generate_example/devel_generate_example.info.yml

@@ -0,0 +1,14 @@
+name: 'Devel generate Example'
+type: module
+description: 'Create an example of DevelGenerate plugin type for testing purposing.'
+package: Development
+# core: 8.x
+configure: admin/config/development/generate
+tags:
+ - developer
+
+# Information added by Drupal.org packaging script on 2016-09-03
+version: '8.x-1.0-alpha1+23-dev'
+core: '8.x'
+project: 'devel'
+datestamp: 1472897643

+ 1 - 0
sites/all/modules/contrib/dev/devel/devel_generate/tests/modules/devel_generate_example/devel_generate_example.module

@@ -0,0 +1 @@
+<?php

+ 88 - 0
sites/all/modules/contrib/dev/devel/devel_generate/tests/modules/devel_generate_example/src/Plugin/DevelGenerate/ExampleDevelGenerate.php

@@ -0,0 +1,88 @@
+<?php
+
+namespace Drupal\devel_generate_example\Plugin\DevelGenerate;
+
+use Drupal\devel_generate\DevelGenerateBase;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a ExampleDevelGenerate plugin.
+ *
+ * @DevelGenerate(
+ *   id = "devel_generate_example",
+ *   label = "Example",
+ *   description = "Generate a given number of examples. Optionally delete current examples.",
+ *   url = "devel_generate_example",
+ *   permission = "administer devel_generate",
+ *   settings = {
+ *     "num" = 50,
+ *     "kill" = FALSE
+ *   }
+ * )
+ */
+class ExampleDevelGenerate extends DevelGenerateBase {
+
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+
+    $form['num'] = array(
+      '#type' => 'textfield',
+      '#title' => $this->t('How many examples would you like to generate?'),
+      '#default_value' => $this->getSetting('num'),
+      '#size' => 10,
+    );
+
+    $form['kill'] = array(
+      '#type' => 'checkbox',
+      '#title' => $this->t('Delete all examples before generating new examples.'),
+      '#default_value' => $this->getSetting('kill'),
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function generateElements(array $values) {
+    $num = $values['num'];
+    $kill = $values['kill'];
+
+    if ($kill) {
+        $this->setMessage($this->t('Old examples have been deleted.'));
+    }
+
+    //Creating user in order to demonstrate
+    // how to override default business login generation.
+    $edit = array(
+      'uid'     => NULL,
+      'name'    => 'example_devel_generate',
+      'pass'    => '',
+      'mail'    => 'example_devel_generate@example.com',
+      'status'  => 1,
+      'created' => REQUEST_TIME,
+      'roles' => '',
+      'devel_generate' => TRUE // A flag to let hook_user_* know that this is a generated user.
+    );
+
+    $account = user_load_by_name('example_devel_generate');
+    if (!$account) {
+      $account = entity_create('user', $edit);
+    }
+
+    // Populate all fields with sample values.
+    $this->populateFields($node);
+
+    $account->save();
+
+    $this->setMessage($this->t('@num_examples created.', array('@num_examples' => $this->formatPlural($num, '1 example', '@count examples'))));
+  }
+
+  public function validateDrushParams($args) {
+    $values = array(
+      'num' => array_shift($args),
+      'kill' => drush_get_option('kill'),
+    );
+    return $values;
+  }
+
+}

+ 93 - 0
sites/all/modules/contrib/dev/devel/devel_generate/tests/src/DevelGenerateManagerTest.php

@@ -0,0 +1,93 @@
+<?php
+
+namespace Drupal\Tests\devel_generate;
+
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\devel_generate\DevelGeneratePluginManager;
+use Drupal\Tests\UnitTestCase;
+use Drupal\Core\Language\Language;
+
+if (!defined('DRUPAL_ROOT')) {
+  //Looping to find drupal root folder.
+  $current_dir = dirname(__DIR__);
+  while (!file_exists("$current_dir/index.php")) {
+    $current_dir = dirname($current_dir);
+  }
+  define('DRUPAL_ROOT', $current_dir);
+}
+
+/**
+ * @coversDefaultClass \Drupal\devel_generate\DevelGeneratePluginManager
+ * @group devel_generate
+ */
+class DevelGenerateManagerTest extends UnitTestCase {
+
+  /**
+   * The plugin discovery.
+   *
+   * @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $discovery;
+
+  /**
+   * A list of devel generate plugin definitions.
+   *
+   * @var array
+   */
+  protected $definitions = array(
+    'devel_generate_example' => array(
+      'id' => 'devel_generate_example',
+      'class' => 'Drupal\devel_generate_example\Plugin\DevelGenerate\ExampleDevelGenerate',
+      'url' => 'devel_generate_example',
+    ),
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    // Mock a Discovery object to replace AnnotationClassDiscovery.
+    $this->discovery = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface');
+    $this->discovery->expects($this->any())
+      ->method('getDefinitions')
+      ->will($this->returnValue($this->definitions));
+
+  }
+
+  /**
+   * Test creating an instance of the DevelGenerateManager.
+   */
+  public function testCreateInstance() {
+    $namespaces = new \ArrayObject(array('Drupal\devel_generate_example' => realpath(dirname(__FILE__) . '/../../../modules/devel_generate_example/lib')));
+    $cache_backend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
+
+    $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+    $manager = new TestDevelGeneratePluginManager($namespaces, $cache_backend, $module_handler);
+    $manager->setDiscovery($this->discovery);
+
+    $example_instance = $manager->createInstance('devel_generate_example');
+    $plugin_def = $example_instance->getPluginDefinition();
+
+    $this->assertInstanceOf('Drupal\devel_generate_example\Plugin\DevelGenerate\ExampleDevelGenerate', $example_instance);
+    $this->assertArrayHasKey('url', $plugin_def);
+    $this->assertTrue($plugin_def['url'] == 'devel_generate_example');
+  }
+
+}
+
+/**
+ * Provides a testing version of DevelGeneratePluginManager with an empty
+ * constructor.
+ */
+class TestDevelGeneratePluginManager extends DevelGeneratePluginManager {
+  /**
+   * Sets the discovery for the manager.
+   *
+   * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $discovery
+   *   The discovery object.
+   */
+  public function setDiscovery(DiscoveryInterface $discovery) {
+    $this->discovery = $discovery;
+  }
+}

+ 42 - 0
sites/all/modules/contrib/dev/devel/devel_node_access/README.txt

@@ -0,0 +1,42 @@
+README
+======
+
+This module contains tools for developers using access control modules
+to restrict access to some nodes.  It is intended to help catch some
+common mistakes and provide feedback to confirm that restricted nodes
+are in fact visible only to the intended users.
+
+Provides a summary page which queries the node_access table and
+reports common mistakes such as the presence of Drupal's default entry
+which grants all users read access to all nodes.  Also reports the
+presence of nodes not represented in node_access table.  This may
+occur when an access control module is installed after nodes have
+already been created.
+
+Provides a block which shows all node_access entries for the nodes
+shown on a given page.  This gives developers a quick check to see
+that grants are provided as they should be.  This block auto-enables
+to the footer region. You may move it as desired.
+
+If Views module is installed, allows browsing of nodes by realm,
+including those nodes not in the node_access table (NULL realm).
+
+WISHLIST
+========
+
+Things I'd like to see but haven't had time to do:
+
+* Automatically solve common problems.  I.e. delete the "all" realm
+  entry, and automatically save all nodes not in the node_access table.
+
+* Nicer feedback indicating whether nodes are visible to the public or
+  not.  I.e. use color coding or icons.
+
+* Summary does not differentiate between view grants and other types
+  of grants.  I personally use node_access only for view grants so I'm
+  not sure exactly what else it should show.
+
+AUTHOR
+======
+
+Dave Cohen AKA yogadex on drupal.org

+ 3 - 0
sites/all/modules/contrib/dev/devel/devel_node_access/config/install/devel_node_access.settings.yml

@@ -0,0 +1,3 @@
+debug_mode: FALSE
+by_user_mode: FALSE
+user_ajax: FALSE

+ 15 - 0
sites/all/modules/contrib/dev/devel/devel_node_access/config/schema/devel_node_access.schema.yml

@@ -0,0 +1,15 @@
+# Schema for the configuration files of the Devel Node Access module.
+
+devel_node_access.settings:
+  type: mapping
+  label: 'Devel Node Access settings'
+  mapping:
+    debug_mode:
+      type: boolean
+      label: 'Debug Mode'
+    by_user_mode:
+      type: boolean
+      label: 'By-User Analysis'
+    user_ajax:
+      type: boolean
+      label: 'User AJAX'

+ 5 - 0
sites/all/modules/contrib/dev/devel/devel_node_access/css/devel_node_access.module.css

@@ -0,0 +1,5 @@
+
+div.devel-node-access-inline > div {
+    display: inline-block;
+}
+

+ 81 - 0
sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.api.php

@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @file
+ * Hook provided by the Devel Node Access module.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Explain your records in the {node_access} table.
+ *
+ * In order to help developers and administrators understand the forces
+ * that control access to any given node, the DNA module provides the
+ * Devel Node Access block, which lists all the grant records in the
+ * {node_access} table for that node.
+ *
+ * However, every Node Access module is free in how it defines and uses the
+ * 'realm' and 'gid' fields in its records in the {node_access} table, and
+ * it's often difficult to interpret them. This hook passes each record
+ * that DNA wants to display, and the owning module is expected to return
+ * an explanation of that record.
+ *
+ * The explanation should not be localized (not be passed through t()), so
+ * that administrators seeking help can present English explanations.
+ *
+ * @param $row
+ *   The record from the {node_access} table, as object. The member fields are:
+ *   nid, gid, realm, grant_view, grant_update, grant_delete.
+ *
+ * @return string|null
+ *   A string with a (short!) explanation of the given {node_access} row,
+ *   to be displayed in DNA's 'Devel Node Access' block. It will be displayed
+ *   as HTML; any variable parts must already be sanitized.
+ *
+ * @see hook_node_access_records()
+ * @see devel_node_access_node_access_explain()
+ *
+ * @ingroup node_access
+ */
+function hook_node_access_explain($row) {
+  if ($row->realm == 'mymodule_myrealm') {
+    if ($row->grant_view) {
+      /** @var \Drupal\user\RoleInterface $role */
+      $role = \Drupal\user\Entity\Role::load($row->gid);
+      return t('Role %role may view this node.', array('%role' => $role->get('name')));
+    }
+    else {
+      return 'No access.';
+    }
+  }
+  return null;
+}
+
+/**
+ * Acknowledge ownership of 'alien' grant records.
+ *
+ * Some node access modules store grant records directly into the {node_access}
+ * table rather than returning them through hook_node_access_records(). This
+ * practice is not recommended and DNA will flag all such records as 'alien'.
+ *
+ * If this is unavoidable, a module can confess to being the owner of these
+ * grant records, so that DNA can properly attribute them.
+ *
+ * @see hook_node_access_records()
+ *
+ * @ingroup node_access
+ */
+function hook_node_access_acknowledge($grant) {
+  if ($grant['realm'] == 'mymodule_all' && $grant['nid'] == 0) {
+    return TRUE;
+  }
+  return NULL;
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */

+ 16 - 0
sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.info.yml

@@ -0,0 +1,16 @@
+type: module
+name: 'Devel Node Access'
+description: 'Developer blocks and page illustrating relevant node_access records.'
+package: Development
+# core: 8.x
+dependencies:
+ - devel
+ - menu_ui
+tags:
+ - developer
+
+# Information added by Drupal.org packaging script on 2016-09-03
+version: '8.x-1.0-alpha1+23-dev'
+core: '8.x'
+project: 'devel'
+datestamp: 1472897643

+ 7 - 0
sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.install

@@ -0,0 +1,7 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the Devel Node Access module.
+ */
+

+ 64 - 0
sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.js

@@ -0,0 +1,64 @@
+/**
+ * @file devel_node_access.js.
+ */
+
+(function ($) {
+
+  /**
+   * Perform the access by user ajax request.
+   */
+  function devel_node_access_user_ajax(context, settings) {
+    // Get the cell ID for the first .dna-permission that isn't processed.
+    var cell = $('td.dna-permission', context)
+               .not('.ajax-processed', context)
+               .attr('id');
+    if (cell !== undefined) {
+      // Generate the URI from the basePath, path, data type, cell ID, and a
+      // random token to bypass caching.
+      var url = settings.path.basePath
+              + "?q="
+              + 'devel/node_access/by_user/json/'
+              + cell
+              + '/'
+              + Math.floor((1000000000 * Math.random())).toString(16);
+      // Execute Ajax callback and handle the response.
+      $.getJSON(url, function(data) {
+        $('#' + cell, context).html(data).addClass('ajax-processed');
+        // Call this function again.
+        devel_node_access_user_ajax(context);
+      });
+      // Ajax fails silently on error, mark bad requests with an error message.
+      // If the request is just slow this will update when the request succeeds.
+      setTimeout(
+        function() {
+          if ($('#' + cell, context).hasClass('ajax-processed') == false) {
+            $('#' + cell, context)
+              .html(
+                '<span class="error">'
+                + '<a href="' + url.replace('/json/', '/html/') + '">'
+                + Drupal.t('Error: could not explain access')
+                + '</a>'
+                + '</span>'
+              )
+              .addClass('ajax-processed');
+            // Call this function again.
+            devel_node_access_user_ajax(context);
+          }
+        },
+        3000
+      );
+
+    }
+  }
+
+  /**
+   * Attach the access by user behavior which initiates ajax.
+   */
+  Drupal.behaviors.develNodeAccessUserAjax = {
+    attach: function(context, settings) {
+      // Start the ajax.
+      devel_node_access_user_ajax(context, settings);
+    }
+  };
+
+})(jQuery);

+ 7 - 0
sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.libraries.yml

@@ -0,0 +1,7 @@
+devel_node_access:
+  version: 0
+  js:
+    devel_node_access.js: {}
+  css:
+    component:
+      css/devel_node_access.module.css: {}

+ 269 - 0
sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.module

@@ -0,0 +1,269 @@
+<?php
+/**
+ * @file
+ * This module gives developers feedback as to what their
+ * node_access table contains, and which nodes are protected or
+ * visible to the public.
+ */
+
+use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\devel_node_access\Plugin\Block\DnaBlock;
+
+define('DNA_ACCESS_VIEW', 'view devel_node_access information');
+
+/**
+ * Implements hook_help().
+ *
+ * {@inheritdoc}
+ */
+function devel_node_access_help($route_name, \Drupal\Core\Routing\RouteMatchInterface $route_match) {
+  switch ($route_name) {
+    case 'help.page.devel_node_access':
+      $output  = '<p>' . t('This module helps in site development.  Specifically, when an access control module is used to limit access to some or all nodes, this module provides feedback showing the node_access table in the database.') . "</p>\n";
+      $output .= '<p>' . t('The node_access table is one method Drupal provides to hide content from some users while displaying it to others.  By default, Drupal shows all nodes to all users.  There are a number of optional modules which may be installed to hide content from specific users based on various criteria.') . "</p>\n";
+      $output .= '<p>' . t('If you have not installed any of these modules, you really have no need for the devel_node_access module.  This module is intended for use during development, so that developers and admins can confirm that the node_access table is working as expected.  You probably do not want this module enabled on a production site.') . "</p>\n";
+      $output .= '<p>' . t('To use this module, enable its Devel Node Access block in a wide region. The block shows the entries in the node_access table for any nodes on the current page, and it provides options to display much more information at the cost of some overhead (requires JavaScript).') . "</p>\n";
+//      $output .= '<p>' . t('This module also provides a <a href="@summary_page">summary page</a> which shows general information about your node_access table.  If you have installed the Views module, you may browse node_access by realm.',
+//                          array('@summary_page' => url('devel/node_access/summary'))
+//                          ) . "</p>\n";
+      return $output;
+  }
+  return NULL;
+}
+
+/**
+ * Implements hook_menu().
+ */
+function devel_node_access_menu() {
+  $items = array();
+
+  if (!\Drupal::moduleHandler()->moduleExists('devel')) {
+    // We have to create the 'Devel settings' menu item ourselves.
+    $items['admin/config/development/devel'] = array(
+      'title'            => 'Devel settings',
+      'description'      => 'Helper pages and blocks to assist Drupal developers and admins with node_access. The devel blocks can be managed via the <a href="' . url('admin/structure/block') . '">block administration</a> page.',
+      'page callback'    => 'drupal_get_form',
+      'page arguments'   => array('devel_node_access_admin_settings'),
+      'access arguments' => array('administer site configuration'),
+    );
+    $items['devel/settings'] = $items['admin/config/development/devel'] + array(
+      'menu_name' => 'devel',
+    );
+  }
+
+  // Create a callback for use by devel_node_access_user_ajax().
+  $items['devel/node_access/by_user/%/%'] = array(
+    'page callback'    => 'devel_node_access_user_ajax',
+    'page arguments'   => array(3, 4),
+    'access arguments' => array(DNA_ACCESS_VIEW),
+    'type'             => MENU_CALLBACK,
+  );
+
+  // Add this to the custom menu 'devel' created by the devel module.
+  $items['devel/node_access/summary'] = array(
+    'title'            => 'Node_access summary',
+    'page callback'    => 'dna_summary',
+    'access arguments' => array(DNA_ACCESS_VIEW),
+    'menu_name'        => 'devel',
+  );
+
+  return $items;
+}
+
+/**
+ * Builds the DNA Summary page.
+ */
+function dna_summary() {
+  // Warn user if they have any entries that could grant access to all nodes.
+  $output = '';
+  $result = db_query('SELECT DISTINCT realm FROM {node_access} WHERE nid = 0 AND gid = 0');
+  $rows = array();
+  foreach ($result as $row) {
+    $rows[] = array($row->realm);
+  }
+  if (!empty($rows)) {
+    $output .= '<h3>' . t('Access Granted to All Nodes (All Users)') . "</h3>\n";
+    $output .= '<p>' . t('Your node_access table contains entries that may be granting all users access to all nodes.  Depending on which access control module(s) you use, you may want to delete these entries.  If you are not using an access control module, you should probably leave these entries as is.') . "</p>\n";
+    $headers = array(t('realm'));
+    $output .= theme('table', array('header' => $headers, 'rows' => $rows));
+    $access_granted_to_all_nodes = TRUE;
+  }
+
+  // How many nodes are not represented in the node_access table?
+  $num = db_query('SELECT COUNT(n.nid) AS num_nodes FROM {node} n LEFT JOIN {node_access} na ON n.nid = na.nid WHERE na.nid IS NULL')->fetchField();
+  if ($num) {
+    $output .= '<h3>' . t('Legacy Nodes') . "</h3>\n";
+    $output .= '<p>' .
+      t('You have !num nodes in your node table which are not represented in your node_access table.  If you have an access control module installed, these nodes may be hidden from all users.  This could be caused by publishing nodes before enabling the access control module.  If this is the case, manually updating each node should add it to the node_access table and fix the problem.', array('!num' => l($num, 'devel/node_access/view/NULL')))
+      . "</p>\n";
+    if (!empty($access_granted_to_all_nodes)) {
+      $output .= '<p>' .
+        t('This issue may be masked by the one above, so look into the former first.')
+        . "</p>\n";
+    }
+  }
+  else {
+    $output .= '<h3>' . t('All Nodes Represented') . "</h3>\n";
+    $output .= '<p>' . t('All nodes are represented in the node_access table.') . "</p>\n";
+  }
+
+
+  // A similar warning to the one above, but slightly more specific.
+  $result = db_query('SELECT DISTINCT realm FROM {node_access} WHERE nid = 0 AND gid <> 0');
+  $rows = array();
+  foreach ($result as $row) {
+    $rows[] = array($row->realm);
+  }
+  if (!empty($rows)) {
+    $output .= '<h3>' . t('Access Granted to All Nodes (Some Users)') . "</h3>\n";
+    $output .= '<p>' . t('Your node_access table contains entries that may be granting some users access to all nodes.  This may be perfectly normal, depending on which access control module(s) you use.') . "</p>\n";
+    $headers = array(t('realm'));
+    $output .= theme('table', array('header' => $headers, 'rows' => $rows));
+  }
+
+
+  // Find specific nodes which may be visible to all users.
+  $result = db_query('SELECT DISTINCT realm, COUNT(DISTINCT nid) as node_count FROM {node_access} WHERE gid = 0 AND nid > 0 GROUP BY realm');
+  $rows = array();
+  foreach ($result as $row) {
+    $rows[] = array(
+      $row->realm,
+      array(
+        'data'  => $row->node_count,
+        'align' => 'center',
+      ),
+    );
+  }
+  if (!empty($rows)) {
+    $output .= '<h3>' . t('Access Granted to Some Nodes') . "</h3>\n";
+    $output .= '<p>' .
+      t('The following realms appear to grant all users access to some specific nodes. This may be perfectly normal, if some of your content is available to the public.')
+      . "</p>\n";
+    $headers = array(t('realm'), t('public nodes'));
+    $output .= theme('table', array('header' => $headers, 'rows' => $rows, 'caption' => t('Public Nodes')));
+  }
+
+
+  // Find specific nodes protected by node_access table.
+  $result = db_query('SELECT DISTINCT realm, COUNT(DISTINCT nid) as node_count FROM {node_access} WHERE gid <> 0 AND nid > 0 GROUP BY realm');
+  $rows = array();
+  foreach ($result as $row) {
+    // No Views yet:
+    //$rows[] = array(l($row->realm, "devel/node_access/view/$row->realm"),
+    $rows[] = array(
+      $row->realm,
+      array(
+        'data' => $row->node_count,
+        'align' => 'center',
+      ),
+    );
+  }
+  if (!empty($rows)) {
+    $output .= '<h3>' . t('Summary by Realm') . "</h3>\n";
+    $output .= '<p>' . t('The following realms grant limited access to some specific nodes.') . "</p>\n";
+    $headers = array(t('realm'), t('private nodes'));
+    $output .= theme('table', array('header' => $headers, 'rows' => $rows, 'caption' => t('Protected Nodes')));
+  }
+
+  return $output;
+}
+
+/**
+ * Implements hook_node_view().
+ *
+ * {@inheritdoc}
+ */
+function devel_node_access_node_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
+  // Remember this node, for display in our block.
+  DnaBlock::visibleNodes($entity->id());
+}
+
+/**
+ * Callback function for Node Access by User block ajax.
+ */
+function devel_node_access_user_ajax($data_type, $cell) {
+  list($op, $nid, $uid) = explode('-', $cell);
+  $node = node_load($nid);
+  $account = user_load($uid);
+  $output = array(
+    '#theme' => 'dna_permission',
+    '#permission' => DnaBlock::explainAccess($op, $node, $account),
+  );
+  // JSON output for Ajax callbacks.
+  if ($data_type == 'json') {
+    drupal_json_output(\Drupal::service('renderer')->render($output));
+    exit;
+  }
+  // HTML output for error message click-throughs.
+  if ($node) {
+    $node_title = l($node->title, 'node/' . $node->id());
+  }
+  else {
+    $node_title = t('unknown node %nid', array('%nid' => $nid));
+  }
+  drupal_set_title(
+    t(
+      'Devel Node Access: %op permission for !user on !node',
+      array(
+        '%op'   => $op,
+        '!user' => theme('username', array('account' => $account)),
+        '!node' => $node_title,
+      )
+    ),
+    PASS_THROUGH
+  );
+  return $output;
+}
+
+/**
+ * Implements hook_node_access_explain().
+ *
+ * {@inheritdoc}
+ */
+function devel_node_access_node_access_explain($row) {
+  if ($row->gid == 0 && $row->realm == 'all') {
+    foreach (array('view', 'update', 'delete') as $op) {
+      $gop = 'grant_' . $op;
+      if (!empty($row->$gop)) {
+        $ops[] = $op;
+      }
+    }
+    if (empty($ops)) {
+      return '(No access granted to ' . ($row->nid == 0 ? 'any nodes.)' : 'this node.)');
+    }
+    else {
+      return 'All users may ' . implode('/', $ops) . ($row->nid == 0 ? ' all nodes.' : ' this node.');
+    }
+  }
+  if (\Drupal::moduleHandler()->moduleExists('node_access_test')) {
+    switch ($row->realm) {
+      case 'node_access_test_author':
+        return "Author (uid=$row->gid) has full access.";
+      case 'node_access_test':
+        return "Users with the 'node test view' permission may view.";
+    }
+  }
+  return NULL;
+}
+
+/**
+ * Implements hook_theme().
+ */
+function devel_node_access_theme() {
+  return array(
+    'dna_permission' => array(
+      'variables'    => array(
+        'permission' => NULL,
+      ),
+    ),
+  );
+}
+
+/**
+ * Indicates whether user has a permission or not.
+ */
+function theme_dna_permission($variables) {
+  $permission = &$variables['permission'];
+  return '<span class="' . ($permission[0] ? 'ok' : 'error') . '" title="' . $permission[2] . '">' . $permission[1] . '</span>';
+}

+ 4 - 0
sites/all/modules/contrib/dev/devel/devel_node_access/devel_node_access.permissions.yml

@@ -0,0 +1,4 @@
+view devel_node_access information:
+  title: 'Access DNA information'
+  description: 'View the node_access information block on node pages and the summary page.'
+  restrict access: TRUE

+ 135 - 0
sites/all/modules/contrib/dev/devel/devel_node_access/src/Form/DnaForm.php

@@ -0,0 +1,135 @@
+<?php
+
+namespace Drupal\devel_node_access\Form;
+
+use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\devel_node_access\Plugin\Block\DnaBlock;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Defines the form to change the DNA settings.
+ */
+class DnaForm extends FormBase {
+
+  /**
+   * Constructs a new DnaForm object.
+   */
+  public function __construct() {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'devel_dna_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    $form['#attached'] = array(
+      'library' =>  array(
+        'devel_node_access/devel_node_access'
+      ),
+    );
+
+    $debug_mode = \Drupal::config('devel_node_access.settings')->get('debug_mode');
+    $by_user_mode = \Drupal::config('devel_node_access.settings')->get('by_user_mode');
+
+    $form['node_content'] = array(
+      '#prefix' => '<div id="devel-node-access-node-content-div">',
+      '#suffix' => '</div>',
+    );
+    $form['node_content'][0] = DnaBlock::buildNodeInfo($debug_mode);
+
+    $form['user_content'] = array(
+      '#prefix' => '<div id="devel-node-access-by-user-content-div">',
+      '#suffix' => '</div>',
+    );
+    if ($by_user_mode) {
+      $form['user_content'][0] =  DnaBlock::buildByUserInfo();
+    }
+
+    $form['setup'] = array(
+      '#markup' => t('Enable:'),
+      '#prefix' => '<div class="devel-node-access-inline">',
+      '#suffix' => '</div>',
+    );
+    $form['setup']['debug_mode'] = array(
+      '#type' => 'checkbox',
+      '#value' => $debug_mode,
+      '#prefix' => ' &nbsp; &nbsp; ',
+      '#title' => t('Debug Mode'),
+      '#ajax' => array(
+        'callback' => '::toggleDebugMode',
+        'wrapper' => 'devel-node-access-node-content-div',
+      ),
+      '#disabled' => TRUE,
+    );
+    $form['setup']['by_user_mode'] = array(
+      '#type' => 'checkbox',
+      '#value' => $by_user_mode,
+      '#prefix' => ' &nbsp; &nbsp; ',
+      '#title' => t('By-User Analysis (slow!)'),
+      '#ajax' => array(
+        'callback' => '::toggleByUserMode',
+        'wrapper' => 'devel-node-access-by-user-content-div',
+      ),
+      '#disabled' => TRUE,
+    );
+
+    return $form;
+  }
+
+  /**
+   * AJAX handler for form_state.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   *
+   * @return array
+   */
+  public function toggleDebugMode($form, FormStateInterface $form_state) {
+    $debug_mode = $form_state->getUserInput();
+    $debug_mode = !empty($debug_mode['debug_mode']);
+    \Drupal::configFactory()->getEditable('devel_node_access.settings')->set('debug_mode', $debug_mode)->save(TRUE);
+    $form['node_content'][0] = DnaBlock::buildNodeInfo($debug_mode);
+    return $form['node_content'];
+  }
+
+  /**
+   * AJAX handler for by_user_state.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   *
+   * @return array
+   */
+  public function toggleByUserMode($form, FormStateInterface $form_state) {
+    $by_user_mode = $form_state->getUserInput();
+    $by_user_mode = !empty($by_user_mode['by_user_mode']);
+    \Drupal::configFactory()->getEditable('devel_node_access.settings')->set('by_user_mode', $by_user_mode)->save(TRUE);
+    $form['user_content'][0] = ($by_user_mode ? DnaBlock::buildByUserInfo() : []);
+    return $form['user_content'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+  }
+
+}

+ 1263 - 0
sites/all/modules/contrib/dev/devel/devel_node_access/src/Plugin/Block/DnaBlock.php

@@ -0,0 +1,1263 @@
+<?php
+
+namespace Drupal\devel_node_access\Plugin\Block;
+
+use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Block\BlockBase;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormBuilderInterface;
+use Drupal\Core\Link;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Routing\RedirectDestinationTrait;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Url;
+use Drupal\node\Entity\Node;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides the "Devel Node Access" block.
+ *
+ * @Block(
+ *   id = "devel_dna_block",
+ *   admin_label = @Translation("Devel Node Access"),
+ *   category = @Translation("Devel Node Access")
+ * )
+ */
+class DnaBlock extends BlockBase implements ContainerFactoryPluginInterface {
+
+  private $node_access = array('@node_access' => 'node_access');
+
+  use RedirectDestinationTrait;
+
+  /**
+   * The FormBuilder object.
+   *
+   * @var \Drupal\Core\Form\FormBuilderInterface
+   */
+  protected $formBuilder;
+
+  /**
+   * The Current User object.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $currentUser;
+
+  /**
+   * The user storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $userStorage;
+
+  /**
+   * Constructs a new DnaBlock object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Session\AccountInterface $current_user
+   *   Current user.
+   * @param \Drupal\Core\Entity\EntityStorageInterface $user_storage
+   *   The user storage.
+   * @param \Drupal\Core\Form\FormBuilderInterface $form_builder
+   *   The form builder service.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, AccountInterface $current_user, EntityStorageInterface $user_storage, FormBuilderInterface $form_builder) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->formBuilder = $form_builder;
+    $this->currentUser = $current_user;
+    $this->userStorage = $user_storage;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    /** @noinspection PhpParamsInspection */
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('current_user'),
+      $container->get('entity.manager')->getStorage('user'),
+      $container->get('form_builder')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function blockAccess(AccountInterface $account) {
+    return AccessResult::allowedIfHasPermission($account, DNA_ACCESS_VIEW);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    $build['#cache'] = ['max-age' => 0];
+
+//    $headers = array(
+//      array('data' => t('node'), 'style' => 'text-align:right;'),
+//      array('data' => t('prio'), 'style' => 'text-align:right;'),
+//      t('status'),
+//      t('realm'),
+//      array('data' => t('gid'), 'style' => 'text-align:right;'),
+//      t('view'),
+//      t('update'),
+//      t('delete'),
+//      t('explained'),
+//    );
+//    $rows[] = array('data' => array(array('data' => 1, 'style' => 'background-color: red; color: blue'),
+//                                    "CACHE 5", 3, 4, 5));
+
+    if (empty(self::visibleNodes())) {
+      $request_uri = \Drupal::request()->getRequestUri();
+      if ($request_uri === '/' || $request_uri === '/node') {
+        $build['#markup'] = t('@node_access information is not available for the nodes on this page due to caching &mdash; flush your caches to display it.', $this->node_access);
+      }
+      return $build;
+    }
+
+    $build['#title'] = t('@node_access entries for nodes shown on this page', $this->node_access);
+//    $build['test_table'] = array(
+//      '#type' => 'table',
+//      '#header' => $headers,
+//      //      array(
+//      //        t('Column 0'),
+//      //        array('data' => t('Active'), 'colspan' => '2'),
+//      //        array('data' => t('Staged'), 'colspan' => '2'),
+//      //      ),
+//      '#rows' => $rows,
+//      '#empty' => $this->t('No records found!'),
+//      '#responsive' => FALSE,
+//      '#attributes' => array(
+//        'class'       => array(),
+//        'style'       => 'text-align: left;',
+//      ),
+//    );
+
+    $build['dna_form'] = $this->formBuilder->getForm('\Drupal\devel_node_access\Form\DnaForm');
+    return $build;
+  }
+
+  /**
+   * Builds and returns the node information.
+   *
+   * @param bool $debug_mode
+   *   The level of detail to include.
+   *
+   * @return array
+   */
+  public static function buildNodeInfo($debug_mode) {
+    global $user;
+
+    $visible_nodes = self::visibleNodes();
+    if (count($visible_nodes) == 0) {
+      return array();
+    }
+    else {
+      $single_nid = reset($visible_nodes);
+    }
+
+    // Find out whether our DnaUser block is active or not.
+    //dpm($blocks = \Drupal::entityTypeManager()->getStorage('block')->load());
+    $user_block_active = FALSE;
+    //foreach ($blocks as $block) {
+    //  if ($block->get('plugin') == 'devel_dna_user_block') {
+    //    $user_block_active = TRUE;
+    //  }
+    //}
+
+
+    // Include rows where nid == 0.
+    $nids = array_merge(array(0 => 0), $visible_nodes);
+    $query = \Drupal::database()->select('node_access', 'na');
+    $query
+      ->fields('na')
+      ->condition('na.nid', $nids, 'IN');
+    $query
+      ->orderBy('na.nid')
+      ->orderBy('na.realm')
+      ->orderBy('na.gid');
+    $nodes = Node::loadMultiple($nids);
+
+    if (!$debug_mode) {
+      $headers = array('node', 'realm', 'gid', 'view', 'update', 'delete', 'explained');
+      $rows = array();
+      foreach ($query->execute() as $row) {
+        $explained = \Drupal::moduleHandler()->invokeAll('node_access_explain', [$row]);
+        $node_title = self::get_node_title($nodes[$row->nid]);
+        $title_attribute = \Drupal::request()->getRequestUri();
+        if (Unicode::strlen($node_title) > 20) {
+          $title_attribute = $title_attribute . ': ' . $node_title;
+          $node_title = Unicode::substr($node_title, 0, 18) . '...';
+        }
+
+        $rows[]     = array(
+          (empty($row->nid) ? '0'
+            : Link::fromTextAndUrl(
+              $node_title,
+              Url::fromUri(
+                \Drupal::request()->getUri(),
+                [
+                  'fragment' => 'node-' . $row->nid,
+                  'attributes' => ['title' => $title_attribute]
+                ]
+              )
+            )
+          ),
+          $row->realm,
+          $row->gid,
+          $row->grant_view,
+          $row->grant_update,
+          $row->grant_delete,
+          implode('<br />', $explained),
+        );
+      }
+      $output[] = array(
+        '#theme'      => 'table',
+        '#header'     => $headers,
+        '#rows'       => $rows,
+        '#attributes' => array('style' => 'text-align: left'),
+      );
+    }
+    else {
+      $tr = 't';
+      $variables = array('@na' => '{node_access}');
+      $states = array(
+        'default'      => array(t('default'),      'ok',      t('Default record supplied by core in the absence of any other non-empty records; in @na.', $variables)),
+        'ok'           => array(t('ok'),           'ok',      t('Highest priority record; in @na.', $variables)),
+        'removed'      => array(t('removed'),      '',        t('Was removed in @func; not in @na.', $variables + array('@func' => 'hook_node_access_records_alter()'))),
+        'static'       => array(t('static'),       'ok',      t('Non-standard record in @na.', $variables)),
+        'unexpected'   => array(t('unexpected'),   'warning', t('The 0/all/0/... record applies to all nodes and all users -- usually it should not be present in @na if any node access module is active!')),
+        'ignored'      => array(t('ignored'),      'warning', t('Lower priority record; not in @na and thus ignored.', $variables)),
+        'empty'        => array(t('empty'),        'warning', t('Does not grant any access, but could block lower priority records; not in @na.', $variables)),
+        'wrong'        => array(t('wrong'),        'error',   t('Is rightfully in @na but at least one access flag is wrong!', $variables)),
+        'missing'      => array(t('missing'),      'error',   t("Should be in @na but isn't!", $variables)),
+        'removed!'     => array(t('removed!'),     'error',   t('Was removed in @func; should NOT be in @na!', $variables + array('@func' => 'hook_node_access_records_alter()'))),
+        'illegitimate' => array(t('illegitimate'), 'error',   t('Should NOT be in @na because of lower priority!', $variables)),
+        'alien'        => array(t('alien'),        'error',   t('Should NOT be in @na because of unknown origin!', $variables)),
+      );
+      $active_states = array('default', 'ok', 'static', 'unexpected', 'wrong', 'illegitimate', 'alien');
+      $headers = array(t('node'), t('prio'), t('status'), t('realm'), t('gid'), t('view'), t('update'), t('delete'), t('explained'));
+      $headers = self::format_row($headers);
+      $active_records = array();
+      foreach ($query->execute() as $active_record) {
+        $active_records[$active_record->nid][$active_record->realm][$active_record->gid] = $active_record;
+      }
+      $all_records = $grants_data = $checked_grants = $grants = array();
+
+      foreach (array('view', 'update', 'delete') as $op) {
+        $grants[$op] = self::simulate_module_invoke_all('node_grants', $user, $op);
+        // Call all hook_node_grants_alter() implementations.
+        $grants_data[$op] = self::simulate_node_grants_alter($grants[$op], $user, $op);
+      }
+
+      foreach ($nids as $nid) {
+        $top_priority = -99999;
+        $acquired_records_nid = array();
+        if ($node = Node::load($nid)) {
+          // Check node_access_acquire_grants().
+          $records = self::simulate_module_invoke_all('node_access_records', $node);
+          // Check drupal_alter('node_access_records').
+          $data = self::simulate_node_access_records_alter($records, $node);
+          if (!empty($data)) {
+            foreach ($data as $data_by_realm) {
+              foreach ($data_by_realm as $data_by_realm_gid) {
+                if (isset($data_by_realm_gid['current'])) {
+                  $record = $data_by_realm_gid['current'];
+                }
+                elseif (isset($data_by_realm_gid['original'])) {
+                  $record = $data_by_realm_gid['original'];
+                  $record['#removed'] = 1;
+                }
+                else {
+                  continue;
+                }
+                $priority = intval(isset($record['priority']) ? $record['priority'] : 0);
+                $top_priority = (isset($top_priority) ? max($top_priority, $priority) : $priority);
+                $record['priority'] = (isset($record['priority']) ? $priority : '&ndash;&nbsp;');
+                $record['history'] = $data_by_realm_gid;
+                $acquired_records_nid[$priority][$record['realm']][$record['gid']] = $record + array(
+                    '#title'  => self::get_node_title($node),
+                    '#module' => (isset($record['#module']) ? $record['#module'] : ''),
+                  );
+              }
+            }
+            krsort($acquired_records_nid);
+          }
+          //dpm($acquired_records_nid, "acquired_records_nid =");
+
+          // Check node_access_grants().
+          if ($node->id()) {
+            foreach (array('view', 'update', 'delete') as $op) {
+              $checked_grants[$nid][$op] = array_merge(array('all' => array(0)), $grants[$op]);
+            }
+          }
+        }
+
+        // Check for records in the node_access table that aren't returned by
+        // node_access_acquire_grants().
+
+        if (isset($active_records[$nid])) {
+          foreach ($active_records[$nid] as $realm => $active_records_realm) {
+            foreach ($active_records_realm as $gid => $active_record) {
+              $found = FALSE;
+              $count_nonempty_records = 0;
+              foreach ($acquired_records_nid as $priority => $acquired_records_nid_priority) {
+                if (isset($acquired_records_nid_priority[$realm][$gid])) {
+                  $found = TRUE;
+                }
+              }
+              // Take the highest priority only.
+              // TODO This has changed in D8!
+              if ($acquired_records_nid_priority = reset($acquired_records_nid)) {
+                foreach ($acquired_records_nid_priority as $acquired_records_nid_priority_realm) {
+                  foreach ($acquired_records_nid_priority_realm as $acquired_records_nid_priority_realm_gid) {
+                    $count_nonempty_records += (!empty($acquired_records_nid_priority_realm_gid['grant_view']) || !empty($acquired_records_nid_priority_realm_gid['grant_update']) || !empty($acquired_records_nid_priority_realm_gid['grant_delete']));
+                  }
+                }
+              }
+              $fixed_record = (array) $active_record;
+              if ($count_nonempty_records == 0 && $realm == 'all' && $gid == 0) {
+                $fixed_record += array(
+                  'priority' => '&ndash;',
+                  'state'    => 'default',
+                );
+              }
+              elseif (!$found) {
+                $acknowledged = self::simulate_module_invoke_all('node_access_acknowledge', $fixed_record);
+                if (empty($acknowledged)) {
+                  // No module acknowledged this record, mark it as alien.
+                  $fixed_record += array(
+                    'priority' => '?',
+                    'state'    => 'alien',
+                  );
+                }
+                else {
+                  // At least one module acknowledged the record,
+                  // attribute it to the first one.
+                  $fixed_record += array(
+                    'priority' => '&ndash;',
+                    'state'    => 'static',
+                    '#module'  => reset(array_keys($acknowledged)),
+                  );
+                }
+              }
+              else {
+                continue;
+              }
+              $fixed_record += array(
+                'nid'    => $nid,
+                '#title' => self::get_node_title($node),
+              );
+              $all_records[] = $fixed_record;
+            }
+          }
+        }
+
+        // Order records and evaluate their status.
+        foreach ($acquired_records_nid as $priority => $acquired_records_priority) {
+          ksort($acquired_records_priority);
+          foreach ($acquired_records_priority as $realm => $acquired_records_realm) {
+            ksort($acquired_records_realm);
+            foreach ($acquired_records_realm as $gid => $acquired_record) {
+              // TODO: Handle priority.
+              //if ($priority == $top_priority) {
+              if (empty($acquired_record['grant_view']) && empty($acquired_record['grant_update']) && empty($acquired_record['grant_delete'])) {
+                $acquired_record['state'] = 'empty';
+              }
+              else {
+                if (isset($active_records[$nid][$realm][$gid])) {
+                  $acquired_record['state'] = (isset($acquired_record['#removed']) ? 'removed!' : 'ok');
+                }
+                else {
+                  $acquired_record['state'] = (isset($acquired_record['#removed']) ? 'removed' : 'missing');
+                }
+                if ($acquired_record['state'] == 'ok') {
+                  foreach (array('view', 'update', 'delete') as $op) {
+                    $active_record = (array) $active_records[$nid][$realm][$gid];
+                    if (empty($acquired_record["grant_$op"]) != empty($active_record["grant_$op"])) {
+                      $acquired_record["grant_$op!"] = $active_record["grant_$op"];
+                    }
+                  }
+                }
+              }
+              //}
+              //else {
+              //  $acquired_record['state'] = (isset($active_records[$nid][$realm][$gid]) ? 'illegitimate' : 'ignored');
+              //}
+              $all_records[] = $acquired_record + array('nid' => $nid);
+            }
+          }
+        }
+      }
+
+      // Fill in the table rows.
+      $rows = array();
+      $error_count = 0;
+      foreach ($all_records as $record) {
+        $row = new \stdClass();
+        $row->nid = $record['nid'];
+        $row->title = $record['#title'];
+        $row->priority = $record['priority'];
+        $row->state = array('data' => $states[$record['state']][0], 'title' => $states[$record['state']][2]);
+        $row->realm = $record['realm'];
+        $row->gid = $record['gid'];
+        $row->grant_view = $record['grant_view'];
+        $row->grant_update = $record['grant_update'];
+        $row->grant_delete = $record['grant_delete'];
+        $row->explained = implode('<br />', \Drupal::moduleHandler()->invokeAll('node_access_explain', $row));
+        unset($row->title);
+        if ($row->nid == 0 && $row->gid == 0 && $row->realm == 'all' && count($all_records) > 1) {
+          $row->state = array('data' => $states['unexpected'][0], 'title' => $states['unexpected'][2]);
+          $class = $states['unexpected'][1];
+        }
+        else {
+          $class = $states[$record['state']][1];
+        }
+        $row = (array) $row;
+        foreach (array('view', 'update', 'delete') as $op) {
+          $row["grant_$op"] = array('data' => $row["grant_$op"]);
+          if ((isset($checked_grants[$record['nid']][$op][$record['realm']]) && in_array($record['gid'], $checked_grants[$record['nid']][$op][$record['realm']]) || ($row['nid'] == 0 && $row['gid'] == 0 && $row['realm'] == 'all')) && !empty($row["grant_$op"]['data']) && in_array($record['state'], $active_states)) {
+            $row["grant_$op"]['data'] .= '&prime;';
+            $row["grant_$op"]['title'] = t('This entry grants access to this node to this user.');
+          }
+          if (isset($record["grant_$op!"])) {
+            $row["grant_$op"]['data'] = $record["grant_$op!"] . '&gt;' . (!$row["grant_$op"]['data'] ? 0 : $row["grant_$op"]['data']);
+            $row["grant_$op"]['class'][] = 'error';
+            if ($class == 'ok') {
+              $row['state'] = array('data' => $states['wrong'][0], 'title' => $states['wrong'][2]);
+              $class = $states['wrong'][1];
+            }
+          }
+        }
+        $error_count += ($class == 'error');
+        $row['nid'] = array(
+          'data'  => '<a href="#node-' . $record['nid'] . '">' . $row['nid'] . '</a>',
+          'title' => $record['#title'],
+        );
+        if (empty($record['#module']) || strpos($record['realm'], $record['#module']) === 0) {
+          $row['realm'] = $record['realm'];
+        }
+        else {
+          $row['realm'] = array(
+            'data' => '(' . $record['#module'] . '::) ' . $record['realm'],
+            'title' => t("The '@module' module fails to adhere to the best practice of naming its realm(s) after itself.", array('@module' => $record['#module'])),
+          );
+        }
+
+        // Prepend information from the D7 hook_node_access_records_alter().
+        $next_style = array();
+        if (isset($record['history'])) {
+          $history = $record['history'];
+          if (($num_changes = count($history['changes']) - empty($history['current'])) > 0) {
+            $first_row = TRUE;
+            while (isset($history['original']) || $num_changes--) {
+              if (isset($history['original'])) {
+                $this_record = $history['original'];
+                $this_action = '[ Original by ' . $this_record['#module'] . ':';
+                unset($history['original']);
+              }
+              else {
+                $change = $history['changes'][0];
+                $this_record = $change['record'];
+                $this_action = ($first_row ? '[ ' : '') . $change['op'] . ':';
+                array_shift($history['changes']);
+              }
+              $rows[] = array(
+                'data'  => array(
+                  'data'  => array(
+                    'data'    => $this_action,
+                    'style'   => array('padding-bottom: 0;'),
+                  ),
+                ),
+                'style' => array_merge(($first_row ? array() : array('border-top-style: dashed;', 'border-top-width: 1px;')), array('border-bottom-style: none;')),
+              );
+              $next_style = array('border-top-style: none;');
+              if (count($history['changes'])) {
+                $g = $this_record;
+                $rows[] = array(
+                  'data'  => array('v', $g['priority'], '', $g['realm'], $g['gid'], $g['grant_view'], $g['grant_update'], $g['grant_delete'], 'v'),
+                  'style' => array('border-top-style: none;', 'border-bottom-style: dashed;'),
+                );
+                $next_style = array('border-top-style: dashed;');
+              }
+              $first_row = FALSE;
+            }
+          }
+        }
+
+        // Fix up the main row cells with the proper class (needed for Bartik).
+        foreach ($row as $key => $value) {
+          if (!is_array($value)) {
+            $row[$key] = array('data' => $value);
+          }
+          $row[$key]['class'] = array($class);
+        }
+        // Add the main row.
+        $will_append = empty($history['current']) && !empty($history['changes']);
+        $rows[] = array(
+          'data'  => array_values($row),
+          'class' => array($class),
+          'style' => array_merge($next_style, ($will_append ? array('border-bottom-style: none;') : array())),
+        );
+
+        // Append information from the D7 hook_node_access_records_alter().
+        if ($will_append) {
+          $last_change = end($history['changes']);
+          $rows[] = array(
+            'data'  => array(
+              'data'  => array(
+                'data'    => $last_change['op'] . ' ]',
+                'style' => array('padding-top: 0;'),
+              ),
+            ),
+            'style' => array('border-top-style: none;'),
+          );
+        }
+      }
+
+      foreach ($rows as $i => $row) {
+        $rows[$i] = self::format_row($row);
+      }
+
+      $output[] = array(
+        '#theme'      => 'table',
+        '#header'     => $headers,
+        '#rows'       => $rows,
+        '#attributes' => array(
+          'class'       => array('system-status-report'),
+          'style'       => 'text-align: left;',
+        ),
+      );
+
+      $output[] = array(
+        '#theme'       => 'form_element',
+        '#description' => t('(Some of the table elements provide additional information if you hover your mouse over them.)'),
+      );
+
+      if ($error_count > 0) {
+        $variables['@Rebuild_permissions'] = '<a href="' . url('admin/reports/status/rebuild') . '">' . $tr('Rebuild permissions') . '</a>';
+        $output[] = array(
+          '#prefix' => "\n<span class=\"error\">",
+          '#markup' => t("You have errors in your @na table! You may be able to fix these for now by running @Rebuild_permissions, but this is likely to destroy the evidence and make it impossible to identify the underlying issues. If you don't fix those, the errors will probably come back again. <br /> DON'T do this just yet if you intend to ask for help with this situation.", $variables),
+          '#suffix' => "</span><br />\n",
+        );
+      }
+
+      // Explain whether access is granted or denied, and why
+      // (using code from node_access()).
+      $tr = 't';
+      array_shift($nids);  // Remove the 0.
+      $accounts = array();
+      $variables += array(
+        //'!username' => '<em class="placeholder">' . theme('username', array('account' => $user)) . '</em>',
+        '@username' => '<em class="placeholder">' . $user->getDisplayName() . '</em>',
+        '%uid'      => $user->id(),
+      );
+
+      if (\Drupal::currentUser()->hasPermission('bypass node access')) {
+        $variables['%bypass_node_access'] = $tr('bypass node access');
+        $output[] = array(
+          '#markup' => t('@username has the %bypass_node_access permission and thus full access to all nodes.', $variables),
+          '#suffix' => '<br />&nbsp;',
+        );
+      }
+      else {
+        $variables['@list'] = '<div style="margin-left: 2em">' . self::get_grant_list($grants_data['view']) . '</div>';
+        $variables['%access'] = 'view';
+        $output[] = array(
+          '#prefix' => "\n<div style='text-align: left' title='" . t('These are the grants returned by hook_node_grants() for this user.') . "'>",
+          '#markup' => t('@username (user %uid) can use these grants (if they are present above) for %access access: @list', $variables),
+          '#suffix' => "</div>\n",
+        );
+        $accounts[] = $user;
+      }
+
+      if (isset($single_nid) && !$user_block_active) {
+        // Only for single nodes.
+        if (\Drupal::currentUser()->isAuthenticated()) {
+          $accounts[] = User::load(0);  // Anonymous, too.
+        }
+        foreach ($accounts as $account) {
+          $nid_items = array();
+          foreach ($nids as $nid) {
+            $op_items = array();
+            foreach (array('create', 'view', 'update', 'delete') as $op) {
+              $explain = self::explainAccess($op, Node::load($nid), $account);
+              $op_items[] = "<div style='width: 5em; display: inline-block'>" . t('%op:', array('%op' => $op)) . ' </div>' . $explain[2];
+            }
+            $nid_items[] = array(
+              '#theme'  => 'item_list',
+              '#items'  => $op_items,
+              '#type'   => 'ul',
+              '#prefix' => t('to node @nid:', array('@nid' => l($nid, 'node/' . $nid))) . "\n<div style='margin-left: 2em'>",
+              '#suffix' => '</div>',
+            );
+          }
+          if (count($nid_items) == 1) {
+            $account_items = $nid_items[0];
+          }
+          else {
+            $account_items = array(
+              '#theme'  => 'item_list',
+              '#items'  => $nid_items,
+              '#type'   => 'ul',
+              '#prefix' => "\n<div style='margin-left: 2em'>",
+              '#suffix' => '</div>',
+            );
+          }
+          $variables['@username'] = '<em class="placeholder">' . theme('username', array('account' => $account)) . '</em>';
+          $output[] = array(
+            '#prefix' => "\n<div style='text-align: left'>",
+            '#type'   => 'item',
+            'lead-in' => array('#markup' => t("@username has the following access", $variables) . ' '),
+            'items'   => $account_items,
+            '#suffix' => "\n</div>\n",
+          );
+        }
+      }
+    }
+
+    return $output;
+  }
+
+  /**
+   * Builds and returns the by-user information.
+   *
+   * @return array|null
+   */
+  public static function buildByUserInfo() {
+    global $user;
+
+    $output = array();
+    return $output;
+
+    // Show which users can access this node.
+    $menu_item = menu_get_item();
+    $map = $menu_item['original_map'];
+    if ($map[0] != 'node' || !isset($map[1]) || !is_numeric($map[1]) || isset($map[2])) {
+      // Ignore anything but node/%.
+      return NULL;
+    }
+
+    if (isset($menu_item['map'][1]) && is_object($node = $menu_item['map'][1])) {
+      // We have the node.
+    }
+    elseif (is_numeric($menu_item['original_map'][1])) {
+      $node = node_load($menu_item['original_map'][1]);
+    }
+    if (isset($node)) {
+      $nid = $node->id();
+      $langcode = $node->langcode->value;
+      $language = language_load($langcode);
+      $node_type = node_type_load($node->bundle());
+      $headers = array(t('username'), '<span title="' . t("Create '@langname'-language nodes of the '@Node_type' type.", array('@langname' => $language->name, '@Node_type' => $node_type->name)) . '">' . t('create') . '</span>', t('view'), t('update'), t('delete'));
+      $rows = array();
+      // Determine whether to use Ajax or pre-populate the tables.
+      if ($ajax = \Drupal::config('devel_node_access.settings')->get('user_ajax')) {
+        $output['#attached']['library'][] = 'devel_node_access/node_access';
+      }
+      // Find all users. The following operations are very inefficient, so we
+      // limit the number of users returned.  It would be better to make a
+      // pager query, or at least make the number of users configurable.  If
+      // anyone is up for that please submit a patch.
+      $query = db_select('users', 'u')
+        ->fields('u', array('uid'))
+        ->orderBy('u.access', 'DESC')
+        ->range(0, 9);
+      $uids = $query->execute()->fetchCol();
+      array_unshift($uids, 0);
+      $accounts = user_load_multiple($uids);
+      foreach ($accounts as $account) {
+        $username = theme('username', array('account' => $account));
+        $uid = $account->id();
+        if ($uid == $user->id()) {
+          $username = '<strong>' . $username . '</strong>';
+        }
+        $rows[] = array(
+          $username,
+          array(
+            'id' => 'create-' . $nid . '-' . $uid,
+            'class' => 'dna-permission',
+            'data' => $ajax ? NULL : theme('dna_permission', array('permission' => self::explainAccess('create', $node, $account, $langcode))),
+          ),
+          array(
+            'id' => 'view-' . $nid . '-' . $uid,
+            'class' => 'dna-permission',
+            'data' => $ajax ? NULL : theme('dna_permission', array('permission' => self::explainAccess('view', $node, $account, $langcode))),
+          ),
+          array(
+            'id' => 'update-' . $nid . '-' . $uid,
+            'class' => 'dna-permission',
+            'data' => $ajax ? NULL : theme('dna_permission', array('permission' => self::explainAccess('update', $node, $account, $langcode))),
+          ),
+          array(
+            'id' => 'delete-' . $nid . '-' . $uid,
+            'class' => 'dna-permission',
+            'data' => $ajax ? NULL : theme('dna_permission', array('permission' => self::explainAccess('delete', $node, $account, $langcode))),
+          ),
+        );
+      }
+      if (count($rows)) {
+        $output['title'] = array(
+          '#prefix' => '<h2>',
+          '#markup' => t('Access permissions by user for the %langname language', array('%langname' => $language->name)),
+          '#postfix' => '</h2>',
+        );
+        $output[] = array(
+          '#theme'      => 'table',
+          '#header'     => $headers,
+          '#rows'       => $rows,
+          '#attributes' => array('style' => 'text-align: left'),
+        );
+        $output[] = array(
+          '#theme'        => 'form_element',
+          '#description'  => t('(This table lists the most-recently active users. Hover your mouse over each result for more details.)'),
+        );
+      }
+    }
+    return $output;
+  }
+
+  /**
+   * Helper function to mimic \Drupal::moduleHandler()->invokeAll() and include
+   * the name of the responding module(s).
+   *
+   * @param $hook
+   *   The name of the hook.
+   *
+   * @return array
+   *   An array of results.
+   *   In the case of scalar results, the array is keyed by the name of the
+   *   modules that returned the result (rather than by numeric index), and
+   *   in the case of array results, a '#module' key is added.
+   */
+  private static function simulate_module_invoke_all($hook) {
+    $args = func_get_args();
+    // Remove $hook from the arguments.
+    array_shift($args);
+    $return = array();
+    foreach (\Drupal::moduleHandler()->getImplementations($hook) as $module) {
+      $function = $module . '_' . $hook;
+      $result = call_user_func_array($function, $args);
+      if (isset($result)) {
+        if (is_array($result)) {
+          foreach ($result as $key => $value) {
+            // Add name of module that returned the value.
+            $result[$key]['#module'] = $module;
+          }
+        }
+        else {
+          // Build array with result keyed by $module.
+          $result = array($module => $result);
+        }
+        $return = \Drupal\Component\Utility\NestedArray::mergeDeep($return, $result);
+      }
+    }
+    return $return;
+  }
+
+  /**
+   * Helper function to mimic hook_node_access_records_alter() and trace what
+   * each module does with it.
+   *
+   * @param array $records
+   *   An indexed array of NA records, augmented by the '#module' key,
+   *   as created by simulate_module_invoke_all('node_access_records').
+   *   This array is updated by the hook_node_access_records_alter()
+   *   implementations.
+   * @param $node
+   *   The node that the NA records belong to.
+   *
+   * @return array
+   *   A tree representation of the NA records in $records including their
+   *   history:
+   *   $data[$realm][$gid]
+   *     ['original']  - NA record before processing
+   *     ['current']   - NA record after processing (if still present)
+   *     ['changes'][]['op']     - change message (add/change/delete by $module)
+   *                  ['record'] - NA record after change (unless deleted)
+   */
+  private static function simulate_node_access_records_alter(&$records, $node) {
+    //dpm($records, 'simulate_node_access_records_alter(): records IN');
+    $hook = 'node_access_records_alter';
+
+    // Build the initial tree (and check for duplicates).
+    $data = self::build_node_access_records_data($records, $node, 'hook_node_access_records()');
+
+    // Simulate drupal_alter('node_access_records', $records, $node).
+    foreach (\Drupal::moduleHandler()->getImplementations($hook) as $module) {
+      // Call hook_node_access_records_alter() for one module at a time
+      // and analyze.
+      $function = $module . '_' . $hook;
+      $function($records, $node);
+
+      foreach ($records as $i => $record) {
+        if (empty($data[$record['realm']][$record['gid']]['current'])) {
+          // It's an added record.
+          $data[$record['realm']][$record['gid']]['current'] = $record;
+          $data[$record['realm']][$record['gid']]['current']['#module'] = $module;
+          $data[$record['realm']][$record['gid']]['changes'][] = array(
+            'op'     => 'added by ' . $module,
+            'record' => $record,
+          );
+          $records[$i]['#module'] = $module;
+        }
+        else {
+          // It's an existing record, check for changes.
+          $view = $update = $delete = FALSE;
+          foreach (array('view', 'update', 'delete') as $op) {
+            $$op = $record["grant_$op"] - $data[$record['realm']][$record['gid']]['current']["grant_$op"];
+          }
+          $old_priority = isset($record['priority']) ? $record['priority'] : 0;
+          $new_priority = isset($data[$record['realm']][$record['gid']]['current']['priority']) ? $data[$record['realm']][$record['gid']]['current']['priority'] : 0;
+          if ($view || $update || $delete || $old_priority != $new_priority) {
+            // It was changed.
+            $data[$record['realm']][$record['gid']]['current'] = $record;
+            $data[$record['realm']][$record['gid']]['current']['#module'] = $module;
+            $data[$record['realm']][$record['gid']]['changes'][] = array(
+              'op'     => 'altered by ' . $module,
+              'record' => $record,
+            );
+            $records[$i]['#module'] = $module;
+          }
+        }
+        $data[$record['realm']][$record['gid']]['found'] = TRUE;
+      }
+
+      // Check for newly introduced duplicates.
+      self::build_node_access_records_data($records, $node, 'hook_node_access_records_alter()');
+
+      // Look for records that have disappeared.
+      foreach ($data as $realm => $data2) {
+        foreach ($data2 as $gid => $data3) {
+          if (empty($data[$realm][$gid]['found']) && isset($data[$realm][$gid]['current'])) {
+            unset($data[$realm][$gid]['current']);
+            $data[$realm][$gid]['changes'][] = array('op' => 'removed by ' . $module);
+          }
+          else {
+            unset($data[$realm][$gid]['found']);
+          }
+        }
+      }
+    }
+    //dpm($data, 'simulate_node_access_records_alter() returns');
+    //dpm($records, 'simulate_node_access_records_alter(): records OUT');
+    return $data;
+  }
+
+  /**
+   * Helper function to build an associative array of node access records and
+   * their history. If there are duplicate records, display an error message.
+   *
+   * @param $records
+   *   An indexed array of node access records, augmented by the '#module' key,
+   *   as created by simulate_module_invoke_all('node_access_records').
+   * @param $node
+   *   The node that the NA records belong to.
+   * @param $function
+   *   The name of the hook that produced the records array, in case we need to
+   *   display an error message.
+   *
+   * @return array
+   *   See _devel_node_access_nar_alter() for the description of the result.
+   */
+  private static function build_node_access_records_data($records, $node, $function) {
+    $data = array();
+    $duplicates = array();
+    foreach ($records as $record) {
+      if (empty($data[$record['realm']][$record['gid']])) {
+        $data[$record['realm']][$record['gid']] = array('original' => $record, 'current' => $record, 'changes' => array());
+      }
+      else {
+        if (empty($duplicates[$record['realm']][$record['gid']])) {
+          $duplicates[$record['realm']][$record['gid']][] = $data[$record['realm']][$record['gid']]['original'];
+        }
+        $duplicates[$record['realm']][$record['gid']][] = $record;
+      }
+    }
+    if (!empty($duplicates)) {
+      // Generate an error message.
+      $msg = t('Devel Node Access has detected duplicate records returned from %function:', array('%function' => $function));
+      $msg .= '<ul>';
+      foreach ($duplicates as $realm => $data_by_realm) {
+        foreach ($data_by_realm as $gid => $data_by_realm_gid) {
+          $msg .= '<li><ul>';
+          foreach ($data_by_realm_gid as $record) {
+            $msg .= "<li>$node->id()/$realm/$gid/" . ($record['grant_view'] ? 1 : 0) . ($record['grant_update'] ? 1 : 0) . ($record['grant_delete'] ? 1 : 0) . ' by ' . $record['#module'] . '</li>';
+          }
+          $msg .= '</ul></li>';
+        }
+      }
+      $msg .= '</ul>';
+      drupal_set_message($msg, 'error', FALSE);
+    }
+    return $data;
+  }
+
+  /**
+   * Helper function to mimic hook_node_grants_alter() and trace what
+   * each module does with it.
+   *
+   * @param array $grants
+   *   An indexed array of grant records, augmented by the '#module' key,
+   *   as created by simulate_module_invoke_all('node_grants').
+   *   This array is updated by the hook_node_grants_alter()
+   *   implementations.
+   * @param $account
+   *   The user account requesting access to content.
+   * @param $op
+   *   The operation being performed, 'view', 'update' or 'delete'.
+   *
+   * @return array
+   *   A tree representation of the grant records in $grants including their
+   *   history:
+   *   $data[$realm][$gid]
+   *     ['cur']    - TRUE or FALSE whether the gid is present or not
+   *     ['ori'][]  - array of module names that contributed this grant (if any)
+   *     ['chg'][]  - array of changes, such as
+   *                     - 'added' if module name is a prefix if the $realm,
+   *                     - 'added by module' otherwise, or
+   *                     - 'removed by module'
+   */
+  private static function simulate_node_grants_alter(&$grants, $account, $op) {
+    //dpm($grants, "simulate_node_grants_alter($account->name, $op): grants IN");
+    $hook = 'node_grants_alter';
+
+    // Build the initial structure.
+    $data = array();
+    foreach ($grants as $realm => $gids) {
+      foreach ($gids as $i => $gid) {
+        if ($i !== '#module') {
+          $data[$realm][$gid]['cur'] = TRUE;
+          $data[$realm][$gid]['ori'][] = $gids['#module'];
+        }
+      }
+      unset($grants[$realm]['#module']);
+    }
+
+    // Simulate drupal_alter('node_grants', $grants, $account, $op).
+    foreach (\Drupal::moduleHandler()->getImplementations($hook) as $module) {
+      // Call hook_node_grants_alter() for one module at a time and analyze.
+      $function = $module . '_' . $hook;
+      $function($grants, $account, $op);
+
+      // Check for new gids.
+      foreach ($grants as $realm => $gids) {
+        foreach ($gids as $i => $gid) {
+          if (empty($data[$realm][$gid]['cur'])) {
+            $data[$realm][$gid]['cur'] = TRUE;
+            $data[$realm][$gid]['chg'][] = 'added by ' . $module;
+          }
+        }
+      }
+
+      // Check for removed gids.
+      foreach ($data as $realm => $gids) {
+        foreach  ($gids as $gid => $history) {
+          if ($history['cur'] && array_search($gid, $grants[$realm]) === FALSE) {
+            $data[$realm][$gid]['cur'] = FALSE;
+            $data[$realm][$gid]['chg'][] = 'removed by ' . $module;
+          }
+        }
+      }
+    }
+
+    //dpm($data, "simulate_node_grants_alter($account->name, $op) returns");
+    //dpm($grants, "simulate_node_grants_alter($account->name, $op): grants OUT");
+    return $data;
+  }
+
+  /**
+   * Helper function to create a list of grants returned by hook_node_grants().
+   */
+  private static function get_grant_list($grants_data) {
+    //dpm($grants_data, "get_grant_list() IN:");
+    $grants_data = array_merge(array('all' => array(0 => array('cur' => TRUE, 'ori' => array('all')))), $grants_data);
+    $items = array();
+    if (count($grants_data)) {
+      foreach ($grants_data as $realm => $gids) {
+        ksort($gids);
+        $gs = array();
+        foreach ($gids as $gid => $history) {
+          if ($history['cur']) {
+            if (isset($history['ori'])) {
+              $g = $gid;                     // Original grant, still active.
+            }
+            else {
+              $g = '<u>' . $gid . '</u>';    // New grant, still active.
+            }
+          }
+          else {
+            $g = '<del>' . $gid . '</del>';  // Deleted grant.
+          }
+
+          $ghs = array();
+          if (isset($history['ori']) && strpos($realm, $history['ori'][0]) !== 0) {
+            $realm = '(' . $history['ori'][0] . '::) ' . $realm;
+          }
+          if (isset($history['chg'])) {
+            foreach ($history['chg'] as $h) {
+              $ghs[] = $h;
+            }
+          }
+          if (!empty($ghs)) {
+            $g .= ' (' . implode(', ', $ghs) . ')';
+          }
+          $gs[] = $g;
+        }
+        $items[] = $realm . ': ' . implode(', ', $gs);
+      }
+      if (!empty($items)) {
+        return theme('item_list', array('items' => $items, 'type' => 'ul'));
+      }
+    }
+    return '';
+  }
+
+  /**
+   * Helper function to return a sanitized node title.
+   */
+  private static function get_node_title(Node $node) {
+    if (isset($node)) {
+      $nid = $node->id();
+      if ($node_title = $node->getTitle()) {
+        return $node_title;
+      }
+      elseif ($nid) {
+        return $nid;
+      }
+    }
+    return '—';
+  }
+
+  /**
+   * Helper function to apply common formatting to a debug-mode table row.
+   */
+  private static function format_row($row, $may_unpack = TRUE) {
+    if ($may_unpack && isset($row['data'])) {
+      $row['data'] = self::format_row($row['data'], FALSE);
+      $row['class'][] = 'even';
+      return $row;
+    }
+    if (count($row) == 1) {
+      if (is_scalar($row['data'])) {
+        $row['data'] = array('data' => $row['data']);
+      }
+      $row['data']['colspan'] = 9;
+    }
+    else {
+      $row = array_values($row);
+      foreach (array(0, 1, 4) as $j) {  // node, prio, gid
+        if (is_scalar($row[$j])) {
+          $row[$j] = array('data' => $row[$j]);
+        }
+        dpm($j);
+        dpm($row);
+//        $row[$j]['style'][] = 'text-align: right;';
+      }
+    }
+    return $row;
+  }
+
+
+  /**
+   * Helper function that mimics node.module's node_access() function.
+   *
+   * Unfortunately, this needs to be updated manually whenever node.module
+   * changes!
+   *
+   * @param string $op
+   *   Operation to check.
+   * @param NodeInterface $node
+   *   Node to check.
+   * @param AccountInterface $account
+   *   (optional) The user object for the user whose access is being checked. If
+   *   omitted, the current user is used. Defaults to NULL.
+   * @param string $langcode
+   *   (optional) The language code for which access is being checked. If
+   *   omitted, the default language is used. Defaults to NULL.
+   *
+   * @return array
+   *   An array suitable for theming with theme_dna_permission().
+   */
+  public static function explainAccess($op, NodeInterface $node, AccountInterface $account = NULL, $langcode = NULL) {
+    $user = Drupal::currentUser();
+
+    if (!$node) {
+      return array(
+        FALSE,
+        '???',
+        t('No node passed to node_access(); this should never happen!'),
+      );
+    }
+    if (!in_array($op, array('view', 'update', 'delete', 'create'), TRUE)) {
+      return array(
+        FALSE,
+        t('@NO: invalid $op', array('@NO' => t('NO'))),
+        t("'@op' is an invalid operation!", array('@op' => $op)),
+      );
+    }
+
+    if ($op == 'create' && is_object($node)) {
+      $node = $node->bundle();
+    }
+
+    if (!empty($account)) {
+      // To try to get the most authentic result we impersonate the given user!
+      // This may reveal bugs in other modules, leading to contradictory
+      // results.
+      /* @var \Drupal\Core\Session\AccountSwitcherInterface $account_switcher */
+      $account_switcher = Drupal::service('account_switcher');
+      $account_switcher->switchTo($account);
+      $result = DnaBlock::explainAccess($op, $node, NULL, $langcode);
+      $account_switcher->switchBack();
+      $access_handler = Drupal::entityTypeManager()->getAccessControlHandler('node');
+      $second_opinion = $access_handler->access($node, $op, $account);
+      if ($second_opinion != $result[0]) {
+        $result[1] .= '<span class="' . ($second_opinion ? 'ok' : 'error') . '" title="Core seems to disagree on this item. This is a bug in either DNA or Core and should be fixed! Try to look at this node as this user and check whether there is still disagreement.">*</span>';
+      }
+      return $result;
+    }
+
+    if (empty($langcode)) {
+      $langcode = (is_object($node) && $node->id()) ? $node->language()->getId() : '';
+    }
+
+    $variables = array(
+      '@NO'                 => t('NO'),
+      '@YES'                => t('YES'),
+      '@bypass_node_access' => t('bypass node access'),
+      '@access_content'     => t('access content'),
+    );
+
+    if (Drupal::currentUser()->hasPermission('bypass node access')) {
+      return array(
+        TRUE,
+        t('@YES: bypass node access', $variables),
+        t("@YES: This user has the '@bypass_node_access' permission and may do everything with nodes.", $variables),
+      );
+    }
+
+    if (!Drupal::currentUser()->hasPermission('access content')) {
+      return array(
+        FALSE,
+        t('@NO: access content', $variables),
+        t("@NO: This user does not have the '@access_content' permission and is denied doing anything with content.", $variables),
+      );
+    }
+
+    foreach (Drupal::moduleHandler()->getImplementations('node_access') as $module) {
+      $function = $module . '_node_access';
+      if (function_exists($function)) {
+        $result = $function($node, $op, $user, $langcode);
+        if ($module == 'node') {
+          $module = 'node (permissions)';
+        }
+        if (isset($result)) {
+          /* TODO
+          if ($result === NODE_ACCESS_DENY) {
+            $denied_by[] = $module;
+          }
+          elseif ($result === NODE_ACCESS_ALLOW) {
+            $allowed_by[] = $module;
+          }
+          */
+          $access[] = $result;
+        }
+      }
+    }
+    $variables += array(
+      '@deniers'  => (empty($denied_by) ? NULL : implode(', ', $denied_by)),
+      '@allowers' => (empty($allowed_by) ? NULL : implode(', ', $allowed_by)),
+    );
+    if (!empty($denied_by)) {
+      $variables += array(
+        '%module' => $denied_by[0] . (count($denied_by) > 1 ? '+' : ''),
+      );
+      return [
+        FALSE,
+        t('@NO: by %module', $variables),
+        empty($allowed_by)
+          ? t("@NO: hook_node_access() of the following module(s) denies this: @deniers.", $variables)
+          : t("@NO: hook_node_access() of the following module(s) denies this: @deniers &ndash; even though the following module(s) would allow it: @allowers.", $variables),
+      ];
+    }
+    if (!empty($allowed_by)) {
+      $variables += array(
+        '%module' => $allowed_by[0] . (count($allowed_by) > 1 ? '+' : ''),
+        '@view_own_unpublished_content' => t('view own unpublished content'),
+      );
+      return array(
+        TRUE,
+        t('@YES: by %module', $variables),
+        t("@YES: hook_node_access() of the following module(s) allows this: @allowers.", $variables),
+      );
+    }
+
+    // TODO if ($op == 'view' && !$node->get('status', $langcode) && \Drupal::currentUser()->hasPermission('view own unpublished content') && $user->uid == $node->get('uid', $langcode) && $user->uid != 0) {
+    if ($op == 'view' && !$node->isPublished() && Drupal::currentUser()->hasPermission('view own unpublished content') && $user->id() == $node->getRevisionAuthor()->id() && $user->id() != 0) {
+      return array(
+        TRUE,
+        t('@YES: view own unpublished content', $variables),
+        t("@YES: The node is unpublished, but the user has the '@view_own_unpublished_content' permission.", $variables),
+      );
+    }
+
+    if ($op != 'create' && $node->id()) {
+      $access_handler = Drupal::entityTypeManager()->getAccessControlHandler('node');
+      // TODO if (node_access($op, $node, $user, $langcode)) {  // delegate this part
+      if ($access_handler->access($node, $op, $user)) {
+        // Delegate this part.
+        $variables['@node_access_table'] = '{node_access}';
+        return array(
+          TRUE,
+          t('@YES: @node_access_table', $variables),
+          t('@YES: Node access allows this based on one or more records in the @node_access_table table (see the other DNA block!).', $variables),
+        );
+      }
+    }
+
+    return array(
+      FALSE,
+      t('@NO: no reason', $variables),
+      t("@NO: None of the checks resulted in allowing this, so it's denied.", $variables)
+      . ($op == 'create' ? ' ' . t('This is most likely due to a withheld permission.') : ''),
+    );
+  }
+
+  /**
+   * Collects the IDs of the visible nodes on the current page.
+   *
+   * @param int|null $nid
+   *   A node ID to save.
+   *
+   * @return array
+   *   The array of saved node IDs.
+   */
+  public static function visibleNodes($nid = NULL) {
+    static $nids = array();
+    if (isset($nid)) {
+      $nids[$nid] = $nid;
+    }
+    elseif (empty($nids)) {
+      ///** @var NodeInterface $node */
+      //$node = NULL;
+      if ($node = \Drupal::routeMatch()->getParameter('node')) {
+        $nid = $node->id();
+        $nids[$nid] = $nid;
+      }
+    }
+    return $nids;
+  }
+
+
+}

+ 274 - 0
sites/all/modules/contrib/dev/devel/drush/devel.drush.inc

@@ -0,0 +1,274 @@
+<?php
+
+/**
+ * @file
+ * Drush integration for the devel module.
+ */
+
+use Drupal\Component\Uuid\Php;
+
+/**
+ * Implements hook_drush_command().
+ */
+function devel_drush_command() {
+  $items['devel-reinstall'] = array(
+    'description' => dt('Uninstall, and Install a list of projects.'),
+    'drush dependencies' => array('pm'),
+    'arguments' => array(
+      'projects' => dt('A space-separated list of project names.'),
+    ),
+    'allow-additional-options' => array('pm-uninstall', 'pm-enable'),
+    'required-arguments' => 1,
+    'aliases' => array('dre'),
+  );
+  $items['fn-hook'] = array(
+    'description' => 'List implementations of a given hook and explore the source of the selected one.',
+    'arguments' => array(
+      'hook' => 'The name of the hook to explore (e.g. "menu" for hook_menu()).'
+    ),
+    'examples' => array(
+      'fn-hook cron' => 'List implementations of hook_cron().',
+    ),
+    'allow-additional-options' => array('fn-view'),
+    'required-arguments' => 1,
+    'aliases' => array('fnh', 'hook'),
+  );
+  $items['fn-event'] = array(
+    'description' => 'List implementations of a given event and explore source of specified one.',
+    'arguments' => array(
+      'event' => 'The name of the event to explore. If omitted, a list of events is shown.'
+    ),
+    'examples' => array(
+      'fn-event' => 'Pick a Kernel event, then pick an implementation, and then view its source code.',
+      'fn-event kernel.terminate' => 'Pick a terminate subscribers and view its source code.',
+    ),
+    'allow-additional-options' => array('fn-view'),
+    'aliases' => array('fne', 'event'),
+  );
+  $items['fn-view'] = array(
+    'description' => 'Show the source of specified function or method.',
+    'arguments' => array(
+      'function' => 'The name of the function or method to view.',
+    ),
+    'options' => array(
+      'pipe' => 'Output just the filename of the function or method',
+      'format' => 'Specify how the filename should be printed. Available placeholders are @startline, @endline and @file',
+    ),
+    'examples' => array(
+      'fn-view drupal_set_breadcrumb' => 'View the source code for function "drupal_set_breadcrumb"',
+      'vi `drush --pipe fn-view user_access --format=\'+@startline @file\'`' => 'Edit the file that contains the function "user_access"',
+      'fn-view NodeController::load' => 'View the source code for method load in the class NodeController'
+    ),
+    'aliases' => array('fnv'),
+    'required-arguments' => 1,
+  );
+  $items['devel-token'] = array(
+    'description' => dt('List available tokens'),
+    'aliases' => array('token'),
+    //@todo support --format option for json, csv, etc.
+  );
+
+  $items['devel-container-services'] = array(
+    'description' => 'Get a list of available container services.',
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
+    'core' => array('8+'),
+    'aliases' => array('dcs'),
+    'options' => array(
+      'format' => 'Format to output. Allowed values are: json, export, html.',
+    ),
+    'arguments' => array(
+      'prefix' => 'A prefix to filter the service list by.',
+    ),
+    'examples' => array(
+      'drush container-services' => 'Gets a list of all available container services',
+      'drush container-services plugin.manager' => 'Get all services containing "plugin.manager"',
+    ),
+    'outputformat' => array(
+      'default' => 'list',
+      'pipe-format' => 'export',
+    ),
+  );
+
+  $items['devel-generate-uuid'] = array(
+    'description' => 'Generate a UUID.',
+    'core' => array('8+'),
+    'examples' => array(
+      "drush devel-generate-uuid" => "Outputs a Universally Unique IDentifier.",
+    ),
+    'aliases' => array('uuid'),
+    'outputformat' => array(
+      'default' => 'string',
+    ),
+  );
+
+  return $items;
+}
+
+/**
+ * A command callback. This is faster than 3 separate bootstraps.
+ */
+function drush_devel_reinstall() {
+  $projects = func_get_args();
+
+  $args = array_merge(array('pm-uninstall'), $projects);
+  call_user_func_array('drush_invoke', $args);
+
+  $args = array_merge(array('pm-enable'), $projects);
+  call_user_func_array('drush_invoke', $args);
+}
+
+/**
+ * Command handler. Show hook implementations.
+ */
+function drush_devel_fn_hook($hook) {
+  // Get implementations in the .install files as well.
+  include_once './core/includes/install.inc';
+  drupal_load_updates();
+
+  if ($hook_implementations = \Drupal::moduleHandler()->getImplementations($hook)) {
+    if ($choice = drush_choice(array_combine($hook_implementations, $hook_implementations), 'Enter the number of the hook implementation you wish to view.')) {
+      return drush_devel_fn_view($choice . "_$hook");
+    }
+  }
+  else {
+    drush_log(dt('No implementations.'), 'ok');
+  }
+}
+
+/**
+ * Command handler. Show hook implementations.
+ */
+function drush_devel_fn_event($event = NULL) {
+  $dispatcher = Drupal::service('event_dispatcher');
+  if (empty($event)) {
+    $events = array('kernel.controller', 'kernel.exception', 'kernel.request', 'kernel.response', 'kernel.terminate', 'kernel.view');
+    $events = array_combine($events, $events);
+    if (!$event = drush_choice($events, 'Enter the event you wish to explore.')) {
+      return drush_user_abort();
+    }
+  }
+  if ($implementations = $dispatcher->getListeners($event)) {
+    foreach ($implementations as $implementation) {
+      $callable = get_class($implementation[0]) . '::' . $implementation[1];
+      $choices[$callable] = $callable;
+    }
+    if ($choice = drush_choice($choices, 'Enter the number of the implementation you wish to view.')) {
+      return drush_devel_fn_view($choice);
+    }
+  }
+  else {
+    drush_log(dt('No implementations.'), 'ok');
+  }
+}
+/**
+ * Command handler.  Show source code of specified function or method.
+ */
+function drush_devel_fn_view($function_name) {
+  // Get implementations in the .install files as well.
+  include_once './core/includes/install.inc';
+  drupal_load_updates();
+
+  if (strpos($function_name, '::') === FALSE) {
+    if (!function_exists($function_name)) {
+      return drush_set_error(dt('Function not found'));
+    }
+    $reflect = new ReflectionFunction($function_name);
+  }
+  else {
+    list($class, $method) = explode('::', $function_name);
+    if (!method_exists($class, $method)) {
+      return drush_set_error(dt('Method not found'));
+    }
+    $reflect = new ReflectionMethod($class, $method);
+  }
+  $func_info = array('@file' => $reflect->getFileName(), '@startline' => $reflect->getStartLine(), '@endline' => $reflect->getEndLine());
+  $format = drush_get_option('format', '@file');
+  drush_print_pipe(dt($format, $func_info));
+  drush_print(dt("// file: @file, lines @startline-@endline", $func_info));
+
+  _drush_devel_print_function($reflect->getFileName(), $reflect->getStartLine(), $reflect->getEndLine());
+}
+
+/**
+ * Command callback. List available tokens.
+ */
+function drush_devel_token() {
+  $rows[] = array(dt('Group'), dt('Token'), dt('Name'));
+  $all = \Drupal::token()->getInfo();
+  foreach ($all['tokens'] as $group => $tokens) {
+    foreach ($tokens as $key => $token) {
+      $rows[] = array($group, $key, $token['name']);
+    }
+  }
+  drush_print_table($rows, TRUE);
+}
+
+/**
+ * Command callback. Outputs a UUID.
+ *
+ * @return string
+ *   A freshly generated UUID.
+ */
+function drush_devel_generate_uuid() {
+  $uuid = new Php();
+  return $uuid->generate();
+}
+
+/**
+ * Print the specified function, including any
+ * doxygen-style comments that come before it.
+ */
+function _drush_devel_print_function($file, $start_line, $end_line) {
+  $line_num = 0;
+  $doxygen = NULL;
+  $fp = fopen( $file, 'r' );
+
+  while (!feof($fp) && ($line_num < ($start_line - 1))) {
+    $line = fgets($fp);
+    ++$line_num;
+
+    if (substr($line,0,3) == '/**') {
+      $doxygen = $line;
+    }
+    elseif (isset($doxygen)) {
+      $doxygen .= $line;
+      if ($line_num + 1 == $start_line) {
+        drush_print(rtrim($doxygen));
+      }
+      if (strstr($line, '*/') !== FALSE) {
+        $doxygen = NULL;
+      }
+    }
+  }
+  while (!feof($fp) && ($line_num < $end_line)) {
+    $line = fgets($fp);
+    ++$line_num;
+    drush_print(rtrim($line));
+  }
+}
+
+/**
+ * Command callback to list available container services.
+ */
+function drush_devel_container_services($prefix = NULL) {
+  $container = Drupal::getContainer();
+
+  if (empty($container)) {
+    return drush_set_error(dt('No container was found.'));
+  }
+
+  // Get a list of all available service IDs.
+  $services = $container->getServiceIds();
+
+  // If there is a prefix, try to find matches.
+  if (isset($prefix)) {
+    $services = preg_grep("/$prefix/", $services);
+  }
+
+  if (empty($services)) {
+    return drush_log(dt('No container services found.'), 'ok');
+  }
+
+  sort($services);
+  return $services;
+}

+ 38 - 0
sites/all/modules/contrib/dev/devel/drush/develDrushTest.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace Unish;
+
+if (class_exists('Unish\CommandUnishTestCase')) {
+
+  /**
+   * PHPUnit Tests for devel. This uses Drush's own test framework, based on PHPUnit.
+   * To run the tests, use run-tests-drush.sh from the devel directory.
+   */
+  class develCase extends CommandUnishTestCase {
+
+    public function testFnCommands() {
+      // Specify '8' just in case user has not set UNISH_DRUPAL_MAJOR_VERSION env variable.
+      $sites = $this->setUpDrupal(1, TRUE, '8');
+
+      // Symlink this module into the Site Under test so it can be enabled.
+      $target = dirname(__DIR__);
+      \symlink($target, $this->webroot() . '/modules/devel');
+      $options = array(
+        'root' => $this->webroot(),
+        'uri' => key($sites),
+      );
+      $this->drush('pm-enable', array('devel'), $options + array('skip' => NULL, 'yes' => NULL));
+
+      $this->drush('fn-view', array('drush_main'), $options);
+      $output = $this->getOutput();
+      $this->assertContains('@return', $output, 'Output contain @return Doxygen.');
+      $this->assertContains('function drush_main() {', $output, 'Output contains function drush_main() declaration');
+
+  //    $this->drush('fn-hook', array('cron'), $options);
+  //    $output = $this->getOutputAsList();
+  //    $expected = array('dblog', 'file', 'field', 'system', 'update');
+  //    $this->assertSame($expected, $output);
+    }
+  }
+
+}

+ 105 - 0
sites/all/modules/contrib/dev/devel/drush/phpstorm.drush.inc

@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * @file
+ * Generate PhpStorm metadata file.
+ */
+
+/**
+ * Implements of hook_drush_command().
+ */
+function phpstorm_drush_command() {
+  $items = array();
+
+  $items['phpstorm-metadata'] = array(
+    'description' => 'Save the PhpStorm Metadata file to Drupal root.',
+    'core' => array('8+'),
+    'aliases' => array('phpm'),
+    'category' => 'devel',
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_drush_help_alter().
+ */
+function phpstorm_drush_help_alter(&$command) {
+  if ($command['command'] == 'cache-rebuild') {
+    $command['options']['storm'] = 'Write a new PHPstorm metadata file to Drupal root.';
+  }
+}
+
+/*
+ * Implements drush_hook_post_COMMAND().
+ */
+function drush_phpstorm_post_cache_rebuild() {
+  if (drush_get_option('storm')) {
+    drush_invoke_process('@self', 'phpstorm-metadata');
+  }
+}
+
+/**
+ * Generate PhpStorm Metadata file.
+ *
+ * @see http://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata
+ */
+function drush_phpstorm_metadata() {
+  $container = \Drupal::getContainer();
+
+  $reflectedClass = new ReflectionClass($container);
+
+  $map = array();
+
+  // Map for all services of the container.
+  // @see \Symfony\Component\DependencyInjection\Container::getServiceIds().
+  foreach ($reflectedClass->getMethods() as $method) {
+    if (preg_match('/^get(.+)Service$/', $method->name, $match)) {
+      $id = strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($match[1], '_', '.')));
+      $service = \Drupal::service($id);
+      if (is_object($service)) {
+        $map["\\Drupal::service('')"][$id] = '\\' . get_class($service);
+      }
+    }
+  }
+
+  // Entity Manager - getStorage
+  foreach (\Drupal::entityTypeManager()->getDefinitions() as $type => $definition) {
+    $class = Drupal::entityTypeManager()->getStorage($type);
+    $map["\\Drupal::entityManager()->getStorage('')"][$type] = '\\' . get_class($class);
+    $map["\\Drupal::entityTypeManager()->getStorage('')"][$type] = '\\' . get_class($class);
+  }
+
+  $content = _drush_phpstorm_metadata_phpstorm_metadata_template($map);
+  file_put_contents(DRUPAL_ROOT . '/.phpstorm.meta.php', $content);
+}
+
+function _drush_phpstorm_metadata_phpstorm_metadata_template($data) {
+  $file = '<?php
+
+namespace PHPSTORM_META {
+
+  /** @noinspection PhpUnusedLocalVariableInspection */
+  /** @noinspection PhpIllegalArrayKeyTypeInspection */
+  $STATIC_METHOD_TYPES = [
+';
+
+  foreach ($data as $method => $map) {
+    $file .= "\n";
+    $file .= "    {$method} => [\n";
+
+    foreach ($map as $argument => $class) {
+      $file .= "      '{$argument}' instanceof {$class},\n";
+    }
+
+    $file .= "    ],";
+    $file .= "\n";
+  }
+
+  $file .= '
+    ];
+  }
+  ';
+
+  return $file;
+}

+ 37 - 0
sites/all/modules/contrib/dev/devel/kint/README.txt

@@ -0,0 +1,37 @@
+WHAT IS IT?
+-----------
+Kint for PHP is a tool designed to present your debugging data in the absolutely
+best way possible.
+
+In other words, it's var_dump() and debug_backtrace() on steroids. Easy to use,
+but powerful and customizable. An essential addition to your development
+toolbox.
+
+USAGE
+-----
+This module allows to use these aliases:
+    kint($data1, $data2, $data3, ...);
+    ksm($data1, $data2, $data3, ...)
+    kint_trace();
+
+But to get the most out of Kint, you will want to use directly the Kint class:
+    kint_require();
+    Kint::dump($data);
+
+Learn more about Kint: http://raveren.github.io/kint/
+
+
+The Kint class function dd() will not work as expected, because this alias
+is already defined in devel.module for other purposes.
+
+CONTACTS
+--------
+Module author:
+    Alexander Danilenko
+    danilenko.dn@gmail.com
+    https://drupal.org/user/1072104
+
+Kint author:
+    Rokas Šleinius a.k.a. Raveren
+    raveren@gmail.com
+    https://github.com/raveren

+ 13 - 0
sites/all/modules/contrib/dev/devel/kint/kint.info.yml

@@ -0,0 +1,13 @@
+name: 'Devel Kint'
+type: module
+description: 'Wrapper for Kint debugging tool'
+package: Development
+# core: 8.x
+tags:
+ - developer
+
+# Information added by Drupal.org packaging script on 2016-09-03
+version: '8.x-1.0-alpha1+23-dev'
+core: '8.x'
+project: 'devel'
+datestamp: 1472897643

+ 65 - 0
sites/all/modules/contrib/dev/devel/kint/kint.module

@@ -0,0 +1,65 @@
+<?php
+
+use Drupal\Core\Render\Markup;
+
+/**
+ * Alias of Kint::dump().
+ *
+ * Prints passed argument(s) using Kint debug tool.
+ */
+function kint() {
+  kint_require();
+  if (\Drupal::currentUser()->hasPermission('access kint')) {
+    $args = func_get_args();
+    if (PHP_SAPI === 'cli') {
+      s($args);
+    }
+    else {
+      \Kint::dump($args);
+    }
+  }
+}
+
+/**
+ * Alias of Kint::trace().
+ *
+ * Prints backtrace in Kint debug tool.
+ */
+function kint_trace() {
+  kint_require();
+  if (\Drupal::currentUser()->hasPermission('access kint')) {
+    call_user_func_array(array('Kint', 'trace'), array());
+  }
+}
+
+/**
+ * Alias of Kint::kintLite().
+ *
+ * Prints with lightweight formatting, using whitespace for formatting instead
+ * of HTML.
+ */
+function kint_lite() {
+  if (\Drupal::currentUser()->hasPermission('access kint')) {
+    $args = func_get_args();
+    call_user_func_array('kintLite', $args);
+  }
+}
+
+/**
+ * Prints passed argument(s) to the 'message' area of the page.
+ */
+function ksm() {
+  kint_require();
+  if (\Drupal::currentUser()->hasPermission('access kint')) {
+    $args = func_get_args();
+    $msg = @Kint::dump($args);
+    drupal_set_message(Markup::create($msg));
+  }
+}
+
+/**
+ * Load the Kint class.
+ */
+function kint_require() {
+  return require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'kint') . '/kint/Kint.class.php';
+}

+ 4 - 0
sites/all/modules/contrib/dev/devel/kint/kint.permissions.yml

@@ -0,0 +1,4 @@
+access kint:
+  description: 'View developer debug output.'
+  title: 'Access kint information'
+  restrict access: TRUE

+ 5 - 0
sites/all/modules/contrib/dev/devel/kint/kint.services.yml

@@ -0,0 +1,5 @@
+services:
+  kint.twig.kint_extension:
+    class: Drupal\kint\Twig\KintExtension
+    tags:
+      - { name: twig.extension }

+ 3 - 0
sites/all/modules/contrib/dev/devel/kint/kint/.gitignore

@@ -0,0 +1,3 @@
+
+/config.php
+/.idea

+ 836 - 0
sites/all/modules/contrib/dev/devel/kint/kint/Kint.class.php

@@ -0,0 +1,836 @@
+<?php
+/**
+ * Kint is a zero-setup debugging tool to output information about variables and stack traces prettily and comfortably.
+ *
+ * https://github.com/raveren/kint
+ */
+
+
+if ( defined( 'KINT_DIR' ) ) return;
+
+
+define( 'KINT_DIR', dirname( __FILE__ ) . '/' );
+define( 'KINT_PHP53', version_compare( PHP_VERSION, '5.3.0' ) >= 0 );
+
+require KINT_DIR . 'config.default.php';
+require KINT_DIR . 'inc/kintVariableData.class.php';
+require KINT_DIR . 'inc/kintParser.class.php';
+require KINT_DIR . 'inc/kintObject.class.php';
+require KINT_DIR . 'decorators/rich.php';
+require KINT_DIR . 'decorators/plain.php';
+
+if ( is_readable( KINT_DIR . 'config.php' ) ) {
+	require KINT_DIR . 'config.php';
+}
+
+# init settings
+if ( !empty( $GLOBALS['_kint_settings'] ) ) {
+	Kint::enabled( $GLOBALS['_kint_settings']['enabled'] );
+
+	foreach ( $GLOBALS['_kint_settings'] as $key => $val ) {
+		property_exists( 'Kint', $key ) and Kint::$$key = $val;
+	}
+
+	unset( $GLOBALS['_kint_settings'], $key, $val );
+}
+
+class Kint
+{
+	// these are all public and 1:1 config array keys so you can switch them easily
+	private static $_enabledMode; # stores mode and active statuses
+
+	public static $returnOutput;
+	public static $fileLinkFormat;
+	public static $displayCalledFrom;
+	public static $charEncodings;
+	public static $maxStrLength;
+	public static $appRootDirs;
+	public static $maxLevels;
+	public static $theme;
+	public static $expandedByDefault;
+
+	public static $cliDetection;
+	public static $cliColors;
+
+	const MODE_RICH       = 'r';
+	const MODE_WHITESPACE = 'w';
+	const MODE_CLI        = 'c';
+	const MODE_PLAIN      = 'p';
+
+
+	public static $aliases = array(
+		'methods'   => array(
+			array( 'kint', 'dump' ),
+			array( 'kint', 'trace' ),
+		),
+		'functions' => array(
+			'd',
+			'dd',
+			'ddd',
+			's',
+			'sd',
+		)
+	);
+
+	private static $_firstRun = true;
+
+	/**
+	 * Enables or disables Kint, can globally enforce the rendering mode. If called without parameters, returns the
+	 * current mode.
+	 *
+	 * @param mixed $forceMode
+	 *      null or void - return current mode
+	 *      false        - disable (no output)
+	 *      true         - enable and detect cli automatically
+	 *      Kint::MODE_* - enable and force selected mode disregarding detection and function
+	 *                     shorthand (s()/d()), note that you can still override this
+	 *                     with the "~" modifier
+	 *
+	 * @return mixed        previously set value if a new one is passed
+	 */
+	public static function enabled( $forceMode = null )
+	{
+		# act both as a setter...
+		if ( isset( $forceMode ) ) {
+			$before             = self::$_enabledMode;
+			self::$_enabledMode = $forceMode;
+
+			return $before;
+		}
+
+		# ...and a getter
+		return self::$_enabledMode;
+	}
+
+	/**
+	 * Prints a debug backtrace, same as Kint::dump(1)
+	 *
+	 * @param array $trace [OPTIONAL] you can pass your own trace, otherwise, `debug_backtrace` will be called
+	 *
+	 * @return mixed
+	 */
+	public static function trace( $trace = null )
+	{
+		if ( !self::enabled() ) return '';
+
+		return self::dump( isset( $trace ) ? $trace : debug_backtrace( true ) );
+	}
+
+
+	/**
+	 * Dump information about variables, accepts any number of parameters, supports modifiers:
+	 *
+	 *  clean up any output before kint and place the dump at the top of page:
+	 *   - Kint::dump()
+	 *  *****
+	 *  expand all nodes on display:
+	 *   ! Kint::dump()
+	 *  *****
+	 *  dump variables disregarding their depth:
+	 *   + Kint::dump()
+	 *  *****
+	 *  return output instead of displaying it:
+	 *   @ Kint::dump()
+	 *  *****
+	 *  force output as plain text
+	 *   ~ Kint::dump()
+	 *
+	 * Modifiers are supported by all dump wrapper functions, including Kint::trace(). Space is optional.
+	 *
+	 *
+	 * You can also use the following shorthand to display debug_backtrace():
+	 *   Kint::dump( 1 );
+	 *
+	 * Passing the result from debug_backtrace() to kint::dump() as a single parameter will display it as trace too:
+	 *   $trace = debug_backtrace( true );
+	 *   Kint::dump( $trace );
+	 *  Or simply:
+	 *   Kint::dump( debug_backtrace() );
+	 *
+	 *
+	 * @param mixed $data
+	 *
+	 * @return void|string
+	 */
+	public static function dump( $data = null )
+	{
+		if ( !self::enabled() ) return '';
+
+		list( $names, $modifiers, $callee, $previousCaller, $miniTrace ) = self::_getCalleeInfo(
+			defined( 'DEBUG_BACKTRACE_IGNORE_ARGS' )
+				? debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS )
+				: debug_backtrace()
+		);
+		$modeOldValue     = self::enabled();
+		$firstRunOldValue = self::$_firstRun;
+
+		# process modifiers: @, +, !, ~ and -
+		if ( strpos( $modifiers, '-' ) !== false ) {
+			self::$_firstRun = true;
+			while ( ob_get_level() ) {
+				ob_end_clean();
+			}
+		}
+		if ( strpos( $modifiers, '!' ) !== false ) {
+			$expandedByDefaultOldValue = self::$expandedByDefault;
+			self::$expandedByDefault   = true;
+		}
+		if ( strpos( $modifiers, '+' ) !== false ) {
+			$maxLevelsOldValue = self::$maxLevels;
+			self::$maxLevels   = false;
+		}
+		if ( strpos( $modifiers, '@' ) !== false ) {
+			$returnOldValue     = self::$returnOutput;
+			self::$returnOutput = true;
+			self::$_firstRun    = true;
+		}
+		if ( strpos( $modifiers, '~' ) !== false ) {
+			self::enabled( self::MODE_WHITESPACE );
+		}
+
+		# set mode for current run
+		$mode = self::enabled();
+		if ( $mode === true ) {
+			$mode = PHP_SAPI === 'cli'
+				? self::MODE_CLI
+				: self::MODE_RICH;
+		}
+		self::enabled( $mode );
+
+		$decorator = self::enabled() === self::MODE_RICH
+			? 'Kint_Decorators_Rich'
+			: 'Kint_Decorators_Plain';
+
+		$output = '';
+		if ( self::$_firstRun ) {
+			$output .= call_user_func( array( $decorator, 'init' ) );
+		}
+
+
+		$trace = false;
+		if ( $names === array( null ) && func_num_args() === 1 && $data === 1 ) { # Kint::dump(1) shorthand
+			$trace = KINT_PHP53 ? debug_backtrace( true ) : debug_backtrace();
+		} elseif ( func_num_args() === 1 && is_array( $data ) ) {
+			$trace = $data; # test if the single parameter is result of debug_backtrace()
+		}
+		$trace and $trace = self::_parseTrace( $trace );
+
+
+		$output .= call_user_func( array( $decorator, 'wrapStart' ) );
+		if ( $trace ) {
+			$output .= call_user_func( array( $decorator, 'decorateTrace' ), $trace );
+		} else {
+			$data = func_num_args() === 0
+				? array( "[[no arguments passed]]" )
+				: func_get_args();
+
+			foreach ( $data as $k => $argument ) {
+				kintParser::reset();
+				# when the dump arguments take long to generate output, user might have changed the file and
+				# Kint might not parse the arguments correctly, so check if names are set and while the
+				# displayed names might be wrong, at least don't throw an error
+				$output .= call_user_func(
+					array( $decorator, 'decorate' ),
+					kintParser::factory( $argument, isset( $names[ $k ] ) ? $names[ $k ] : '' )
+				);
+			}
+		}
+
+		$output .= call_user_func( array( $decorator, 'wrapEnd' ), $callee, $miniTrace, $previousCaller );
+
+		self::enabled( $modeOldValue );
+
+		self::$_firstRun = false;
+		if ( strpos( $modifiers, '~' ) !== false ) {
+			self::$_firstRun = $firstRunOldValue;
+		} else {
+			self::enabled( $modeOldValue );
+		}
+		if ( strpos( $modifiers, '!' ) !== false ) {
+			self::$expandedByDefault = $expandedByDefaultOldValue;
+		}
+		if ( strpos( $modifiers, '+' ) !== false ) {
+			self::$maxLevels = $maxLevelsOldValue;
+		}
+		if ( strpos( $modifiers, '@' ) !== false ) {
+			self::$returnOutput = $returnOldValue;
+			self::$_firstRun    = $firstRunOldValue;
+			return $output;
+		}
+
+		if ( self::$returnOutput ) return $output;
+
+		echo $output;
+		return '';
+	}
+
+
+	/**
+	 * generic path display callback, can be configured in the settings; purpose is to show relevant path info and hide
+	 * as much of the path as possible.
+	 *
+	 * @param string $file
+	 *
+	 * @return string
+	 */
+	public static function shortenPath( $file )
+	{
+		$file          = str_replace( '\\', '/', $file );
+		$shortenedName = $file;
+		$replaced      = false;
+		if ( is_array( self::$appRootDirs ) ) foreach ( self::$appRootDirs as $path => $replaceString ) {
+			if ( empty( $path ) ) continue;
+
+			$path = str_replace( '\\', '/', $path );
+
+			if ( strpos( $file, $path ) === 0 ) {
+				$shortenedName = $replaceString . substr( $file, strlen( $path ) );
+				$replaced      = true;
+				break;
+			}
+		}
+
+		# fallback to find common path with Kint dir
+		if ( !$replaced ) {
+			$pathParts = explode( '/', str_replace( '\\', '/', KINT_DIR ) );
+			$fileParts = explode( '/', $file );
+			$i         = 0;
+			foreach ( $fileParts as $i => $filePart ) {
+				if ( !isset( $pathParts[ $i ] ) || $pathParts[ $i ] !== $filePart ) break;
+			}
+
+			$shortenedName = ( $i ? '.../' : '' ) . implode( '/', array_slice( $fileParts, $i ) );
+		}
+
+		return $shortenedName;
+	}
+
+	public static function getIdeLink( $file, $line )
+	{
+		return str_replace( array( '%f', '%l' ), array( $file, $line ), self::$fileLinkFormat );
+	}
+
+	/**
+	 * trace helper, shows the place in code inline
+	 *
+	 * @param string $file full path to file
+	 * @param int    $lineNumber the line to display
+	 * @param int    $padding surrounding lines to show besides the main one
+	 *
+	 * @return bool|string
+	 */
+	private static function _showSource( $file, $lineNumber, $padding = 7 )
+	{
+		if ( !$file OR !is_readable( $file ) ) {
+			# continuing will cause errors
+			return false;
+		}
+
+		# open the file and set the line position
+		$file = fopen( $file, 'r' );
+		$line = 0;
+
+		# Set the reading range
+		$range = array(
+			'start' => $lineNumber - $padding,
+			'end'   => $lineNumber + $padding
+		);
+
+		# set the zero-padding amount for line numbers
+		$format = '% ' . strlen( $range['end'] ) . 'd';
+
+		$source = '';
+		while ( ( $row = fgets( $file ) ) !== false ) {
+			# increment the line number
+			if ( ++$line > $range['end'] ) {
+				break;
+			}
+
+			if ( $line >= $range['start'] ) {
+				# make the row safe for output
+				$row = htmlspecialchars( $row, ENT_NOQUOTES, 'UTF-8' );
+
+				# trim whitespace and sanitize the row
+				$row = '<span>' . sprintf( $format, $line ) . '</span> ' . $row;
+
+				if ( $line === $lineNumber ) {
+					# apply highlighting to this row
+					$row = '<div class="kint-highlight">' . $row . '</div>';
+				} else {
+					$row = '<div>' . $row . '</div>';
+				}
+
+				# add to the captured source
+				$source .= $row;
+			}
+		}
+
+		# close the file
+		fclose( $file );
+
+		return $source;
+	}
+
+
+	/**
+	 * returns parameter names that the function was passed, as well as any predefined symbols before function
+	 * call (modifiers)
+	 *
+	 * @param array $trace
+	 *
+	 * @return array( $parameters, $modifier, $callee, $previousCaller )
+	 */
+	private static function _getCalleeInfo( $trace )
+	{
+		$previousCaller = array();
+		$miniTrace      = array();
+		$prevStep       = array();
+
+		# go from back of trace to find first occurrence of call to Kint or its wrappers
+		while ( $step = array_pop( $trace ) ) {
+
+			if ( self::_stepIsInternal( $step ) ) {
+				$previousCaller = $prevStep;
+				break;
+			} elseif ( isset( $step['file'], $step['line'] ) ) {
+				unset( $step['object'], $step['args'] );
+				array_unshift( $miniTrace, $step );
+			}
+
+			$prevStep = $step;
+		}
+		$callee = $step;
+
+		if ( !isset( $callee['file'] ) || !is_readable( $callee['file'] ) ) return false;
+
+
+		# open the file and read it up to the position where the function call expression ended
+		$file   = fopen( $callee['file'], 'r' );
+		$line   = 0;
+		$source = '';
+		while ( ( $row = fgets( $file ) ) !== false ) {
+			if ( ++$line > $callee['line'] ) break;
+			$source .= $row;
+		}
+		fclose( $file );
+		$source = self::_removeAllButCode( $source );
+
+
+		if ( empty( $callee['class'] ) ) {
+			$codePattern = $callee['function'];
+		} else {
+			if ( $callee['type'] === '::' ) {
+				$codePattern = $callee['class'] . "\x07*" . $callee['type'] . "\x07*" . $callee['function'];;
+			} else /*if ( $callee['type'] === '->' )*/ {
+				$codePattern = ".*\x07*" . $callee['type'] . "\x07*" . $callee['function'];;
+			}
+		}
+
+		// todo if more than one call in one line - not possible to determine variable names
+		// todo does not recognize string concat
+		# get the position of the last call to the function
+		preg_match_all( "
+            [
+            # beginning of statement
+            [\x07{(]
+
+            # search for modifiers (group 1)
+            ([-+!@~]*)?
+
+            # spaces
+            \x07*
+
+            # check if output is assigned to a variable (group 2) todo: does not detect concat
+            (
+                \\$[a-z0-9_]+ # variable
+                \x07*\\.?=\x07*  # assignment
+            )?
+
+            # possibly a namespace symbol
+            \\\\?
+
+			# spaces again
+            \x07*
+
+            # main call to Kint
+            {$codePattern}
+
+			# spaces everywhere
+            \x07*
+
+            # find the character where kint's opening bracket resides (group 3)
+            (\\()
+
+            ]ix",
+			$source,
+			$matches,
+			PREG_OFFSET_CAPTURE
+		);
+
+		$modifiers  = end( $matches[1] );
+		$assignment = end( $matches[2] );
+		$bracket    = end( $matches[3] );
+
+		$modifiers = $modifiers[0];
+		if ( $assignment[1] !== -1 ) {
+			$modifiers .= '@';
+		}
+
+		$paramsString = preg_replace( "[\x07+]", ' ', substr( $source, $bracket[1] + 1 ) );
+		# we now have a string like this:
+		# <parameters passed>); <the rest of the last read line>
+
+		# remove everything in brackets and quotes, we don't need nested statements nor literal strings which would
+		# only complicate separating individual arguments
+		$c              = strlen( $paramsString );
+		$inString       = $escaped = $openedBracket = $closingBracket = false;
+		$i              = 0;
+		$inBrackets     = 0;
+		$openedBrackets = array();
+
+		while ( $i < $c ) {
+			$letter = $paramsString[ $i ];
+
+			if ( !$inString ) {
+				if ( $letter === '\'' || $letter === '"' ) {
+					$inString = $letter;
+				} elseif ( $letter === '(' || $letter === '[' ) {
+					$inBrackets++;
+					$openedBrackets[] = $openedBracket = $letter;
+					$closingBracket   = $openedBracket === '(' ? ')' : ']';
+				} elseif ( $inBrackets && $letter === $closingBracket ) {
+					$inBrackets--;
+					array_pop( $openedBrackets );
+					$openedBracket  = end( $openedBrackets );
+					$closingBracket = $openedBracket === '(' ? ')' : ']';
+				} elseif ( !$inBrackets && $letter === ')' ) {
+					$paramsString = substr( $paramsString, 0, $i );
+					break;
+				}
+			} elseif ( $letter === $inString && !$escaped ) {
+				$inString = false;
+			}
+
+			# replace whatever was inside quotes or brackets with untypeable characters, we don't
+			# need that info. We'll later replace the whole string with '...'
+			if ( $inBrackets > 0 ) {
+				if ( $inBrackets > 1 || $letter !== $openedBracket ) {
+					$paramsString[ $i ] = "\x07";
+				}
+			}
+			if ( $inString ) {
+				if ( $letter !== $inString || $escaped ) {
+					$paramsString[ $i ] = "\x07";
+				}
+			}
+
+			$escaped = !$escaped && ( $letter === '\\' );
+			$i++;
+		}
+
+		# by now we have an un-nested arguments list, lets make it to an array for processing further
+		$arguments = explode( ',', preg_replace( "[\x07+]", '...', $paramsString ) );
+
+		# test each argument whether it was passed literary or was it an expression or a variable name
+		$parameters = array();
+		$blacklist  = array( 'null', 'true', 'false', 'array(...)', 'array()', '"..."', '[...]', 'b"..."', );
+		foreach ( $arguments as $argument ) {
+			$argument = trim( $argument );
+
+			if ( is_numeric( $argument )
+				|| in_array( str_replace( "'", '"', strtolower( $argument ) ), $blacklist, true )
+			) {
+				$parameters[] = null;
+			} else {
+				$parameters[] = $argument;
+			}
+		}
+
+		return array( $parameters, $modifiers, $callee, $previousCaller, $miniTrace );
+	}
+
+	/**
+	 * removes comments and zaps whitespace & <?php tags from php code, makes for easier further parsing
+	 *
+	 * @param string $source
+	 *
+	 * @return string
+	 */
+	private static function _removeAllButCode( $source )
+	{
+		$commentTokens    = array(
+			T_COMMENT => true, T_INLINE_HTML => true, T_DOC_COMMENT => true
+		);
+		$whiteSpaceTokens = array(
+			T_WHITESPACE => true, T_CLOSE_TAG => true,
+			T_OPEN_TAG   => true, T_OPEN_TAG_WITH_ECHO => true,
+		);
+
+		$cleanedSource = '';
+		foreach ( token_get_all( $source ) as $token ) {
+			if ( is_array( $token ) ) {
+				if ( isset( $commentTokens[ $token[0] ] ) ) continue;
+
+				if ( isset( $whiteSpaceTokens[ $token[0] ] ) ) {
+					$token = "\x07";
+				} else {
+					$token = $token[1];
+				}
+			} elseif ( $token === ';' ) {
+				$token = "\x07";
+			}
+
+			$cleanedSource .= $token;
+		}
+		return $cleanedSource;
+	}
+
+	/**
+	 * returns whether current trace step belongs to Kint or its wrappers
+	 *
+	 * @param $step
+	 *
+	 * @return array
+	 */
+	private static function _stepIsInternal( $step )
+	{
+		if ( isset( $step['class'] ) ) {
+			foreach ( self::$aliases['methods'] as $alias ) {
+				if ( $alias[0] === strtolower( $step['class'] ) && $alias[1] === strtolower( $step['function'] ) ) {
+					return true;
+				}
+			}
+			return false;
+		} else {
+			return in_array( strtolower( $step['function'] ), self::$aliases['functions'], true );
+		}
+	}
+
+	private static function _parseTrace( array $data )
+	{
+		$trace       = array();
+		$traceFields = array( 'file', 'line', 'args', 'class' );
+		$fileFound   = false; # file element must exist in one of the steps
+
+		# validate whether a trace was indeed passed
+		while ( $step = array_pop( $data ) ) {
+			if ( !is_array( $step ) || !isset( $step['function'] ) ) return false;
+			if ( !$fileFound && isset( $step['file'] ) && file_exists( $step['file'] ) ) {
+				$fileFound = true;
+			}
+
+			$valid = false;
+			foreach ( $traceFields as $element ) {
+				if ( isset( $step[ $element ] ) ) {
+					$valid = true;
+					break;
+				}
+			}
+			if ( !$valid ) return false;
+
+			if ( self::_stepIsInternal( $step ) ) {
+				$step = array(
+					'file'     => $step['file'],
+					'line'     => $step['line'],
+					'function' => '',
+				);
+				array_unshift( $trace, $step );
+				break;
+			}
+			if ( $step['function'] !== 'spl_autoload_call' ) { # meaningless
+				array_unshift( $trace, $step );
+			}
+		}
+		if ( !$fileFound ) return false;
+
+		$output = array();
+		foreach ( $trace as $step ) {
+			if ( isset( $step['file'] ) ) {
+				$file = $step['file'];
+
+				if ( isset( $step['line'] ) ) {
+					$line = $step['line'];
+					# include the source of this step
+					if ( self::enabled() === self::MODE_RICH ) {
+						$source = self::_showSource( $file, $line );
+					}
+				}
+			}
+
+			$function = $step['function'];
+
+			if ( in_array( $function, array( 'include', 'include_once', 'require', 'require_once' ) ) ) {
+				if ( empty( $step['args'] ) ) {
+					# no arguments
+					$args = array();
+				} else {
+					# sanitize the included file path
+					$args = array( 'file' => self::shortenPath( $step['args'][0] ) );
+				}
+			} elseif ( isset( $step['args'] ) ) {
+				if ( empty( $step['class'] ) && !function_exists( $function ) ) {
+					# introspection on closures or language constructs in a stack trace is impossible before PHP 5.3
+					$params = null;
+				} else {
+					try {
+						if ( isset( $step['class'] ) ) {
+							if ( method_exists( $step['class'], $function ) ) {
+								$reflection = new ReflectionMethod( $step['class'], $function );
+							} else if ( isset( $step['type'] ) && $step['type'] == '::' ) {
+								$reflection = new ReflectionMethod( $step['class'], '__callStatic' );
+							} else {
+								$reflection = new ReflectionMethod( $step['class'], '__call' );
+							}
+						} else {
+							$reflection = new ReflectionFunction( $function );
+						}
+
+						# get the function parameters
+						$params = $reflection->getParameters();
+					} catch ( Exception $e ) { # avoid various PHP version incompatibilities
+						$params = null;
+					}
+				}
+
+				$args = array();
+				foreach ( $step['args'] as $i => $arg ) {
+					if ( isset( $params[ $i ] ) ) {
+						# assign the argument by the parameter name
+						$args[ $params[ $i ]->name ] = $arg;
+					} else {
+						# assign the argument by number
+						$args[ '#' . ( $i + 1 ) ] = $arg;
+					}
+				}
+			}
+
+			if ( isset( $step['class'] ) ) {
+				# Class->method() or Class::method()
+				$function = $step['class'] . $step['type'] . $function;
+			}
+
+			// todo it's possible to parse the object name out from the source!
+			$output[] = array(
+				'function' => $function,
+				'args'     => isset( $args ) ? $args : null,
+				'file'     => isset( $file ) ? $file : null,
+				'line'     => isset( $line ) ? $line : null,
+				'source'   => isset( $source ) ? $source : null,
+				'object'   => isset( $step['object'] ) ? $step['object'] : null,
+			);
+
+			unset( $function, $args, $file, $line, $source );
+		}
+
+		return $output;
+	}
+}
+
+
+if ( !function_exists( 'd' ) ) {
+	/**
+	 * Alias of Kint::dump()
+	 *
+	 * @return string
+	 */
+	function d()
+	{
+		if ( !Kint::enabled() ) return '';
+		$_ = func_get_args();
+		return call_user_func_array( array( 'Kint', 'dump' ), $_ );
+	}
+}
+
+if ( !function_exists( 'dd' ) ) {
+	/**
+	 * Alias of Kint::dump()
+	 * [!!!] IMPORTANT: execution will halt after call to this function
+	 *
+	 * @return string
+	 * @deprecated
+	 */
+	function dd()
+	{
+		if ( !Kint::enabled() ) return '';
+
+		echo "<pre>Kint: dd() is being deprecated, please use ddd() instead</pre>\n";
+		$_ = func_get_args();
+		call_user_func_array( array( 'Kint', 'dump' ), $_ );
+		die;
+	}
+}
+
+if ( !function_exists( 'ddd' ) ) {
+	/**
+	 * Alias of Kint::dump()
+	 * [!!!] IMPORTANT: execution will halt after call to this function
+	 *
+	 * @return string
+	 */
+	function ddd()
+	{
+		if ( !Kint::enabled() ) return '';
+		$_ = func_get_args();
+		call_user_func_array( array( 'Kint', 'dump' ), $_ );
+		die;
+	}
+}
+
+if ( !function_exists( 's' ) ) {
+	/**
+	 * Alias of Kint::dump(), however the output is in plain htmlescaped text and some minor visibility enhancements
+	 * added. If run in CLI mode, output is pure whitespace.
+	 *
+	 * To force rendering mode without autodetecting anything:
+	 *
+	 *  Kint::enabled( Kint::MODE_PLAIN );
+	 *  Kint::dump( $variable );
+	 *
+	 * [!!!] IMPORTANT: execution will halt after call to this function
+	 *
+	 * @return string
+	 */
+	function s()
+	{
+		$enabled = Kint::enabled();
+		if ( !$enabled ) return '';
+
+		if ( $enabled === Kint::MODE_WHITESPACE ) { # if already in whitespace, don't elevate to plain
+			$restoreMode = Kint::MODE_WHITESPACE;
+		} else {
+			$restoreMode = Kint::enabled( # remove cli colors in cli mode; remove rich interface in HTML mode
+				PHP_SAPI === 'cli' ? Kint::MODE_WHITESPACE : Kint::MODE_PLAIN
+			);
+		}
+
+		$params = func_get_args();
+		$dump   = call_user_func_array( array( 'Kint', 'dump' ), $params );
+		Kint::enabled( $restoreMode );
+		return $dump;
+	}
+}
+
+if ( !function_exists( 'sd' ) ) {
+	/**
+	 * @see s()
+	 *
+	 * [!!!] IMPORTANT: execution will halt after call to this function
+	 *
+	 * @return string
+	 */
+	function sd()
+	{
+		$enabled = Kint::enabled();
+		if ( !$enabled ) return '';
+
+		if ( $enabled !== Kint::MODE_WHITESPACE ) {
+			Kint::enabled(
+				PHP_SAPI === 'cli' ? Kint::MODE_WHITESPACE : Kint::MODE_PLAIN
+			);
+		}
+
+		$params = func_get_args();
+		call_user_func_array( array( 'Kint', 'dump' ), $params );
+		die;
+	}
+}

+ 20 - 0
sites/all/modules/contrib/dev/devel/kint/kint/LICENCE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Rokas Šleinius (raveren@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 141 - 0
sites/all/modules/contrib/dev/devel/kint/kint/README.md

@@ -0,0 +1,141 @@
+# Kint - debugging helper for PHP developers
+
+[![Total Downloads](https://poser.pugx.org/raveren/kint/downloads.png)](https://packagist.org/packages/raveren/kint)
+
+> **New version** v1.0.0 is released with more than two years of active development - changes are too numerous to list, but there's CLI output and literally hundreds of improvements and additions.
+
+![Screenshot](http://raveren.github.com/kint/img/preview.png)
+
+## What am I looking at?
+
+At first glance Kint is just a pretty replacement for **[var_dump()](http://php.net/manual/en/function.var-dump.php)**, **[print_r()](http://php.net/manual/en/function.print-r.php)** and **[debug_backtrace()](http://php.net/manual/en/function.debug-backtrace.php)**. 
+
+However, it's much, *much* more than that. Even the excellent `xdebug` var_dump improvements don't come close - you will eventually wonder how you developed without it. 
+
+Just to list some of the most useful features:
+
+ * The **variable name and place in code** where Kint was called from is displayed;
+ * You can **disable all Kint output easily and on the fly** - so you can even debug live systems without anyone knowing (even though you know you shouldn't be doing that!:). 
+ * **CLI is detected** and formatted for automatically (but everything can be overridden on the fly) - if your setup supports it, the output is colored too:
+  ![Kint CLI output](http://i.imgur.com/6B9MCLw.png)
+ * **Debug backtraces** are finally fully readable, actually informative and a pleasure to the eye.
+ * Kint has been **in active development for more than six years** and is shipped with [Drupal 8](https://www.drupal.org/) by default as part of its devel suite. You can trust it not being abandoned or getting left behind in features.
+ * Variable content is **displayed in the most informative way** - and you *never, ever* miss anything! Kint guarantees you see every piece of physically available information about everything you are dumping*; 
+   * <sup>in some cases, the content is truncated where it would otherwise be too large to view anyway - but the user is always made aware of that;</sup>
+ * Some variable content types have an alternative display - for example you will be able see `JSON` in its raw form - but also as an associative array:
+  ![Kint displays data intelligently](http://i.imgur.com/9P57Ror.png)
+  There are more than ten custom variable type displays inbuilt and more are added periodically.
+
+
+## Installation and Usage
+
+One of the main goals of Kint is to be **zero setup**. 
+
+[Download the archive](https://github.com/raveren/kint/releases/download/1.0.2/kint.zip) and simply
+```php
+<?php
+require '/kint/Kint.class.php';
+```
+
+**Or, if you use Composer:**
+
+```json
+"require": {
+   "raveren/kint": "^1.0"
+}
+```
+
+Or just run `composer require raveren/kint`
+
+**That's it, you can now use Kint to debug your code:**
+
+```php
+########## DUMP VARIABLE ###########################
+Kint::dump($GLOBALS, $_SERVER); // pass any number of parameters
+
+// or simply use d() as a shorthand:
+d($_SERVER);
+
+
+########## DEBUG BACKTRACE #########################
+Kint::trace();
+// or via shorthand:
+d(1);
+
+
+############# BASIC OUTPUT #########################
+# this will show a basic javascript-free display
+s($GLOBALS);
+
+
+######### WHITESPACE FORMATTED OUTPUT ##############
+# this will be garbled if viewed in browser as it is whitespace-formatted only
+~d($GLOBALS); // just prepend with the tilde
+
+
+########## MISCELLANEOUS ###########################
+# this will disable kint completely
+Kint::enabled(false);
+
+ddd('Get off my lawn!'); // no effect
+
+Kint::enabled(true);
+ddd( 'this line will stop the execution flow because Kint was just re-enabled above!' );
+
+
+```
+
+Note, that Kint *does* have configuration (like themes and IDE integration!), but it's in need of being rewritten, so I'm not documenting it yet.
+
+## Tips & Tricks
+
+  * Kint is enabled by default, call `Kint::enabled(false);` to turn its funcionality completely off. The *best practice* is to enable Kint in DEVELOPMENT environment only (or for example `Kint::enabled($_SERVER['REMOTE_ADDR'] === '<your IP>');`) - so even if you accidentally leave a dump in production, no one will know.
+  * `sd()` and `ddd()` are shorthands for `s();die;` and `d();die;` respectively. 
+    * **Important:** The older shorthand `dd()` is deprecated due to compatibility issues and will eventually be removed. Use the analogous `ddd()` instead.
+  * When looking at Kint output, press <kbd>D</kbd> on the keyboard and you will be able to traverse the tree with arrows and tab keys - and expand/collapse nodes with space or enter.
+  * Double clicking the `[+]` sign in the output will expand/collapse ALL nodes; triple clicking big blocks of text will select it all.
+  * Clicking the tiny arrows on the right of the output open it in a separate window where you can keep it for comparison.
+  * To catch output from Kint just assign it to a variable<sup>beta</sup>
+```php
+$o = Kint::dump($GLOBALS); 
+// yes, the assignment is automatically detected, and $o 
+// now holds whatever was going to be printed otherwise.
+
+// it also supports modifiers (read on) for the variable:
+~$o = Kint::dump($GLOBALS); // this output will be in whitespace
+```
+  * There are a couple of real-time modifiers you can use:
+    * `~d($var)` this call will output in plain text format.
+    * `+d($var)` will disregard depth level limits and output everything (careful, this can hang your browser on huge objects)
+    * `!d($var)` will show expanded rich output.
+    * `-d($var)` will attempt to `ob_clean` the previous output so if you're dumping something inside a HTML page, you will still see Kint output.
+  You can combine modifiers too: `~+d($var)`
+  * To force a specific dump output type just pass it to the `Kint::enabled()` method. Available options are: `Kint::MODE_RICH` (default), `Kint::MODE_PLAIN`, `Kint::MODE_WHITESPACE` and `Kint::MODE_CLI`:
+```php
+Kint::enabled(Kint::MODE_WHITESPACE);
+$kintOutput = Kint::dump($GLOBALS); 
+// now $kintOutput can be written to a text log file and 
+// be perfectly readable from there
+```
+  * To change display theme, use `Kint::$theme = '<theme name>';` where available options are: `'original'` (default), `'solarized'`, `'solarized-dark'` and `'aante-light'`. Here's an (outdated) preview:
+  ![Kint themes](http://raveren.github.io/kint/img/theme-preview.png)
+  * Kint also includes a naïve profiler you may find handy. It's for determining relatively which code blocks take longer than others:
+```php
+Kint::dump( microtime() ); // just pass microtime()
+sleep( 1 );
+Kint::dump( microtime(), 'after sleep(1)' );
+sleep( 2 );
+ddd( microtime(), 'final call, after sleep(2)' );
+```
+  ![Kint profiling feature](http://i.imgur.com/tmHUMW4.png)
+----
+
+[Visit the project page](http://raveren.github.com/kint/) for documentation, configuration, and more advanced usage examples.
+
+### Author
+
+**Rokas Šleinius** (Raveren)
+
+### License
+
+Licensed under the MIT License

+ 29 - 0
sites/all/modules/contrib/dev/devel/kint/kint/composer.json

@@ -0,0 +1,29 @@
+{
+    "name": "raveren/kint",
+    "description": "Kint - debugging helper for PHP developers",
+    "keywords": ["kint", "php", "debug"],
+    "type": "library",
+    "homepage": "https://github.com/raveren/kint",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Rokas Šleinius",
+            "homepage": "https://github.com/raveren"
+        },
+        {
+            "name": "Contributors",
+            "homepage": "https://github.com/raveren/kint/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=5.1.0"
+    },
+    "autoload": {
+        "files": ["Kint.class.php"]
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.0.x-dev"
+        }
+    }
+}

+ 94 - 0
sites/all/modules/contrib/dev/devel/kint/kint/config.default.php

@@ -0,0 +1,94 @@
+<?php
+isset( $GLOBALS['_kint_settings'] ) or $GLOBALS['_kint_settings'] = array();
+$_kintSettings = &$GLOBALS['_kint_settings'];
+
+
+/** @var bool if set to false, kint will become silent, same as Kint::enabled(false) or Kint::$enabled = false */
+$_kintSettings['enabled'] = true;
+
+
+/**
+ * @var bool whether to display where kint was called from
+ */
+$_kintSettings['displayCalledFrom'] = true;
+
+
+/**
+ * @var string format of the link to the source file in trace entries. Use %f for file path, %l for line number.
+ * Defaults to xdebug.file_link_format if not set.
+ *
+ * [!] EXAMPLE (works with for phpStorm and RemoteCall Plugin):
+ *
+ * $_kintSettings['fileLinkFormat'] = 'http://localhost:8091/?message=%f:%l';
+ *
+ */
+$_kintSettings['fileLinkFormat'] = ini_get( 'xdebug.file_link_format' );
+
+
+/**
+ * @var array base directories of your application that will be displayed instead of the full path. Keys are paths,
+ * values are replacement strings
+ *
+ * Defaults to array( $_SERVER['DOCUMENT_ROOT'] => '&lt;ROOT&gt;' )
+ *
+ * [!] EXAMPLE (for Kohana framework):
+ *
+ * $_kintSettings['appRootDirs'] = array(
+ *      APPPATH => 'APPPATH', // make sure the constants are already defined at the time of including this config file
+ *      SYSPATH => 'SYSPATH',
+ *      MODPATH => 'MODPATH',
+ *      DOCROOT => 'DOCROOT',
+ * );
+ *
+ * [!] EXAMPLE #2 (for a semi-universal approach)
+ *
+ * $_kintSettings['appRootDirs'] = array(
+ *      realpath( __DIR__ . '/../../..' ) => 'ROOT', // go up as many levels as needed in the realpath() param
+ * );
+ *
+ * $_kintSettings['fileLinkFormat'] = 'http://localhost:8091/?message=%f:%l';
+ *
+ */
+$_kintSettings['appRootDirs'] = isset( $_SERVER['DOCUMENT_ROOT'] )
+	? array( $_SERVER['DOCUMENT_ROOT'] => '&lt;ROOT&gt;' )
+	: array();
+
+
+/** @var int max length of string before it is truncated and displayed separately in full. Zero or false to disable */
+$_kintSettings['maxStrLength'] = 80;
+
+/** @var array possible alternative char encodings in order of probability, eg. array('windows-1251') */
+$_kintSettings['charEncodings'] = array(
+	'UTF-8',
+	'Windows-1252', # Western; includes iso-8859-1, replace this with windows-1251 if you have Russian code
+	'euc-jp',       # Japanese
+
+	# all other charsets cannot be differentiated by PHP and/or are not supported by mb_* functions,
+	# I need a better means of detecting the codeset, no idea how though :(
+
+	//		'iso-8859-13',  # Baltic
+	//		'windows-1251', # Cyrillic
+	//		'windows-1250', # Central European
+	//		'shift_jis',    # Japanese
+	//		'iso-2022-jp',  # Japanese
+);
+
+
+/** @var int max array/object levels to go deep, if zero no limits are applied */
+$_kintSettings['maxLevels'] = 7;
+
+
+/** @var string name of theme for rich view */
+$_kintSettings['theme'] = 'original';
+
+
+/** @var bool enable detection when Kint is command line. Formats output with whitespace only; does not HTML-escape it */
+$_kintSettings['cliDetection'] = true;
+
+/** @var bool in addition to above setting, enable detection when Kint is run in *UNIX* command line.
+ * Attempts to add coloring, but if seen as plain text, the color information is visible as gibberish
+ */
+$_kintSettings['cliColors'] = true;
+
+
+unset( $_kintSettings );

+ 335 - 0
sites/all/modules/contrib/dev/devel/kint/kint/decorators/plain.php

@@ -0,0 +1,335 @@
+<?php
+
+class Kint_Decorators_Plain
+{
+	private static $_enableColors;
+
+	private static $_cliEffects      = array(
+		# effects
+		'bold'             => '1', 'dark' => '2',
+		'italic'           => '3', 'underline' => '4',
+		'blink'            => '5', 'reverse' => '7',
+		'concealed'        => '8', 'default' => '39',
+
+		# colors
+		'black'            => '30', 'red' => '31',
+		'green'            => '32', 'yellow' => '33',
+		'blue'             => '34', 'magenta' => '35',
+		'cyan'             => '36', 'light_gray' => '37',
+		'dark_gray'        => '90', 'light_red' => '91',
+		'light_green'      => '92', 'light_yellow' => '93',
+		'light_blue'       => '94', 'light_magenta' => '95',
+		'light_cyan'       => '96', 'white' => '97',
+
+		# backgrounds
+		'bg_default'       => '49', 'bg_black' => '40',
+		'bg_red'           => '41', 'bg_green' => '42',
+		'bg_yellow'        => '43', 'bg_blue' => '44',
+		'bg_magenta'       => '45', 'bg_cyan' => '46',
+		'bg_light_gray'    => '47', 'bg_dark_gray' => '100',
+		'bg_light_red'     => '101', 'bg_light_green' => '102',
+		'bg_light_yellow'  => '103', 'bg_light_blue' => '104',
+		'bg_light_magenta' => '105', 'bg_light_cyan' => '106',
+		'bg_white'         => '107',
+	);
+	private static $_utfSymbols      = array(
+		'┌', '═', '┐',
+		'│',
+		'└', '─', '┘',
+	);
+	private static $_winShellSymbols = array(
+		"\xda", "\xdc", "\xbf",
+		"\xb3",
+		"\xc0", "\xc4", "\xd9",
+	);
+	private static $_htmlSymbols     = array(
+		"&#9484;", "&#9604;", "&#9488;",
+		"&#9474;",
+		"&#9492;", "&#9472;", "&#9496;",
+	);
+
+	public static function decorate( kintVariableData $kintVar, $level = 0 )
+	{
+		$output = '';
+		if ( $level === 0 ) {
+			$name          = $kintVar->name ? $kintVar->name : 'literal';
+			$kintVar->name = null;
+
+			$output .= self::_title( $name );
+		}
+
+
+		$space = str_repeat( $s = '    ', $level );
+		$output .= $space . self::_drawHeader( $kintVar );
+
+
+		if ( $kintVar->extendedValue !== null ) {
+			$output .= ' ' . ( $kintVar->type === 'array' ? '[' : '(' ) . PHP_EOL;
+
+
+			if ( is_array( $kintVar->extendedValue ) ) {
+				foreach ( $kintVar->extendedValue as $v ) {
+					$output .= self::decorate( $v, $level + 1 );
+				}
+			} elseif ( is_string( $kintVar->extendedValue ) ) {
+				$output .= $space . $s . $kintVar->extendedValue . PHP_EOL; # depth too great or similar
+			} else {
+				$output .= self::decorate( $kintVar->extendedValue, $level + 1 ); //it's kintVariableData
+			}
+			$output .= $space . ( $kintVar->type === 'array' ? ']' : ')' ) . PHP_EOL;
+		} else {
+			$output .= PHP_EOL;
+		}
+
+		return $output;
+	}
+
+	public static function decorateTrace( $traceData )
+	{
+		$output   = self::_title( 'TRACE' );
+		$lastStep = count( $traceData );
+		foreach ( $traceData as $stepNo => $step ) {
+			$title = str_pad( ++$stepNo . ': ', 4, ' ' );
+
+			$title .= self::_colorize(
+				( isset( $step['file'] ) ? self::_buildCalleeString( $step ) : 'PHP internal call' ),
+				'title'
+			);
+
+			if ( !empty( $step['function'] ) ) {
+				$title .= '    ' . $step['function'];
+				if ( isset( $step['args'] ) ) {
+					$title .= '(';
+					if ( empty( $step['args'] ) ) {
+						$title .= ')';
+					} else {
+					}
+					$title .= PHP_EOL;
+				}
+			}
+
+			$output .= $title;
+
+			if ( !empty( $step['args'] ) ) {
+				$appendDollar = $step['function'] === '{closure}' ? '' : '$';
+
+				$i = 0;
+				foreach ( $step['args'] as $name => $argument ) {
+					$argument           = kintParser::factory(
+						$argument,
+						$name ? $appendDollar . $name : '#' . ++$i
+					);
+					$argument->operator = $name ? ' =' : ':';
+					$maxLevels          = Kint::$maxLevels;
+					if ( $maxLevels ) {
+						Kint::$maxLevels = $maxLevels + 2;
+					}
+					$output .= self::decorate( $argument, 2 );
+					if ( $maxLevels ) {
+						Kint::$maxLevels = $maxLevels;
+					}
+				}
+				$output .= '    )' . PHP_EOL;
+			}
+
+			if ( !empty( $step['object'] ) ) {
+				$output .= self::_colorize(
+					'    ' . self::_char( '─', 27 ) . ' Callee object ' . self::_char( '─', 34 ),
+					'title'
+				);
+
+				$maxLevels = Kint::$maxLevels;
+				if ( $maxLevels ) {
+					# in cli the terminal window is filled too quickly to display huge objects
+					Kint::$maxLevels = Kint::enabled() === Kint::MODE_CLI
+						? 1
+						: $maxLevels + 1;
+				}
+				$output .= self::decorate( kintParser::factory( $step['object'] ), 1 );
+				if ( $maxLevels ) {
+					Kint::$maxLevels = $maxLevels;
+				}
+			}
+
+			if ( $stepNo !== $lastStep ) {
+				$output .= self::_colorize( self::_char( '─', 80 ), 'title' );
+			}
+		}
+
+		return $output;
+	}
+
+
+	private static function _colorize( $text, $type, $nlAfter = true )
+	{
+		$nlAfter = $nlAfter ? PHP_EOL : '';
+
+		switch ( Kint::enabled() ) {
+			case Kint::MODE_PLAIN:
+				if ( !self::$_enableColors ) return $text . $nlAfter;
+
+				switch ( $type ) {
+					case 'value':
+						$text = "<i>{$text}</i>";
+						break;
+					case 'type':
+						$text = "<b>{$text}</b>";
+						break;
+					case 'title':
+						$text = "<u>{$text}</u>";
+						break;
+				}
+
+				return $text . $nlAfter;
+				break;
+			case Kint::MODE_CLI:
+				if ( !self::$_enableColors ) return $text . $nlAfter;
+
+				$optionsMap = array(
+					'title' => "\x1b[36m", # cyan
+					'type'  => "\x1b[35;1m", # magenta bold
+					'value' => "\x1b[32m", # green
+				);
+
+				return $optionsMap[ $type ] . $text . "\x1b[0m" . $nlAfter;
+				break;
+			case Kint::MODE_WHITESPACE:
+			default:
+				return $text . $nlAfter;
+				break;
+		}
+	}
+
+
+	private static function _char( $char, $repeat = null )
+	{
+		switch ( Kint::enabled() ) {
+			case Kint::MODE_PLAIN:
+				$char = self::$_htmlSymbols[ array_search( $char, self::$_utfSymbols, true ) ];
+				break;
+			case Kint::MODE_CLI:
+				$inWindowsShell = PHP_SAPI === 'cli' && DIRECTORY_SEPARATOR !== '/';
+				if ( $inWindowsShell ) {
+					$char = self::$_winShellSymbols[ array_search( $char, self::$_utfSymbols, true ) ];
+				}
+				break;
+			case Kint::MODE_WHITESPACE:
+			default:
+				break;
+		}
+
+		return $repeat ? str_repeat( $char, $repeat ) : $char;
+	}
+
+	private static function _title( $text )
+	{
+		$escaped          = kintParser::escape( $text );
+		$lengthDifference = strlen( $escaped ) - strlen( $text );
+		return
+			self::_colorize(
+				self::_char( '┌' ) . self::_char( '─', 78 ) . self::_char( '┐' ) . PHP_EOL
+				. self::_char( '│' ),
+				'title',
+				false
+			)
+
+			. self::_colorize( str_pad( $escaped, 78 + $lengthDifference, ' ', STR_PAD_BOTH ), 'title', false )
+
+			. self::_colorize( self::_char( '│' ) . PHP_EOL
+				. self::_char( '└' ) . self::_char( '─', 78 ) . self::_char( '┘' ),
+				'title'
+			);
+	}
+
+	public static function wrapStart()
+	{
+		if ( Kint::enabled() === Kint::MODE_PLAIN ) {
+			return '<pre class="-kint">';
+		}
+		return '';
+	}
+
+	public static function wrapEnd( $callee, $miniTrace, $prevCaller )
+	{
+		$lastLine = self::_colorize( self::_char( "═", 80 ), 'title' );
+		$lastChar = Kint::enabled() === Kint::MODE_PLAIN ? '</pre>' : '';
+
+
+		if ( !Kint::$displayCalledFrom ) return $lastLine . $lastChar;
+
+
+		return $lastLine . self::_colorize( 'Called from ' . self::_buildCalleeString( $callee ), 'title' ) . $lastChar;
+	}
+
+
+	private static function _drawHeader( kintVariableData $kintVar )
+	{
+		$output = '';
+
+		if ( $kintVar->access ) {
+			$output .= ' ' . $kintVar->access;
+		}
+
+		if ( $kintVar->name !== null && $kintVar->name !== '' ) {
+			$output .= ' ' . kintParser::escape( $kintVar->name );
+		}
+
+		if ( $kintVar->operator ) {
+			$output .= ' ' . $kintVar->operator;
+		}
+
+		$output .= ' ' . self::_colorize( $kintVar->type, 'type', false );
+
+		if ( $kintVar->size !== null ) {
+			$output .= ' (' . $kintVar->size . ')';
+		}
+
+
+		if ( $kintVar->value !== null && $kintVar->value !== '' ) {
+			$output .= ' ' . self::_colorize(
+					$kintVar->value, # escape shell
+					'value',
+					false
+				);
+		}
+
+		return ltrim( $output );
+	}
+
+	private static function _buildCalleeString( $callee )
+	{
+		if ( Kint::enabled() === Kint::MODE_CLI ) { // todo win/nix
+			return "+{$callee['line']} {$callee['file']}";
+		}
+
+		$url           = Kint::getIdeLink( $callee['file'], $callee['line'] );
+		$shortenedName = Kint::shortenPath( $callee['file'] ) . ':' . $callee['line'];
+
+		if ( Kint::enabled() === Kint::MODE_PLAIN ) {
+			if ( strpos( $url, 'http://' ) === 0 ) {
+				$calleeInfo = "<a href=\"#\"onclick=\""
+					. "X=new XMLHttpRequest;"
+					. "X.open('GET','{$url}');"
+					. "X.send();"
+					. "return!1\">{$shortenedName}</a>";
+			} else {
+				$calleeInfo = "<a href=\"{$url}\">{$shortenedName}</a>";
+			}
+		} else {
+			$calleeInfo = $shortenedName;
+		}
+
+		return $calleeInfo;
+	}
+
+	public static function init()
+	{
+		self::$_enableColors =
+			Kint::$cliColors
+			&& ( DIRECTORY_SEPARATOR === '/' || getenv( 'ANSICON' ) !== false || getenv( 'ConEmuANSI' ) === 'ON' );
+
+		return Kint::enabled() === Kint::MODE_PLAIN
+			? '<style>.-kint i{color:#d00;font-style:normal}.-kint u{color:#030;text-decoration:none;font-weight:bold}</style>'
+			: '';
+	}
+}

+ 319 - 0
sites/all/modules/contrib/dev/devel/kint/kint/decorators/rich.php

@@ -0,0 +1,319 @@
+<?php
+
+class Kint_Decorators_Rich
+{
+	# make calls to Kint::dump() from different places in source coloured differently.
+	private static $_usedColors = array();
+
+	public static function decorate( kintVariableData $kintVar )
+	{
+		$output = '<dl>';
+
+		$extendedPresent = $kintVar->extendedValue !== null || $kintVar->_alternatives !== null;
+
+		if ( $extendedPresent ) {
+			$class = 'kint-parent';
+			if ( Kint::$expandedByDefault ) {
+				$class .= ' kint-show';
+			}
+			$output .= '<dt class="' . $class . '">';
+		} else {
+			$output .= '<dt>';
+		}
+
+		if ( $extendedPresent ) {
+			$output .= '<span class="kint-popup-trigger" title="Open in new window">&rarr;</span><nav></nav>';
+		}
+
+		$output .= self::_drawHeader( $kintVar ) . $kintVar->value . '</dt>';
+
+
+		if ( $extendedPresent ) {
+			$output .= '<dd>';
+		}
+
+		if ( isset( $kintVar->extendedValue ) ) {
+
+			if ( is_array( $kintVar->extendedValue ) ) {
+				foreach ( $kintVar->extendedValue as $v ) {
+					$output .= self::decorate( $v );
+				}
+			} elseif ( is_string( $kintVar->extendedValue ) ) {
+				$output .= '<pre>' . $kintVar->extendedValue . '</pre>';
+			} else {
+				$output .= self::decorate( $kintVar->extendedValue ); //it's kint's container
+			}
+
+		} elseif ( isset( $kintVar->_alternatives ) ) {
+			$output .= "<ul class=\"kint-tabs\">";
+
+			foreach ( $kintVar->_alternatives as $k => $var ) {
+				$active = $k === 0 ? ' class="kint-active-tab"' : '';
+				$output .= "<li{$active}>" . self::_drawHeader( $var, false ) . '</li>';
+			}
+
+			$output .= "</ul><ul>";
+
+			foreach ( $kintVar->_alternatives as $var ) {
+				$output .= "<li>";
+
+				$var = $var->value;
+
+				if ( is_array( $var ) ) {
+					foreach ( $var as $v ) {
+						$output .= is_string( $v )
+							? '<pre>' . $v . '</pre>'
+							: self::decorate( $v );
+					}
+				} elseif ( is_string( $var ) ) {
+					$output .= '<pre>' . $var . '</pre>';
+				} elseif ( isset( $var ) ) {
+					throw new Exception(
+						'Kint has encountered an error, '
+						. 'please paste this report to https://github.com/raveren/kint/issues<br>'
+						. 'Error encountered at ' . basename( __FILE__ ) . ':' . __LINE__ . '<br>'
+						. ' variables: '
+						. htmlspecialchars( var_export( $kintVar->_alternatives, true ), ENT_QUOTES )
+					);
+				}
+
+				$output .= "</li>";
+			}
+
+			$output .= "</ul>";
+		}
+		if ( $extendedPresent ) {
+			$output .= '</dd>';
+		}
+
+		$output .= '</dl>';
+
+		return $output;
+	}
+
+	public static function decorateTrace( $traceData )
+	{
+		$output = '<dl class="kint-trace">';
+
+		foreach ( $traceData as $i => $step ) {
+			$class = 'kint-parent';
+			if ( Kint::$expandedByDefault ) {
+				$class .= ' kint-show';
+			}
+
+			$output .= '<dt class="' . $class . '">'
+				. '<b>' . ( $i + 1 ) . '</b> '
+				. '<nav></nav>'
+				. '<var>';
+
+			if ( isset( $step['file'] ) ) {
+				$output .= self::_ideLink( $step['file'], $step['line'] );
+			} else {
+				$output .= 'PHP internal call';
+			}
+
+			$output .= '</var>';
+
+			$output .= $step['function'];
+
+			if ( isset( $step['args'] ) ) {
+				$output .= '(' . implode( ', ', array_keys( $step['args'] ) ) . ')';
+			}
+			$output .= '</dt><dd>';
+			$firstTab = ' class="kint-active-tab"';
+			$output .= '<ul class="kint-tabs">';
+
+			if ( !empty( $step['source'] ) ) {
+				$output .= "<li{$firstTab}>Source</li>";
+				$firstTab = '';
+			}
+
+			if ( !empty( $step['args'] ) ) {
+				$output .= "<li{$firstTab}>Arguments</li>";
+				$firstTab = '';
+			}
+
+			if ( !empty( $step['object'] ) ) {
+				kintParser::reset();
+				$calleeDump = kintParser::factory( $step['object'] );
+
+				$output .= "<li{$firstTab}>Callee object [{$calleeDump->type}]</li>";
+			}
+
+
+			$output .= '</ul><ul>';
+
+
+			if ( !empty( $step['source'] ) ) {
+				$output .= "<li><pre class=\"kint-source\">{$step['source']}</pre></li>";
+			}
+
+			if ( !empty( $step['args'] ) ) {
+				$output .= "<li>";
+				foreach ( $step['args'] as $k => $arg ) {
+					kintParser::reset();
+					$output .= self::decorate( kintParser::factory( $arg, $k ) );
+				}
+				$output .= "</li>";
+			}
+			if ( !empty( $step['object'] ) ) {
+				$output .= "<li>" . self::decorate( $calleeDump ) . "</li>";
+			}
+
+			$output .= '</ul></dd>';
+		}
+		$output .= '</dl>';
+
+		return $output;
+	}
+
+
+	/**
+	 * called for each dump, opens the html tag
+	 *
+	 * @param array $callee caller information taken from debug backtrace
+	 *
+	 * @return string
+	 */
+	public static function wrapStart()
+	{
+		return "<div class=\"kint\">";
+	}
+
+
+	/**
+	 * closes Kint::_wrapStart() started html tags and displays callee information
+	 *
+	 * @param array $callee caller information taken from debug backtrace
+	 * @param array $miniTrace full path to kint call
+	 * @param array $prevCaller previous caller information taken from debug backtrace
+	 *
+	 * @return string
+	 */
+	public static function wrapEnd( $callee, $miniTrace, $prevCaller )
+	{
+		if ( !Kint::$displayCalledFrom ) {
+			return '</div>';
+		}
+
+		$callingFunction = '';
+		$calleeInfo      = '';
+		$traceDisplay    = '';
+		if ( isset( $prevCaller['class'] ) ) {
+			$callingFunction = $prevCaller['class'];
+		}
+		if ( isset( $prevCaller['type'] ) ) {
+			$callingFunction .= $prevCaller['type'];
+		}
+		if ( isset( $prevCaller['function'] )
+			&& !in_array( $prevCaller['function'], array( 'include', 'include_once', 'require', 'require_once' ) )
+		) {
+			$callingFunction .= $prevCaller['function'] . '()';
+		}
+		$callingFunction and $callingFunction = " [{$callingFunction}]";
+
+
+		if ( isset( $callee['file'] ) ) {
+			$calleeInfo .= 'Called from ' . self::_ideLink( $callee['file'], $callee['line'] );
+		}
+
+		if ( !empty( $miniTrace ) ) {
+			$traceDisplay = '<ol>';
+			foreach ( $miniTrace as $step ) {
+				$traceDisplay .= '<li>' . self::_ideLink( $step['file'], $step['line'] ); // closing tag not required
+				if ( isset( $step['function'] )
+					&& !in_array( $step['function'], array( 'include', 'include_once', 'require', 'require_once' ) )
+				) {
+					$classString = ' [';
+					if ( isset( $step['class'] ) ) {
+						$classString .= $step['class'];
+					}
+					if ( isset( $step['type'] ) ) {
+						$classString .= $step['type'];
+					}
+					$classString .= $step['function'] . '()]';
+					$traceDisplay .= $classString;
+				}
+			}
+			$traceDisplay .= '</ol>';
+
+			$calleeInfo = '<nav></nav>' . $calleeInfo;
+		}
+
+
+		return "<footer>"
+		. '<span class="kint-popup-trigger" title="Open in new window">&rarr;</span> '
+		. "{$calleeInfo}{$callingFunction}{$traceDisplay}"
+		. "</footer></div>";
+	}
+
+
+	private static function _drawHeader( kintVariableData $kintVar, $verbose = true )
+	{
+		$output = '';
+		if ( $verbose ) {
+			if ( $kintVar->access !== null ) {
+				$output .= "<var>" . $kintVar->access . "</var> ";
+			}
+
+			if ( $kintVar->name !== null && $kintVar->name !== '' ) {
+				$output .= "<dfn>" . kintParser::escape( $kintVar->name ) . "</dfn> ";
+			}
+
+			if ( $kintVar->operator !== null ) {
+				$output .= $kintVar->operator . " ";
+			}
+		}
+
+		if ( $kintVar->type !== null ) {
+			if ( $verbose ) {
+				$output .= "<var>";
+			}
+
+			$output .= $kintVar->type;
+
+			if ( $verbose ) {
+				$output .= "</var>";
+			} else {
+				$output .= " ";
+			}
+		}
+
+
+		if ( $kintVar->size !== null ) {
+			$output .= "(" . $kintVar->size . ") ";
+		}
+
+		return $output;
+	}
+
+	private static function _ideLink( $file, $line )
+	{
+		$shortenedPath = Kint::shortenPath( $file );
+		if ( !Kint::$fileLinkFormat ) return $shortenedPath . ':' . $line;
+
+		$ideLink = Kint::getIdeLink( $file, $line );
+		$class   = ( strpos( $ideLink, 'http://' ) === 0 ) ? 'class="kint-ide-link" ' : '';
+		return "<a {$class}href=\"{$ideLink}\">{$shortenedPath}:{$line}</a>";
+	}
+
+
+	/**
+	 * produces css and js required for display. May be called multiple times, will only produce output once per
+	 * pageload or until `-` or `@` modifier is used
+	 *
+	 * @return string
+	 */
+	public static function init()
+	{
+		$baseDir = KINT_DIR . 'view/compiled/';
+
+		if ( !is_readable( $cssFile = $baseDir . Kint::$theme . '.css' ) ) {
+			$cssFile = $baseDir . 'original.css';
+		}
+
+		return
+			'<script class="-kint-js">' . file_get_contents( $baseDir . 'kint.js' ) . '</script>'
+			. '<style class="-kint-css">' . file_get_contents( $cssFile ) . "</style>\n";
+	}
+}

+ 176 - 0
sites/all/modules/contrib/dev/devel/kint/kint/examples/overview.php

@@ -0,0 +1,176 @@
+<?php
+require( '../Kint.class.php' );
+
+$selectedTheme = isset( $_GET['theme'] ) ? $_GET['theme'] : 'original';
+$allowedThemes = array();
+$dh            = opendir( '../view/compiled' );
+while ( ( $filename = readdir( $dh ) ) !== false ) {
+	if ( strpos( $filename, '.css' ) !== false ) {
+		$allowedThemes[] = str_replace( '.css', '', $filename );
+	}
+}
+
+sort( $allowedThemes );
+
+if ( in_array( $selectedTheme, $allowedThemes ) ) {
+	Kint::$theme = $selectedTheme;
+}
+
+class BaseUser
+{
+	/**
+	 * @return string
+	 */
+	public function getFullName() { }
+}
+
+class User extends BaseUser
+{
+	CONST DEFAULT_PATH    = 'some/default/path';
+	CONST ROLE_DISALLOWED = 1;
+	CONST ROLE_ALLOWED    = 2;
+	CONST ROLE_FORBIDDEN  = 3;
+
+	public  $additionalData;
+	private $username = 'demo_username';
+	private $password = 'demo_password';
+	private $createdDate;
+
+	public function __construct() { }
+
+	/**
+	 * Check is user is equal to another user
+	 */
+	public function isEqualTo( BaseUser $user ) { }
+
+	/**
+	 * Get data from this demo class
+	 *
+	 * @param string $username
+	 *
+	 * @return array
+	 */
+	public function setUsername( $username ) { }
+
+	/**
+	 * Set additional data
+	 *
+	 * @array $data
+	 */
+	public function setAdditionalData( array $data ) { $this->additionalData = $data; }
+
+	/**
+	 * @return \DateTime date object
+	 */
+	public function getCreatedDate() { }
+
+	/**
+	 * @param \DateTime $date
+	 */
+	public function setCreatedDate( DateTime $date ) { $this->createdDate = $date; }
+
+	/**
+	 * Dummy method that triggers trace
+	 */
+	public function ensure() { Kint::trace(); }
+}
+
+class UserManager
+{
+	private $user;
+
+	/**
+	 * Get user from manager
+	 */
+	public function getUser() { return $this->user; }
+
+	/**
+	 * Debug specific user
+	 *
+	 * @param \User $user
+	 */
+	public function debugUser( $user )
+	{
+		$this->user = $user;
+		d( $this->getUser() );
+	}
+
+	/**
+	 * Ensure user (triggers ensure() method on \User object that trace)
+	 *
+	 * @void
+	 */
+	public function ensureUser() { $this->user->ensure(); }
+}
+
+$user = new User;
+$user->setAdditionalData( array(
+		'last_login'             => new DateTime(),
+		'current_unix_timestamp' => time(),
+		'random_rgb_color_code'  => '#FF9900',
+		'impressions'            => 60,
+		'nickname'               => 'Someuser',
+	)
+);
+$user->setCreatedDate( new DateTime( '2013-10-10' ) );
+$userManager = new UserManager();
+
+for ( $i = 1; $i < 6; $i++ ) {
+	$tabularData[] = array(
+		'date'        => "2013-01-0{$i}",
+		'allowed'     => $i % 3 == 0,
+		'action'      => "action {$i}",
+		'clicks'      => rand( 100, 50000 ),
+		'impressions' => rand( 10000, 500000 ),
+	);
+
+	if ( $i % 2 == 0 ) {
+		unset( $tabularData[ $i - 1 ]['clicks'] );
+	}
+}
+
+$nestedArray = array();
+
+for ( $i = 1; $i < 6; $i++ ) {
+	$nestedArray["user group {$i}"] = array(
+		"user {$i}" => array(
+			'name'    => "Name {$i}",
+			'surname' => "Surname {$i}"
+		),
+
+		'data'      => array(
+			'conversions' => rand( 100, 5000 ),
+			'spent'       => array( 'currency' => 'EUR', 'amount' => rand( 10000, 500000 ) )
+		),
+	);
+}
+?>
+<html>
+<head>
+	<title>Kint PHP debugging tool - overview</title>
+</head>
+<body>
+<div>
+	<label style="float: right">Switch theme:
+		<select onchange="window.location = '?theme=' + this.value">
+			<?php $chosen = isset( $_GET['theme'] ) ? $_GET['theme'] : 'original' ?>
+			<?php foreach ( $allowedThemes as $theme ) : ?>
+				<option value="<?php echo $theme ?>"<?php echo $theme === $chosen ? ' selected' : '' ?>>
+					<?php echo ucfirst( str_replace( '-', ' ', $theme ) ) ?>
+				</option>
+			<?php endforeach ?>
+		</select>
+	</label>
+
+	<h2>Kint PHP debugging tool - overview</h2>
+</div>
+<h3>Debug variables</h3>
+<?php
+$userManager->debugUser( $user );
+d( $userManager, $tabularData );
+d( $nestedArray );
+?>
+<h3>Trace</h3>
+<?php $userManager->ensureUser(); ?>
+</body>
+</html>

+ 19 - 0
sites/all/modules/contrib/dev/devel/kint/kint/inc/kintObject.class.php

@@ -0,0 +1,19 @@
+<?php
+
+abstract class KintObject
+{
+	/** @var string type of variable, can be set in inherited object or in static::parse() method */
+	public $name = 'NOT SET';
+
+	/** @var string quick variable value displayed inline */
+	public $value;
+
+	/**
+	 * returns false or associative array - each key represents a tab in default view, values may be anything
+	 *
+	 * @param $variable
+	 *
+	 * @return mixed
+	 */
+	abstract public function parse( & $variable );
+}

+ 608 - 0
sites/all/modules/contrib/dev/devel/kint/kint/inc/kintParser.class.php

@@ -0,0 +1,608 @@
+<?php
+
+abstract class kintParser extends kintVariableData
+{
+	private static $_level = 0;
+	private static $_customDataTypes;
+	private static $_objectParsers;
+	private static $_objects;
+	private static $_marker;
+
+	private static $_skipAlternatives = false;
+
+	private static $_placeFullStringInValue = false;
+
+
+	private static function _init()
+	{
+		$fh = opendir( KINT_DIR . 'parsers/custom/' );
+		while ( $fileName = readdir( $fh ) ) {
+			if ( substr( $fileName, -4 ) !== '.php' ) continue;
+
+			require KINT_DIR . 'parsers/custom/' . $fileName;
+			self::$_customDataTypes[] = substr( $fileName, 0, -4 );
+		}
+		$fh = opendir( KINT_DIR . 'parsers/objects/' );
+		while ( $fileName = readdir( $fh ) ) {
+			if ( substr( $fileName, -4 ) !== '.php' ) continue;
+
+			require KINT_DIR . 'parsers/objects/' . $fileName;
+			self::$_objectParsers[] = substr( $fileName, 0, -4 );
+		}
+	}
+
+	public static function reset()
+	{
+		self::$_level   = 0;
+		self::$_objects = self::$_marker = null;
+	}
+
+	/**
+	 * main and usually single method a custom parser must implement
+	 *
+	 * @param mixed $variable
+	 *
+	 * @return mixed [!!!] false is returned if the variable is not of current type
+	 */
+	abstract protected function _parse( & $variable );
+
+
+	/**
+	 * the only public entry point to return a parsed representation of a variable
+	 *
+	 * @static
+	 *
+	 * @param      $variable
+	 * @param null $name
+	 *
+	 * @throws Exception
+	 * @return \kintParser
+	 */
+	public final static function factory( & $variable, $name = null )
+	{
+		isset( self::$_customDataTypes ) or self::_init();
+
+		# save internal data to revert after dumping to properly handle recursions etc
+		$revert = array(
+			'level'   => self::$_level,
+			'objects' => self::$_objects,
+		);
+
+		self::$_level++;
+
+		$varData       = new kintVariableData;
+		$varData->name = $name;
+
+		# first parse the variable based on its type
+		$varType = gettype( $variable );
+		$varType === 'unknown type' and $varType = 'unknown'; # PHP 5.4 inconsistency
+		$methodName = '_parse_' . $varType;
+
+		# objects can be presented in a different way altogether, INSTEAD, not ALONGSIDE the generic parser
+		if ( $varType === 'object' ) {
+			foreach ( self::$_objectParsers as $parserClass ) {
+				$className = 'Kint_Objects_' . $parserClass;
+
+				/** @var $object KintObject */
+				$object = new $className;
+				if ( ( $alternativeTabs = $object->parse( $variable ) ) !== false ) {
+					self::$_skipAlternatives   = true;
+					$alternativeDisplay        = new kintVariableData;
+					$alternativeDisplay->type  = $object->name;
+					$alternativeDisplay->value = $object->value;
+					$alternativeDisplay->name  = $name;
+
+					foreach ( $alternativeTabs as $name => $values ) {
+						$alternative       = kintParser::factory( $values );
+						$alternative->type = $name;
+						if ( Kint::enabled() === Kint::MODE_RICH ) {
+							empty( $alternative->value ) and $alternative->value = $alternative->extendedValue;
+							$alternativeDisplay->_alternatives[] = $alternative;
+						} else {
+							$alternativeDisplay->extendedValue[] = $alternative;
+						}
+					}
+
+					self::$_skipAlternatives = false;
+					self::$_level   = $revert['level'];
+					self::$_objects = $revert['objects'];
+					return $alternativeDisplay;
+				}
+			}
+		}
+
+		# base type parser returning false means "stop processing further": e.g. recursion
+		if ( self::$methodName( $variable, $varData ) === false ) {
+			self::$_level--;
+			return $varData;
+		}
+
+		if ( Kint::enabled() === Kint::MODE_RICH && !self::$_skipAlternatives ) {
+			# if an alternative returns something that can be represented in an alternative way, don't :)
+			self::$_skipAlternatives = true;
+
+			# now check whether the variable can be represented in a different way
+			foreach ( self::$_customDataTypes as $parserClass ) {
+				$className = 'Kint_Parsers_' . $parserClass;
+
+				/** @var $parser kintParser */
+				$parser       = new $className;
+				$parser->name = $name; # the parser may overwrite the name value, so set it first
+
+				if ( $parser->_parse( $variable ) !== false ) {
+					$varData->_alternatives[] = $parser;
+				}
+			}
+
+
+			# if alternatives exist, push extendedValue to their front and display it as one of alternatives
+			if ( !empty( $varData->_alternatives ) && isset( $varData->extendedValue ) ) {
+				$_ = new kintVariableData;
+
+				$_->value = $varData->extendedValue;
+				$_->type  = 'contents';
+				$_->size  = null;
+
+				array_unshift( $varData->_alternatives, $_ );
+				$varData->extendedValue = null;
+			}
+
+			self::$_skipAlternatives = false;
+		}
+
+		self::$_level   = $revert['level'];
+		self::$_objects = $revert['objects'];
+
+		if ( strlen( $varData->name ) > 80 ) {
+			$varData->name =
+				self::_substr( $varData->name, 0, 37 )
+				. '...'
+				. self::_substr( $varData->name, -38, null );
+		}
+		return $varData;
+	}
+
+	private static function _checkDepth()
+	{
+		return Kint::$maxLevels != 0 && self::$_level >= Kint::$maxLevels;
+	}
+
+	private static function _isArrayTabular( array $variable )
+	{
+		if ( Kint::enabled() !== Kint::MODE_RICH ) return false;
+
+		$arrayKeys   = array();
+		$keys        = null;
+		$closeEnough = false;
+		foreach ( $variable as $row ) {
+			if ( !is_array( $row ) || empty( $row ) ) return false;
+
+			foreach ( $row as $col ) {
+				if ( !empty( $col ) && !is_scalar( $col ) ) return false; // todo add tabular "tolerance"
+			}
+
+			if ( isset( $keys ) && !$closeEnough ) {
+				# let's just see if the first two rows have same keys, that's faster and has the
+				# positive side effect of easily spotting missing keys in later rows
+				if ( $keys !== array_keys( $row ) ) return false;
+
+				$closeEnough = true;
+			} else {
+				$keys = array_keys( $row );
+			}
+
+			$arrayKeys = array_unique( array_merge( $arrayKeys, $keys ) );
+		}
+
+		return $arrayKeys;
+	}
+
+	private static function _decorateCell( kintVariableData $kintVar )
+	{
+		if ( $kintVar->extendedValue !== null || !empty( $kintVar->_alternatives ) ) {
+			return '<td>' . Kint_Decorators_Rich::decorate( $kintVar ) . '</td>';
+		}
+
+		$output = '<td';
+
+		if ( $kintVar->value !== null ) {
+			$output .= ' title="' . $kintVar->type;
+
+			if ( $kintVar->size !== null ) {
+				$output .= " (" . $kintVar->size . ")";
+			}
+
+			$output .= '">' . $kintVar->value;
+		} else {
+			$output .= '>';
+
+			if ( $kintVar->type !== 'NULL' ) {
+				$output .= '<u>' . $kintVar->type;
+
+				if ( $kintVar->size !== null ) {
+					$output .= "(" . $kintVar->size . ")";
+				}
+
+				$output .= '</u>';
+			} else {
+				$output .= '<u>NULL</u>';
+			}
+		}
+
+
+		return $output . '</td>';
+	}
+
+
+	public static function escape( $value, $encoding = null )
+	{
+		if ( empty( $value ) ) return $value;
+
+		if ( Kint::enabled() === Kint::MODE_CLI ) {
+			$value = str_replace( "\x1b", "\\x1b", $value );
+		}
+
+		if ( Kint::enabled() === Kint::MODE_CLI || Kint::enabled() === Kint::MODE_WHITESPACE ) return $value;
+
+		$encoding or $encoding = self::_detectEncoding( $value );
+		$value = htmlspecialchars( $value, ENT_NOQUOTES, $encoding === 'ASCII' ? 'UTF-8' : $encoding );
+
+
+		if ( $encoding === 'UTF-8' ) {
+			// todo we could make the symbols hover-title show the code for the invisible symbol
+			# when possible force invisible characters to have some sort of display (experimental)
+			$value = preg_replace( '/[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\x9F]/u', '?', $value );
+		}
+
+		# this call converts all non-ASCII characters into html chars of format
+		if ( function_exists( 'mb_encode_numericentity' ) ) {
+			$value = mb_encode_numericentity(
+				$value,
+				array( 0x80, 0xffff, 0, 0xffff, ),
+				$encoding
+			);
+		}
+
+		return $value;
+	}
+
+
+	private static $_dealingWithGlobals = false;
+
+	private static function _parse_array( &$variable, kintVariableData $variableData )
+	{
+		isset( self::$_marker ) or self::$_marker = "\x00" . uniqid();
+
+		# naturally, $GLOBALS variable is an intertwined recursion nightmare, use black magic
+		$globalsDetector = false;
+		if ( array_key_exists( 'GLOBALS', $variable ) && is_array( $variable['GLOBALS'] ) ) {
+			$globalsDetector = "\x01" . uniqid();
+
+			$variable['GLOBALS'][ $globalsDetector ] = true;
+			if ( isset( $variable[ $globalsDetector ] ) ) {
+				unset( $variable[ $globalsDetector ] );
+				self::$_dealingWithGlobals = true;
+			} else {
+				unset( $variable['GLOBALS'][ $globalsDetector ] );
+				$globalsDetector = false;
+			}
+		}
+
+		$variableData->type = 'array';
+		$variableData->size = count( $variable );
+
+		if ( $variableData->size === 0 ) {
+			return;
+		}
+		if ( isset( $variable[ self::$_marker ] ) ) { # recursion; todo mayhaps show from where
+			if ( self::$_dealingWithGlobals ) {
+				$variableData->value = '*RECURSION*';
+			} else {
+				unset( $variable[ self::$_marker ] );
+				$variableData->value = self::$_marker;
+			}
+			return false;
+		}
+		if ( self::_checkDepth() ) {
+			$variableData->extendedValue = "*DEPTH TOO GREAT*";
+			return false;
+		}
+
+		$isSequential = self::_isSequential( $variable );
+
+		if ( $variableData->size > 1 && ( $arrayKeys = self::_isArrayTabular( $variable ) ) !== false ) {
+			$variable[ self::$_marker ] = true; # this must be AFTER _isArrayTabular
+			$firstRow                   = true;
+			$extendedValue              = '<table class="kint-report"><thead>';
+
+			foreach ( $variable as $rowIndex => & $row ) {
+				# display strings in their full length
+				self::$_placeFullStringInValue = true;
+
+				if ( $rowIndex === self::$_marker ) continue;
+
+				if ( isset( $row[ self::$_marker ] ) ) {
+					$variableData->value = "*RECURSION*";
+					return false;
+				}
+
+
+				$extendedValue .= '<tr>';
+				if ( $isSequential ) {
+					$output = '<td>' . '#' . ( $rowIndex + 1 )  . '</td>';
+				} else {
+					$output = self::_decorateCell( kintParser::factory( $rowIndex ) );
+				}
+				if ( $firstRow ) {
+					$extendedValue .= '<th>&nbsp;</th>';
+				}
+
+				# we iterate the known full set of keys from all rows in case some appeared at later rows,
+				# as we only check the first two to assume
+				foreach ( $arrayKeys as $key ) {
+					if ( $firstRow ) {
+						$extendedValue .= '<th>' . self::escape( $key ) . '</th>';
+					}
+
+					if ( !array_key_exists( $key, $row ) ) {
+						$output .= '<td class="kint-empty"></td>';
+						continue;
+					}
+
+					$var = kintParser::factory( $row[ $key ] );
+
+					if ( $var->value === self::$_marker ) {
+						$variableData->value = '*RECURSION*';
+						return false;
+					} elseif ( $var->value === '*RECURSION*' ) {
+						$output .= '<td class="kint-empty"><u>*RECURSION*</u></td>';
+					} else {
+						$output .= self::_decorateCell( $var );
+					}
+					unset( $var );
+				}
+
+				if ( $firstRow ) {
+					$extendedValue .= '</tr></thead><tr>';
+					$firstRow = false;
+				}
+
+				$extendedValue .= $output . '</tr>';
+			}
+			self::$_placeFullStringInValue = false;
+
+			$variableData->extendedValue = $extendedValue . '</table>';
+
+		} else {
+			$variable[ self::$_marker ] = true;
+			$extendedValue              = array();
+
+			foreach ( $variable as $key => & $val ) {
+				if ( $key === self::$_marker ) continue;
+
+				$output = kintParser::factory( $val );
+				if ( $output->value === self::$_marker ) {
+					$variableData->value = "*RECURSION*"; // recursion occurred on a higher level, thus $this is recursion
+					return false;
+				}
+				if ( !$isSequential ) {
+					$output->operator = '=>';
+				}
+				$output->name    = $isSequential ? null : "'" . $key . "'";
+				$extendedValue[] = $output;
+			}
+			$variableData->extendedValue = $extendedValue;
+		}
+
+		if ( $globalsDetector ) {
+			self::$_dealingWithGlobals = false;
+		}
+
+		unset( $variable[ self::$_marker ] );
+	}
+
+
+	private static function _parse_object( &$variable, kintVariableData $variableData )
+	{
+		if ( function_exists( 'spl_object_hash' ) ) {
+			$hash = spl_object_hash( $variable );
+		} else {
+			ob_start();
+			var_dump( $variable );
+			preg_match( '[#(\d+)]', ob_get_clean(), $match );
+			$hash = $match[1];
+		}
+
+		$castedArray        = (array) $variable;
+		$variableData->type = get_class( $variable );
+		$variableData->size = count( $castedArray );
+
+		if ( isset( self::$_objects[ $hash ] ) ) {
+			$variableData->value = '*RECURSION*';
+			return false;
+		}
+		if ( self::_checkDepth() ) {
+			$variableData->extendedValue = "*DEPTH TOO GREAT*";
+			return false;
+		}
+
+
+		# ArrayObject (and maybe ArrayIterator, did not try yet) unsurprisingly consist of mainly dark magic.
+		# What bothers me most, var_dump sees no problem with it, and ArrayObject also uses a custom,
+		# undocumented serialize function, so you can see the properties in internal functions, but
+		# can never iterate some of them if the flags are not STD_PROP_LIST. Fun stuff.
+		if ( $variableData->type === 'ArrayObject' || is_subclass_of( $variable, 'ArrayObject' ) ) {
+			$arrayObjectFlags = $variable->getFlags();
+			$variable->setFlags( ArrayObject::STD_PROP_LIST );
+		}
+
+		self::$_objects[ $hash ] = true; // todo store reflectorObject here for alternatives cache
+		$reflector               = new ReflectionObject( $variable );
+
+		# add link to definition of userland objects
+		if ( Kint::enabled() === Kint::MODE_RICH && Kint::$fileLinkFormat && $reflector->isUserDefined() ) {
+			$url = Kint::getIdeLink( $reflector->getFileName(), $reflector->getStartLine() );
+
+			$class              = ( strpos( $url, 'http://' ) === 0 ) ? 'class="kint-ide-link" ' : '';
+			$variableData->type = "<a {$class}href=\"{$url}\">{$variableData->type}</a>";
+		}
+		$variableData->size = 0;
+
+		$extendedValue = array();
+		$encountered   = array();
+
+		# copy the object as an array as it provides more info than Reflection (depends)
+		foreach ( $castedArray as $key => $value ) {
+			/* casting object to array:
+			 * integer properties are inaccessible;
+			 * private variables have the class name prepended to the variable name;
+			 * protected variables have a '*' prepended to the variable name.
+			 * These prepended values have null bytes on either side.
+			 * http://www.php.net/manual/en/language.types.array.php#language.types.array.casting
+			 */
+			if ( $key{0} === "\x00" ) {
+
+				$access = $key{1} === "*" ? "protected" : "private";
+
+				// Remove the access level from the variable name
+				$key = substr( $key, strrpos( $key, "\x00" ) + 1 );
+			} else {
+				$access = "public";
+			}
+
+			$encountered[ $key ] = true;
+
+			$output           = kintParser::factory( $value, self::escape( $key ) );
+			$output->access   = $access;
+			$output->operator = '->';
+			$extendedValue[]  = $output;
+			$variableData->size++;
+		}
+
+		foreach ( $reflector->getProperties() as $property ) {
+			$name = $property->name;
+			if ( $property->isStatic() || isset( $encountered[ $name ] ) ) continue;
+
+			if ( $property->isProtected() ) {
+				$property->setAccessible( true );
+				$access = "protected";
+			} elseif ( $property->isPrivate() ) {
+				$property->setAccessible( true );
+				$access = "private";
+			} else {
+				$access = "public";
+			}
+
+			$value = $property->getValue( $variable );
+
+			$output           = kintParser::factory( $value, self::escape( $name ) );
+			$output->access   = $access;
+			$output->operator = '->';
+			$extendedValue[]  = $output;
+			$variableData->size++;
+		}
+
+		if ( isset( $arrayObjectFlags ) ) {
+			$variable->setFlags( $arrayObjectFlags );
+		}
+
+		if ( $variableData->size ) {
+			$variableData->extendedValue = $extendedValue;
+		}
+	}
+
+
+	private static function _parse_boolean( &$variable, kintVariableData $variableData )
+	{
+		$variableData->type  = 'bool';
+		$variableData->value = $variable ? 'TRUE' : 'FALSE';
+	}
+
+	private static function _parse_double( &$variable, kintVariableData $variableData )
+	{
+		$variableData->type  = 'float';
+		$variableData->value = $variable;
+	}
+
+	private static function _parse_integer( &$variable, kintVariableData $variableData )
+	{
+		$variableData->type  = 'integer';
+		$variableData->value = $variable;
+	}
+
+	private static function _parse_null( &$variable, kintVariableData $variableData )
+	{
+		$variableData->type = 'NULL';
+	}
+
+	private static function _parse_resource( &$variable, kintVariableData $variableData )
+	{
+		$resourceType       = get_resource_type( $variable );
+		$variableData->type = "resource ({$resourceType})";
+
+		if ( $resourceType === 'stream' && $meta = stream_get_meta_data( $variable ) ) {
+
+			if ( isset( $meta['uri'] ) ) {
+				$file = $meta['uri'];
+
+				if ( function_exists( 'stream_is_local' ) ) {
+					// Only exists on PHP >= 5.2.4
+					if ( stream_is_local( $file ) ) {
+						$file = Kint::shortenPath( $file );
+					}
+				}
+
+				$variableData->value = $file;
+			}
+		}
+	}
+
+	private static function _parse_string( &$variable, kintVariableData $variableData )
+	{
+		$variableData->type = 'string';
+
+		$encoding = self::_detectEncoding( $variable );
+		if ( $encoding !== 'ASCII' ) {
+			$variableData->type .= ' ' . $encoding;
+		}
+
+
+		$variableData->size = self::_strlen( $variable, $encoding );
+		if ( Kint::enabled() !== Kint::MODE_RICH ) {
+			$variableData->value = '"' . self::escape( $variable, $encoding ) . '"';
+			return;
+		}
+
+
+		if ( !self::$_placeFullStringInValue ) {
+
+			$strippedString = preg_replace( '[\s+]', ' ', $variable );
+			if ( Kint::$maxStrLength && $variableData->size > Kint::$maxStrLength ) {
+
+				// encode and truncate
+				$variableData->value         = '"'
+					. self::escape( self::_substr( $strippedString, 0, Kint::$maxStrLength, $encoding ), $encoding )
+					. '&hellip;"';
+				$variableData->extendedValue = self::escape( $variable, $encoding );
+
+				return;
+			} elseif ( $variable !== $strippedString ) { // omit no data from display
+
+				$variableData->value         = '"' . self::escape( $variable, $encoding ) . '"';
+				$variableData->extendedValue = self::escape( $variable, $encoding );
+
+				return;
+			}
+		}
+
+		$variableData->value = '"' . self::escape( $variable, $encoding ) . '"';
+	}
+
+	private static function _parse_unknown( &$variable, kintVariableData $variableData )
+	{
+		$type                = gettype( $variable );
+		$variableData->type  = "UNKNOWN" . ( !empty( $type ) ? " ({$type})" : '' );
+		$variableData->value = var_export( $variable, true );
+	}
+
+}

+ 102 - 0
sites/all/modules/contrib/dev/devel/kint/kint/inc/kintVariableData.class.php

@@ -0,0 +1,102 @@
+<?php
+
+class kintVariableData
+{
+	/** @var string */
+	public $type;
+	/** @var string */
+	public $access;
+	/** @var string */
+	public $name;
+	/** @var string */
+	public $operator;
+	/** @var int */
+	public $size;
+	/**
+	 * @var kintVariableData[] array of kintVariableData objects or strings; displayed collapsed, each element from
+	 * the array is a separate possible representation of the dumped var
+	 */
+	public $extendedValue;
+	/** @var string inline value */
+	public $value;
+
+	/** @var kintVariableData[] array of alternative representations for same variable, don't use in custom parsers */
+	public $_alternatives;
+
+	/* *******************************************
+	 * HELPERS
+	 */
+
+	private static $_supportedCharsets = array(
+		'UTF-8',
+		'Windows-1252', # Western; includes iso-8859-1
+		'euc-jp',       # Japanese
+
+		# all other charsets cannot be differentiated by PHP and/or are not supported by mb_* functions,
+		# I need a better means of detecting the codeset, no idea how though :(
+
+		//		'iso-8859-13',  # Baltic
+		//		'windows-1251', # Cyrillic
+		//		'windows-1250', # Central European
+		//		'shift_jis',    # Japanese
+		//		'iso-2022-jp',  # Japanese
+	);
+
+	protected static function _detectEncoding( $value )
+	{
+		$ret = null;
+		if ( function_exists( 'mb_detect_encoding' ) ) {
+			$mbDetected = mb_detect_encoding( $value );
+			if ( $mbDetected === 'ASCII' ) return 'ASCII';
+		}
+
+
+		if ( !function_exists( 'iconv' ) ) {
+			return !empty( $mbDetected ) ? $mbDetected : 'UTF-8';
+		}
+
+		$md5 = md5( $value );
+		foreach ( Kint::$charEncodings as $encoding ) {
+			# fuck knows why, //IGNORE and //TRANSLIT still throw notice
+			if ( md5( @iconv( $encoding, $encoding, $value ) ) === $md5 ) {
+				return $encoding;
+			}
+		}
+
+		return 'ASCII';
+	}
+
+	/**
+	 * returns whether the array:
+	 *  1) is numeric and
+	 *  2) in sequence starting from zero
+	 *
+	 * @param array $array
+	 *
+	 * @return bool
+	 */
+	protected static function _isSequential( array $array )
+	{
+		return array_keys( $array ) === range( 0, count( $array ) - 1 );
+	}
+
+	protected static function _strlen( $string, $encoding = null )
+	{
+		if ( function_exists( 'mb_strlen' ) ) {
+			$encoding or $encoding = self::_detectEncoding( $string );
+			return mb_strlen( $string, $encoding );
+		} else {
+			return strlen( $string );
+		}
+	}
+
+	protected static function _substr( $string, $start, $end, $encoding = null )
+	{
+		if ( function_exists( 'mb_substr' ) ) {
+			$encoding or $encoding = self::_detectEncoding( $string );
+			return mb_substr( $string, $start, $end, $encoding );
+		} else {
+			return substr( $string, $start, $end );
+		}
+	}
+}

+ 150 - 0
sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/classmethods.php

@@ -0,0 +1,150 @@
+<?php
+
+class Kint_Parsers_ClassMethods extends kintParser
+{
+	private static $cache = array();
+
+	protected function _parse( &$variable )
+	{
+		if ( !KINT_PHP53 || !is_object( $variable ) ) return false;
+
+		$className = get_class( $variable );
+
+		# assuming class definition will not change inside one request
+		if ( !isset( self::$cache[ $className ] ) ) {
+			$reflection = new ReflectionClass( $variable );
+
+			$public = $private = $protected = array();
+
+			// Class methods
+			foreach ( $reflection->getMethods() as $method ) {
+				$params = array();
+
+				// Access type
+				$access = implode( ' ', Reflection::getModifierNames( $method->getModifiers() ) );
+
+				// Method parameters
+				foreach ( $method->getParameters() as $param ) {
+					$paramString = '';
+
+					if ( $param->isArray() ) {
+						$paramString .= 'array ';
+					} else {
+						try {
+							if ( $paramClassName = $param->getClass() ) {
+								$paramString .= $paramClassName->name . ' ';
+							}
+						} catch ( ReflectionException $e ) {
+							preg_match( '/\[\s\<\w+?>\s([\w]+)/s', $param->__toString(), $matches );
+							$paramClassName = isset( $matches[1] ) ? $matches[1] : '';
+
+							$paramString .= ' UNDEFINED CLASS (' . $paramClassName . ') ';
+						}
+					}
+
+					$paramString .= ( $param->isPassedByReference() ? '&' : '' ) . '$' . $param->getName();
+
+					if ( $param->isDefaultValueAvailable() ) {
+						if ( is_array( $param->getDefaultValue() ) ) {
+							$arrayValues = array();
+							foreach ( $param->getDefaultValue() as $key => $value ) {
+								$arrayValues[] = $key . ' => ' . $value;
+							}
+
+							$defaultValue = 'array(' . implode( ', ', $arrayValues ) . ')';
+						} elseif ( $param->getDefaultValue() === null ) {
+							$defaultValue = 'NULL';
+						} elseif ( $param->getDefaultValue() === false ) {
+							$defaultValue = 'false';
+						} elseif ( $param->getDefaultValue() === true ) {
+							$defaultValue = 'true';
+						} elseif ( $param->getDefaultValue() === '' ) {
+							$defaultValue = '""';
+						} else {
+							$defaultValue = $param->getDefaultValue();
+						}
+
+						$paramString .= ' = ' . $defaultValue;
+					}
+
+					$params[] = $paramString;
+				}
+
+				$output = new kintVariableData;
+
+				// Simple DocBlock parser, look for @return
+				if ( ( $docBlock = $method->getDocComment() ) ) {
+					$matches = array();
+					if ( preg_match_all( '/@(\w+)\s+(.*)\r?\n/m', $docBlock, $matches ) ) {
+						$lines = array_combine( $matches[1], $matches[2] );
+						if ( isset( $lines['return'] ) ) {
+							$output->operator = '->';
+							# since we're outputting code, assumption that the string is utf8 is most likely correct
+							# and saves resources
+							$output->type = self::escape( $lines['return'], 'UTF-8' );
+						}
+					}
+				}
+
+				$output->name   = ( $method->returnsReference() ? '&' : '' ) . $method->getName() . '('
+					. implode( ', ', $params ) . ')';
+				$output->access = $access;
+
+				if ( is_string( $docBlock ) ) {
+					$lines = array();
+					foreach ( explode( "\n", $docBlock ) as $line ) {
+						$line = trim( $line );
+
+						if ( in_array( $line, array( '/**', '/*', '*/' ) ) ) {
+							continue;
+						} elseif ( strpos( $line, '*' ) === 0 ) {
+							$line = substr( $line, 1 );
+						}
+
+						$lines[] = self::escape( trim( $line ), 'UTF-8' );
+					}
+
+					$output->extendedValue = implode( "\n", $lines ) . "\n\n";
+				}
+
+				$declaringClass     = $method->getDeclaringClass();
+				$declaringClassName = $declaringClass->getName();
+
+				if ( $declaringClassName !== $className ) {
+					$output->extendedValue .= "<small>Inherited from <i>{$declaringClassName}</i></small>\n";
+				}
+
+				$fileName = Kint::shortenPath( $method->getFileName() ) . ':' . $method->getStartLine();
+				$output->extendedValue .= "<small>Defined in {$fileName}</small>";
+
+				$sortName = $access . $method->getName();
+
+				if ( $method->isPrivate() ) {
+					$private[ $sortName ] = $output;
+				} elseif ( $method->isProtected() ) {
+					$protected[ $sortName ] = $output;
+				} else {
+					$public[ $sortName ] = $output;
+				}
+			}
+
+			if ( !$private && !$protected && !$public ) {
+				self::$cache[ $className ] = false;
+			}
+
+			ksort( $public );
+			ksort( $protected );
+			ksort( $private );
+
+			self::$cache[ $className ] = $public + $protected + $private;
+		}
+
+		if ( count( self::$cache[ $className ] ) === 0 ) {
+			return false;
+		}
+
+		$this->value = self::$cache[ $className ];
+		$this->type  = 'Available methods';
+		$this->size  = count( self::$cache[ $className ] );
+	}
+}

+ 49 - 0
sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/classstatics.php

@@ -0,0 +1,49 @@
+<?php
+
+class Kint_Parsers_ClassStatics extends kintParser
+{
+	protected function _parse( & $variable )
+	{
+		if ( !KINT_PHP53 || !is_object( $variable ) ) return false;
+
+		$extendedValue = array();
+
+		$reflection = new ReflectionClass( $variable );
+		// first show static values
+		foreach ( $reflection->getProperties( ReflectionProperty::IS_STATIC ) as $property ) {
+			if ( $property->isPrivate() ) {
+				if ( !method_exists( $property, 'setAccessible' ) ) {
+					break;
+				}
+				$property->setAccessible( true );
+				$access = "private";
+			} elseif ( $property->isProtected() ) {
+				$property->setAccessible( true );
+				$access = "protected";
+			} else {
+				$access = 'public';
+			}
+
+			$_      = $property->getValue();
+			$output = kintParser::factory( $_, '$' . $property->getName() );
+
+			$output->access   = $access;
+			$output->operator = '::';
+			$extendedValue[]  = $output;
+		}
+
+		foreach ( $reflection->getConstants() as $constant => $val ) {
+			$output = kintParser::factory( $val, $constant );
+
+			$output->access   = 'constant';
+			$output->operator = '::';
+			$extendedValue[]  = $output;
+		}
+
+		if ( empty( $extendedValue ) ) return false;
+
+		$this->value = $extendedValue;
+		$this->type  = 'Static class properties';
+		$this->size  = count( $extendedValue );
+	}
+}

+ 400 - 0
sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/color.php

@@ -0,0 +1,400 @@
+<?php
+class Kint_Parsers_Color extends kintParser
+{
+	private static $_css3Named = array(
+		'aliceblue'=>'#f0f8ff','antiquewhite'=>'#faebd7','aqua'=>'#00ffff','aquamarine'=>'#7fffd4','azure'=>'#f0ffff',
+		'beige'=>'#f5f5dc','bisque'=>'#ffe4c4','black'=>'#000000','blanchedalmond'=>'#ffebcd','blue'=>'#0000ff',
+		'blueviolet'=>'#8a2be2','brown'=>'#a52a2a','burlywood'=>'#deb887','cadetblue'=>'#5f9ea0','chartreuse'=>'#7fff00',
+		'chocolate'=>'#d2691e','coral'=>'#ff7f50','cornflowerblue'=>'#6495ed','cornsilk'=>'#fff8dc','crimson'=>'#dc143c',
+		'cyan'=>'#00ffff','darkblue'=>'#00008b','darkcyan'=>'#008b8b','darkgoldenrod'=>'#b8860b','darkgray'=>'#a9a9a9',
+		'darkgrey'=>'#a9a9a9','darkgreen'=>'#006400','darkkhaki'=>'#bdb76b','darkmagenta'=>'#8b008b',
+		'darkolivegreen'=>'#556b2f','darkorange'=>'#ff8c00','darkorchid'=>'#9932cc','darkred'=>'#8b0000',
+		'darksalmon'=>'#e9967a','darkseagreen'=>'#8fbc8f','darkslateblue'=>'#483d8b','darkslategray'=>'#2f4f4f',
+		'darkslategrey'=>'#2f4f4f','darkturquoise'=>'#00ced1','darkviolet'=>'#9400d3','deeppink'=>'#ff1493',
+		'deepskyblue'=>'#00bfff','dimgray'=>'#696969','dimgrey'=>'#696969','dodgerblue'=>'#1e90ff',
+		'firebrick'=>'#b22222','floralwhite'=>'#fffaf0','forestgreen'=>'#228b22','fuchsia'=>'#ff00ff',
+		'gainsboro'=>'#dcdcdc','ghostwhite'=>'#f8f8ff','gold'=>'#ffd700','goldenrod'=>'#daa520','gray'=>'#808080',
+		'grey'=>'#808080','green'=>'#008000','greenyellow'=>'#adff2f','honeydew'=>'#f0fff0','hotpink'=>'#ff69b4',
+		'indianred'=>'#cd5c5c','indigo'=>'#4b0082','ivory'=>'#fffff0','khaki'=>'#f0e68c','lavender'=>'#e6e6fa',
+		'lavenderblush'=>'#fff0f5','lawngreen'=>'#7cfc00','lemonchiffon'=>'#fffacd','lightblue'=>'#add8e6',
+		'lightcoral'=>'#f08080','lightcyan'=>'#e0ffff','lightgoldenrodyellow'=>'#fafad2','lightgray'=>'#d3d3d3',
+		'lightgrey'=>'#d3d3d3','lightgreen'=>'#90ee90','lightpink'=>'#ffb6c1','lightsalmon'=>'#ffa07a',
+		'lightseagreen'=>'#20b2aa','lightskyblue'=>'#87cefa','lightslategray'=>'#778899','lightslategrey'=>'#778899',
+		'lightsteelblue'=>'#b0c4de','lightyellow'=>'#ffffe0','lime'=>'#00ff00','limegreen'=>'#32cd32','linen'=>'#faf0e6',
+		'magenta'=>'#ff00ff','maroon'=>'#800000','mediumaquamarine'=>'#66cdaa','mediumblue'=>'#0000cd',
+		'mediumorchid'=>'#ba55d3','mediumpurple'=>'#9370d8','mediumseagreen'=>'#3cb371','mediumslateblue'=>'#7b68ee',
+		'mediumspringgreen'=>'#00fa9a','mediumturquoise'=>'#48d1cc','mediumvioletred'=>'#c71585',
+		'midnightblue'=>'#191970','mintcream'=>'#f5fffa','mistyrose'=>'#ffe4e1','moccasin'=>'#ffe4b5',
+		'navajowhite'=>'#ffdead','navy'=>'#000080','oldlace'=>'#fdf5e6','olive'=>'#808000','olivedrab'=>'#6b8e23',
+		'orange'=>'#ffa500','orangered'=>'#ff4500','orchid'=>'#da70d6','palegoldenrod'=>'#eee8aa','palegreen'=>'#98fb98',
+		'paleturquoise'=>'#afeeee','palevioletred'=>'#d87093','papayawhip'=>'#ffefd5','peachpuff'=>'#ffdab9',
+		'peru'=>'#cd853f','pink'=>'#ffc0cb','plum'=>'#dda0dd','powderblue'=>'#b0e0e6','purple'=>'#800080',
+		'red'=>'#ff0000','rosybrown'=>'#bc8f8f','royalblue'=>'#4169e1','saddlebrown'=>'#8b4513','salmon'=>'#fa8072',
+		'sandybrown'=>'#f4a460','seagreen'=>'#2e8b57','seashell'=>'#fff5ee','sienna'=>'#a0522d','silver'=>'#c0c0c0',
+		'skyblue'=>'#87ceeb','slateblue'=>'#6a5acd','slategray'=>'#708090','slategrey'=>'#708090','snow'=>'#fffafa',
+		'springgreen'=>'#00ff7f','steelblue'=>'#4682b4','tan'=>'#d2b48c','teal'=>'#008080','thistle'=>'#d8bfd8',
+		'tomato'=>'#ff6347','turquoise'=>'#40e0d0','violet'=>'#ee82ee','wheat'=>'#f5deb3','white'=>'#ffffff',
+		'whitesmoke'=>'#f5f5f5','yellow'=>'#ffff00','yellowgreen'=>'#9acd32'
+	);
+
+
+	protected function _parse( & $variable )
+	{
+		if ( !self::_fits( $variable ) ) return false;
+
+		$this->type  = 'CSS color';
+		$variants    = self::_convert( $variable );
+		$this->value =
+			"<div style=\"background:{$variable}\" class=\"kint-color-preview\">{$variable}</div>"
+			. "<strong>hex :</strong> {$variants['hex']}\n"
+			. "<strong>rgb :</strong> {$variants['rgb']}\n"
+			. ( isset( $variants['name'] ) ? "<strong>name:</strong> {$variants['name']}\n" : '' )
+			. "<strong>hsl :</strong> {$variants['hsl']}";
+	}
+
+
+	private static function _fits( $variable )
+	{
+		if ( !is_string( $variable ) ) return false;
+
+		$var = strtolower( trim( $variable ) );
+
+		return isset( self::$_css3Named[$var] )
+			|| preg_match(
+				'/^(?:#[0-9A-Fa-f]{3}|#[0-9A-Fa-f]{6}|(?:rgb|hsl)a?\s*\((?:\s*[0-9.%]+\s*,?){3,4}\))$/',
+				$var
+			);
+	}
+
+	private static function _convert( $color )
+	{
+		$color         = strtolower( $color );
+		$decimalColors = array();
+		$variants      = array(
+			'hex'  => null,
+			'rgb'  => null,
+			'name' => null,
+			'hsl'  => null,
+		);
+
+		if ( isset( self::$_css3Named[ $color ] ) ) {
+			$variants['name'] = $color;
+			$color            = self::$_css3Named[ $color ];
+		}
+
+		if ( $color{0} === '#' ) {
+			$variants['hex'] = $color;
+			$color           = substr( $color, 1 );
+			if ( strlen( $color ) === 6 ) {
+				$colors = str_split( $color, 2 );
+			} else {
+				$colors = array(
+					$color{0} . $color{0},
+					$color{1} . $color{1},
+					$color{2} . $color{2},
+				);
+			}
+
+			$decimalColors = array_map( 'hexdec', $colors );
+		} elseif ( substr( $color, 0, 3 ) === 'rgb' ) {
+			$variants['rgb'] = $color;
+			preg_match_all( '#([0-9.%]+)#', $color, $matches );
+			$decimalColors = $matches[1];
+			foreach ( $decimalColors as &$color ) {
+				if ( strpos( $color, '%' ) !== false ) {
+					$color = str_replace( '%', '', $color ) * 2.55;
+				}
+			}
+
+
+		} elseif ( substr( $color, 0, 3 ) === 'hsl' ) {
+			$variants['hsl'] = $color;
+			preg_match_all( '#([0-9.%]+)#', $color, $matches );
+
+			$colors = $matches[1];
+			$colors[0] /= 360;
+			$colors[1] = str_replace( '%', '', $colors[1] ) / 100;
+			$colors[2] = str_replace( '%', '', $colors[2] ) / 100;
+
+			$decimalColors = self::_HSLtoRGB( $colors );
+			if ( isset( $colors[3] ) ) {
+				$decimalColors[] = $colors[3];
+			}
+		}
+
+		if ( isset( $decimalColors[3] ) ) {
+			$alpha = $decimalColors[3];
+			unset( $decimalColors[3] );
+		} else {
+			$alpha = null;
+		}
+		foreach ( $variants as $type => &$variant ) {
+			if ( isset( $variant ) ) continue;
+
+			switch ( $type ) {
+				case 'hex':
+					$variant = '#';
+					foreach ( $decimalColors as &$color ) {
+						$variant .= str_pad( dechex( $color ), 2, "0", STR_PAD_LEFT );
+					}
+					$variant .= isset( $alpha ) ? ' (alpha omitted)' : '';
+					break;
+				case 'rgb':
+					$rgb = $decimalColors;
+					if ( isset( $alpha ) ) {
+						$rgb[] = $alpha;
+						$a     = 'a';
+					} else {
+						$a = '';
+					}
+					$variant = "rgb{$a}( " . implode( ', ', $rgb ) . " )";
+					break;
+				case 'hsl':
+					$rgb = self::_RGBtoHSL( $decimalColors );
+					if ( $rgb === null ) {
+						unset( $variants[ $type ] );
+						break;
+					}
+					if ( isset( $alpha ) ) {
+						$rgb[] = $alpha;
+						$a     = 'a';
+					} else {
+						$a = '';
+					}
+
+					$variant = "hsl{$a}( " . implode( ', ', $rgb ) . " )";
+					break;
+				case 'name':
+					// [!] name in initial variants array must go after hex
+					if ( ( $key = array_search( $variants['hex'], self::$_css3Named, true ) ) !== false ) {
+						$variant = $key;
+					} else {
+						unset( $variants[ $type ] );
+					}
+					break;
+			}
+
+		}
+
+		return $variants;
+	}
+
+
+	private static function _HSLtoRGB( array $hsl )
+	{
+		list( $h, $s, $l ) = $hsl;
+		$m2 = ( $l <= 0.5 ) ? $l * ( $s + 1 ) : $l + $s - $l * $s;
+		$m1 = $l * 2 - $m2;
+		return array(
+			round( self::_hue2rgb( $m1, $m2, $h + 0.33333 ) * 255 ),
+			round( self::_hue2rgb( $m1, $m2, $h ) * 255 ),
+			round( self::_hue2rgb( $m1, $m2, $h - 0.33333 ) * 255 ),
+		);
+	}
+
+
+	/**
+	 * Helper function for _color_hsl2rgb().
+	 */
+	private static function _hue2rgb( $m1, $m2, $h )
+	{
+		$h = ( $h < 0 ) ? $h + 1 : ( ( $h > 1 ) ? $h - 1 : $h );
+		if ( $h * 6 < 1 ) return $m1 + ( $m2 - $m1 ) * $h * 6;
+		if ( $h * 2 < 1 ) return $m2;
+		if ( $h * 3 < 2 ) return $m1 + ( $m2 - $m1 ) * ( 0.66666 - $h ) * 6;
+		return $m1;
+	}
+
+
+	private static function _RGBtoHSL( array $rgb )
+	{
+		list( $clrR, $clrG, $clrB ) = $rgb;
+
+		$clrMin   = min( $clrR, $clrG, $clrB );
+		$clrMax   = max( $clrR, $clrG, $clrB );
+		$deltaMax = $clrMax - $clrMin;
+
+		$L = ( $clrMax + $clrMin ) / 510;
+
+		if ( 0 == $deltaMax ) {
+			$H = 0;
+			$S = 0;
+		} else {
+			if ( 0.5 > $L ) {
+				$S = $deltaMax / ( $clrMax + $clrMin );
+			} else {
+				$S = $deltaMax / ( 510 - $clrMax - $clrMin );
+			}
+
+			if ( $clrMax == $clrR ) {
+				$H = ( $clrG - $clrB ) / ( 6.0 * $deltaMax );
+			} else if ( $clrMax == $clrG ) {
+				$H = 1 / 3 + ( $clrB - $clrR ) / ( 6.0 * $deltaMax );
+			} else {
+				$H = 2 / 3 + ( $clrR - $clrG ) / ( 6.0 * $deltaMax );
+			}
+
+			if ( 0 > $H ) $H += 1;
+			if ( 1 < $H ) $H -= 1;
+		}
+		return array(
+			round( $H * 360 ),
+			round( $S * 100 ) . '%',
+			round( $L * 100 ) . '%'
+		);
+
+	}
+}
+
+/* *************
+ * TEST DATA
+ *
+dd(array(
+'hsl(0,  100%,50%)',
+'hsl(30, 100%,50%)',
+'hsl(60, 100%,50%)',
+'hsl(90, 100%,50%)',
+'hsl(120,100%,50%)',
+'hsl(150,100%,50%)',
+'hsl(180,100%,50%)',
+'hsl(210,100%,50%)',
+'hsl(240,100%,50%)',
+'hsl(270,100%,50%)',
+'hsl(300,100%,50%)',
+'hsl(330,100%,50%)',
+'hsl(360,100%,50%)',
+'hsl(120,100%,25%)',
+'hsl(120,100%,50%)',
+'hsl(120,100%,75%)',
+'hsl(120,100%,50%)',
+'hsl(120, 67%,50%)',
+'hsl(120, 33%,50%)',
+'hsl(120,  0%,50%)',
+'hsl(120, 60%,70%)',
+'#f03',
+'#F03',
+'#ff0033',
+'#FF0033',
+'rgb(255,0,51)',
+'rgb(255, 0, 51)',
+'rgb(100%,0%,20%)',
+'rgb(100%, 0%, 20%)',
+'hsla(240,100%,50%,0.05)',
+'hsla(240,100%,50%, 0.4)',
+'hsla(240,100%,50%, 0.7)',
+'hsla(240,100%,50%,   1)',
+'rgba(255,0,0,0.1)',
+'rgba(255,0,0,0.4)',
+'rgba(255,0,0,0.7)',
+'rgba(255,0,0,  1)',
+'black',
+'silver',
+'gray',
+'white',
+'maroon',
+'red',
+'purple',
+'fuchsia',
+'green',
+'lime',
+'olive',
+'yellow',
+'navy',
+'blue',
+'teal',
+'aqua',
+'orange',
+'aliceblue',
+'antiquewhite',
+'aquamarine',
+'azure',
+'beige',
+'bisque',
+'blanchedalmond',
+'blueviolet',
+'brown',
+'burlywood',
+'cadetblue',
+'chartreuse',
+'chocolate',
+'coral',
+'cornflowerblue',
+'cornsilk',
+'crimson',
+'darkblue',
+'darkcyan',
+'darkgoldenrod',
+'darkgray',
+'darkgreen',
+'darkgrey',
+'darkkhaki',
+'darkmagenta',
+'darkolivegreen',
+'darkorange',
+'darkorchid',
+'darkred',
+'darksalmon',
+'darkseagreen',
+'darkslateblue',
+'darkslategray',
+'darkslategrey',
+'darkturquoise',
+'darkviolet',
+'deeppink',
+'deepskyblue',
+'dimgray',
+'dimgrey',
+'dodgerblue',
+'firebrick',
+'floralwhite',
+'forestgreen',
+'gainsboro',
+'ghostwhite',
+'gold',
+'goldenrod',
+'greenyellow',
+'grey',
+'honeydew',
+'hotpink',
+'indianred',
+'indigo',
+'ivory',
+'khaki',
+'lavender',
+'lavenderblush',
+'lawngreen',
+'lemonchiffon',
+'lightblue',
+'lightcoral',
+'lightcyan',
+'lightgoldenrodyellow',
+'lightgray',
+'lightgreen',
+'lightgrey',
+'lightpink',
+'lightsalmon',
+'lightseagreen',
+'lightskyblue',
+'lightslategray',
+'lightslategrey',
+'lightsteelblue',
+'lightyellow',
+'limegreen',
+'linen',
+'mediumaquamarine',
+'mediumblue',
+'mediumorchid',
+'mediumpurple',
+'mediumseagreen',
+'mediumslateblue',
+'mediumspringgreen',
+'mediumturquoise',
+'mediumvioletred',
+'midnightblue',
+'mintcream',
+'mistyrose',
+'moccasin',
+'navajowhite',
+'oldlace',
+'olivedrab',
+));*/

+ 69 - 0
sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/fspath.php

@@ -0,0 +1,69 @@
+<?php
+
+class Kint_Parsers_FsPath extends kintParser
+{
+	protected function _parse( & $variable )
+	{
+		if ( !KINT_PHP53
+			|| !is_string( $variable )
+			|| strlen( $variable ) > 2048
+			|| preg_match( '[[:?<>"*|]]', $variable )
+			|| !@is_readable( $variable ) # f@#! PHP and its random warnings
+		) return false;
+
+		try {
+			$fileInfo = new SplFileInfo( $variable );
+			$flags    = array();
+			$perms    = $fileInfo->getPerms();
+
+			if ( ( $perms & 0xC000 ) === 0xC000 ) {
+				$type    = 'File socket';
+				$flags[] = 's';
+			} elseif ( ( $perms & 0xA000 ) === 0xA000 ) {
+				$type    = 'File symlink';
+				$flags[] = 'l';
+			} elseif ( ( $perms & 0x8000 ) === 0x8000 ) {
+				$type    = 'File';
+				$flags[] = '-';
+			} elseif ( ( $perms & 0x6000 ) === 0x6000 ) {
+				$type    = 'Block special file';
+				$flags[] = 'b';
+			} elseif ( ( $perms & 0x4000 ) === 0x4000 ) {
+				$type    = 'Directory';
+				$flags[] = 'd';
+			} elseif ( ( $perms & 0x2000 ) === 0x2000 ) {
+				$type    = 'Character special file';
+				$flags[] = 'c';
+			} elseif ( ( $perms & 0x1000 ) === 0x1000 ) {
+				$type    = 'FIFO pipe file';
+				$flags[] = 'p';
+			} else {
+				$type    = 'Unknown file';
+				$flags[] = 'u';
+			}
+
+			// owner
+			$flags[] = ( ( $perms & 0x0100 ) ? 'r' : '-' );
+			$flags[] = ( ( $perms & 0x0080 ) ? 'w' : '-' );
+			$flags[] = ( ( $perms & 0x0040 ) ? ( ( $perms & 0x0800 ) ? 's' : 'x' ) : ( ( $perms & 0x0800 ) ? 'S' : '-' ) );
+
+			// group
+			$flags[] = ( ( $perms & 0x0020 ) ? 'r' : '-' );
+			$flags[] = ( ( $perms & 0x0010 ) ? 'w' : '-' );
+			$flags[] = ( ( $perms & 0x0008 ) ? ( ( $perms & 0x0400 ) ? 's' : 'x' ) : ( ( $perms & 0x0400 ) ? 'S' : '-' ) );
+
+			// world
+			$flags[] = ( ( $perms & 0x0004 ) ? 'r' : '-' );
+			$flags[] = ( ( $perms & 0x0002 ) ? 'w' : '-' );
+			$flags[] = ( ( $perms & 0x0001 ) ? ( ( $perms & 0x0200 ) ? 't' : 'x' ) : ( ( $perms & 0x0200 ) ? 'T' : '-' ) );
+
+			$this->type  = $type;
+			$this->size  = sprintf( '%.2fK', $fileInfo->getSize() / 1024 );
+			$this->value = implode( $flags );
+
+		} catch ( Exception $e ) {
+			return false;
+		}
+
+	}
+}

+ 19 - 0
sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/json.php

@@ -0,0 +1,19 @@
+<?php
+
+class Kint_Parsers_Json extends kintParser
+{
+	protected function _parse( & $variable )
+	{
+		if ( !KINT_PHP53
+			|| !is_string( $variable )
+			|| !isset( $variable{0} ) || ( $variable{0} !== '{' && $variable{0} !== '[' )
+			|| ( $json = json_decode( $variable, true ) ) === null
+		) return false;
+
+		$val = (array) $json;
+		if ( empty( $val ) ) return false;
+
+		$this->value = kintParser::factory( $val )->extendedValue;
+		$this->type  = 'JSON';
+	}
+}

+ 60 - 0
sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/microtime.php

@@ -0,0 +1,60 @@
+<?php
+
+class Kint_Parsers_Microtime extends kintParser
+{
+	private static $_times = array();
+	private static $_laps  = array();
+
+	protected function _parse( & $variable )
+	{
+		if ( !is_string( $variable ) || !preg_match( '[0\.[0-9]{8} [0-9]{10}]', $variable ) ) {
+			return false;
+		}
+
+		list( $usec, $sec ) = explode( " ", $variable );
+
+		$time = (float) $usec + (float) $sec;
+		if ( KINT_PHP53 ) {
+			$size = memory_get_usage( true );
+		}
+
+		# '@' is used to prevent the dreaded timezone not set error
+		$this->value = @date( 'Y-m-d H:i:s', $sec ) . '.' . substr( $usec, 2, 4 );
+
+		$numberOfCalls = count( self::$_times );
+		if ( $numberOfCalls > 0 ) { # meh, faster than count($times) > 1
+			$lap           = $time - end( self::$_times );
+			self::$_laps[] = $lap;
+
+			$this->value .= "\n<b>SINCE LAST CALL:</b> <b class=\"kint-microtime\">" . round( $lap, 4 ) . '</b>s.';
+			if ( $numberOfCalls > 1 ) {
+				$this->value .= "\n<b>SINCE START:</b> " . round( $time - self::$_times[0], 4 ) . 's.';
+				$this->value .= "\n<b>AVERAGE DURATION:</b> "
+					. round( array_sum( self::$_laps ) / $numberOfCalls, 4 ) . 's.';
+			}
+		}
+
+		$unit = array( 'B', 'KB', 'MB', 'GB', 'TB' );
+		if ( KINT_PHP53 ) {
+			$this->value .= "\n<b>MEMORY USAGE:</b> " . $size . " bytes ("
+				. round( $size / pow( 1024, ( $i = floor( log( $size, 1024 ) ) ) ), 3 ) . ' ' . $unit[ $i ] . ")";
+		}
+
+		self::$_times[] = $time;
+		$this->type     = 'Stats';
+	}
+
+	/*
+	function test() {
+		d( 'start', microtime() );
+		for ( $i = 0; $i < 10; $i++ ) {
+			d(
+				$duration = mt_rand( 0, 200000 ), // the reported duration will be larger because of Kint overhead
+				usleep( $duration ),
+				microtime()
+	        );
+		}
+		dd(  );
+	}
+	 */
+}

+ 22 - 0
sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/objectiterateable.php

@@ -0,0 +1,22 @@
+<?php
+
+class Kint_Parsers_objectIterateable extends kintParser
+{
+	protected function _parse( & $variable )
+	{
+		if ( !KINT_PHP53
+			|| !is_object( $variable )
+			|| !$variable instanceof Traversable
+			|| stripos( get_class( $variable ), 'zend' ) !== false // zf2 PDO wrapper does not play nice
+		) return false;
+
+
+		$arrayCopy = iterator_to_array( $variable, true );
+
+		if ( $arrayCopy === false ) return false;
+
+		$this->value = kintParser::factory( $arrayCopy )->extendedValue;
+		$this->type  = 'Iterator contents';
+		$this->size  = count( $arrayCopy );
+	}
+}

+ 24 - 0
sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/splobjectstorage.php

@@ -0,0 +1,24 @@
+<?php
+
+class Kint_Parsers_SplObjectStorage extends kintParser
+{
+	protected function _parse( & $variable )
+	{
+		if ( !is_object( $variable ) || !$variable instanceof SplObjectStorage ) return false;
+
+		/** @var $variable SplObjectStorage */
+
+		$count = $variable->count();
+		if ( $count === 0 ) return false;
+
+		$variable->rewind();
+		while ( $variable->valid() ) {
+			$current       = $variable->current();
+			$this->value[] = kintParser::factory( $current );
+			$variable->next();
+		}
+
+		$this->type = 'Storage contents';
+		$this->size = $count;
+	}
+}

+ 29 - 0
sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/timestamp.php

@@ -0,0 +1,29 @@
+<?php
+
+class Kint_Parsers_Timestamp extends kintParser
+{
+	private static function _fits( $variable )
+	{
+		if ( !is_string( $variable ) && !is_int( $variable ) ) return false;
+
+		$len = strlen( (int) $variable );
+		return
+			(
+				$len === 9 || $len === 10 # a little naive
+				|| ( $len === 13 && substr( $variable, -3 ) === '000' ) # also handles javascript micro timestamps
+			)
+			&& ( (string) (int) $variable == $variable );
+	}
+
+
+	protected function _parse( & $variable )
+	{
+		if ( !self::_fits( $variable ) ) return false;
+
+		$var = strlen( $variable ) === 13 ? substr( $variable, 0, -3 ) : $variable;
+
+		$this->type = 'timestamp';
+		# avoid dreaded "Timezone must be set" error
+		$this->value = @date( 'Y-m-d H:i:s', $var );
+	}
+}

+ 25 - 0
sites/all/modules/contrib/dev/devel/kint/kint/parsers/custom/xml.php

@@ -0,0 +1,25 @@
+<?php
+
+class Kint_Parsers_Xml extends kintParser
+{
+	protected function _parse( & $variable )
+	{
+		try {
+			if ( is_string( $variable ) && substr( $variable, 0, 5 ) === '<?xml' ) {
+				$e   = libxml_use_internal_errors( true );
+				$xml = simplexml_load_string( $variable );
+				libxml_use_internal_errors( $e );
+				if ( empty( $xml ) ) {
+					return false;
+				}
+			} else {
+				return false;
+			}
+		} catch ( Exception $e ) {
+			return false;
+		}
+
+		$this->value = kintParser::factory( $xml )->extendedValue;
+		$this->type  = 'XML';
+	}
+}

+ 47 - 0
sites/all/modules/contrib/dev/devel/kint/kint/parsers/objects/closure.php

@@ -0,0 +1,47 @@
+<?php
+
+class Kint_Objects_Closure extends KintObject
+{
+	public function parse( & $variable )
+	{
+		if ( !$variable instanceof Closure ) return false;
+
+		$this->name = 'Closure';
+		$reflection = new ReflectionFunction( $variable );
+		$ret        = array(
+			'Parameters' => array()
+		);
+		if ( $val = $reflection->getParameters() ) {
+			foreach ( $val as $parameter ) {
+				// todo http://php.net/manual/en/class.reflectionparameter.php
+				$ret['Parameters'][] = $parameter->name;
+			}
+
+		}
+		if ( $val = $reflection->getStaticVariables() ) {
+			$ret['Uses'] = $val;
+		}
+		if ( method_exists($reflection, 'getClousureThis') && $val = $reflection->getClosureThis() ) {
+			$ret['Uses']['$this'] = $val;
+		}
+		if ( $val = $reflection->getFileName() ) {
+			$this->value = Kint::shortenPath( $val ) . ':' . $reflection->getStartLine();
+		}
+
+		return $ret;
+	}
+
+
+	public function isDefaultValueAvailable()
+	{
+		if ( PHP_VERSION_ID === 50316 ) { // PHP bug #62988
+			try {
+				$this->getDefaultValue();
+				return true;
+			} catch ( \ReflectionException $e ) {
+				return false;
+			}
+		}
+		return parent::isDefaultValueAvailable();
+	}
+}

+ 35 - 0
sites/all/modules/contrib/dev/devel/kint/kint/parsers/objects/smarty.php

@@ -0,0 +1,35 @@
+<?php
+
+class Kint_Objects_Smarty extends KintObject
+{
+	public function parse( & $variable )
+	{
+		if ( !$variable instanceof Smarty
+			|| !defined( 'Smarty::SMARTY_VERSION' ) # lower than 3.x
+		) return false;
+
+
+		$this->name = 'object Smarty (v' . substr( Smarty::SMARTY_VERSION, 7 ) . ')'; # trim 'Smarty-'
+
+		$assigned = $globalAssigns = array();
+		foreach ( $variable->tpl_vars as $name => $var ) {
+			$assigned[ $name ] = $var->value;
+		}
+		foreach ( Smarty::$global_tpl_vars as $name => $var ) {
+			if ( $name === 'SCRIPT_NAME' ) continue;
+
+			$globalAssigns[ $name ] = $var->value;
+		}
+
+		return array(
+			'Assigned'          => $assigned,
+			'Assigned globally' => $globalAssigns,
+			'Configuration'     => array(
+				'Compiled files stored in' => isset($variable->compile_dir)
+					? $variable->compile_dir
+					: $variable->getCompileDir(),
+			)
+		);
+
+	}
+}

+ 70 - 0
sites/all/modules/contrib/dev/devel/kint/kint/parsers/objects/splfileinfo.php

@@ -0,0 +1,70 @@
+<?php
+
+class Kint_Objects_SplFileInfo extends KintObject
+{
+	public function parse( & $variable )
+	{
+		if ( !KINT_PHP53 || !is_object( $variable ) || !$variable instanceof SplFileInfo ) return false;
+
+		$this->name  = 'SplFileInfo';
+		$this->value = $variable->getBasename();
+
+
+		$flags = array();
+		$perms = $variable->getPerms();
+
+		if ( ( $perms & 0xC000 ) === 0xC000 ) {
+			$type    = 'File socket';
+			$flags[] = 's';
+		} elseif ( ( $perms & 0xA000 ) === 0xA000 ) {
+			$type    = 'File symlink';
+			$flags[] = 'l';
+		} elseif ( ( $perms & 0x8000 ) === 0x8000 ) {
+			$type    = 'File';
+			$flags[] = '-';
+		} elseif ( ( $perms & 0x6000 ) === 0x6000 ) {
+			$type    = 'Block special file';
+			$flags[] = 'b';
+		} elseif ( ( $perms & 0x4000 ) === 0x4000 ) {
+			$type    = 'Directory';
+			$flags[] = 'd';
+		} elseif ( ( $perms & 0x2000 ) === 0x2000 ) {
+			$type    = 'Character special file';
+			$flags[] = 'c';
+		} elseif ( ( $perms & 0x1000 ) === 0x1000 ) {
+			$type    = 'FIFO pipe file';
+			$flags[] = 'p';
+		} else {
+			$type    = 'Unknown file';
+			$flags[] = 'u';
+		}
+
+		// owner
+		$flags[] = ( ( $perms & 0x0100 ) ? 'r' : '-' );
+		$flags[] = ( ( $perms & 0x0080 ) ? 'w' : '-' );
+		$flags[] = ( ( $perms & 0x0040 ) ? ( ( $perms & 0x0800 ) ? 's' : 'x' ) : ( ( $perms & 0x0800 ) ? 'S' : '-' ) );
+
+		// group
+		$flags[] = ( ( $perms & 0x0020 ) ? 'r' : '-' );
+		$flags[] = ( ( $perms & 0x0010 ) ? 'w' : '-' );
+		$flags[] = ( ( $perms & 0x0008 ) ? ( ( $perms & 0x0400 ) ? 's' : 'x' ) : ( ( $perms & 0x0400 ) ? 'S' : '-' ) );
+
+		// world
+		$flags[] = ( ( $perms & 0x0004 ) ? 'r' : '-' );
+		$flags[] = ( ( $perms & 0x0002 ) ? 'w' : '-' );
+		$flags[] = ( ( $perms & 0x0001 ) ? ( ( $perms & 0x0200 ) ? 't' : 'x' ) : ( ( $perms & 0x0200 ) ? 'T' : '-' ) );
+
+		$size  = sprintf( '%.2fK', $variable->getSize() / 1024 );
+		$flags = implode( $flags );
+		$path  = $variable->getRealPath();
+
+		return array(
+			'File information' => array(
+				'Full path' => $path,
+				'Type'      => $type,
+				'Size'      => $size,
+				'Flags'     => $flags
+			)
+		);
+	}
+}

+ 437 - 0
sites/all/modules/contrib/dev/devel/kint/kint/view/base.js

@@ -0,0 +1,437 @@
+/**
+ java -jar compiler.jar --js $FileName$ --js_output_file ../inc/kint.js --compilation_level ADVANCED_OPTIMIZATIONS --output_wrapper "(function(){%output%})()"
+ */
+
+if ( typeof kintInitialized === 'undefined' ) {
+	kintInitialized = 1;
+	var kint = {
+		visiblePluses : [], // all visible toggle carets
+		currentPlus   : -1, // currently selected caret
+
+		selectText : function( element ) {
+			var selection = window.getSelection(),
+			    range = document.createRange();
+
+			range.selectNodeContents(element);
+			selection.removeAllRanges();
+			selection.addRange(range);
+		},
+
+		each : function( selector, callback ) {
+			Array.prototype.slice.call(document.querySelectorAll(selector), 0).forEach(callback)
+		},
+
+		hasClass : function( target, className ) {
+			if ( !target.classList ) return false;
+
+			if ( typeof className === 'undefined' ) {
+				className = 'kint-show';
+			}
+			return target.classList.contains(className);
+		},
+
+		addClass : function( target, className ) {
+			if ( typeof className === 'undefined' ) {
+				className = 'kint-show';
+			}
+			target.classList.add(className);
+		},
+
+		removeClass : function( target, className ) {
+			if ( typeof className === 'undefined' ) {
+				className = 'kint-show';
+			}
+			target.classList.remove(className);
+			return target;
+		},
+
+		next : function( element ) {
+			do {
+				element = element.nextElementSibling;
+			} while ( element.nodeName.toLowerCase() !== 'dd' );
+
+			return element;
+		},
+
+		toggle : function( element, hide ) {
+			var parent = kint.next(element);
+
+			if ( typeof hide === 'undefined' ) {
+				hide = kint.hasClass(element);
+			}
+
+			if ( hide ) {
+				kint.removeClass(element);
+			} else {
+				kint.addClass(element);
+			}
+
+			if ( parent.childNodes.length === 1 ) {
+				parent = parent.childNodes[0].childNodes[0]; // reuse variable cause I can
+
+				// parent is checked in case of empty <pre> when array("\n") is dumped
+				if ( parent && kint.hasClass(parent, 'kint-parent') ) {
+					kint.toggle(parent, hide)
+				}
+			}
+		},
+
+		toggleChildren : function( element, hide ) {
+			var parent = kint.next(element)
+				, nodes = parent.getElementsByClassName('kint-parent')
+				, i = nodes.length;
+
+			if ( typeof hide === 'undefined' ) {
+				hide = kint.hasClass(element);
+			}
+
+			while ( i-- ) {
+				kint.toggle(nodes[i], hide);
+			}
+			kint.toggle(element, hide);
+		},
+
+		toggleAll : function( caret ) {
+			var elements = document.getElementsByClassName('kint-parent')
+				, i = elements.length
+				, visible = kint.hasClass(caret.parentNode);
+
+			while ( i-- ) {
+				kint.toggle(elements[i], visible);
+			}
+		},
+
+		switchTab : function( target ) {
+			var lis, el = target, index = 0;
+
+			target.parentNode.getElementsByClassName('kint-active-tab')[0].className = '';
+			target.className = 'kint-active-tab';
+
+			// take the index of clicked title tab and make the same n-th content tab visible
+			while ( el = el.previousSibling ) el.nodeType === 1 && index++;
+			lis = target.parentNode.nextSibling.childNodes;
+			for ( var i = 0; i < lis.length; i++ ) {
+				if ( i === index ) {
+					lis[i].style.display = 'block';
+
+					if ( lis[i].childNodes.length === 1 ) {
+						el = lis[i].childNodes[0].childNodes[0];
+
+						if ( kint.hasClass(el, 'kint-parent') ) {
+							kint.toggle(el, false)
+						}
+					}
+				} else {
+					lis[i].style.display = 'none';
+				}
+			}
+		},
+
+		isSibling : function( el ) {
+			for ( ; ; ) {
+				el = el.parentNode;
+				if ( !el || kint.hasClass(el, 'kint') ) break;
+			}
+
+			return !!el;
+		},
+
+		fetchVisiblePluses : function() {
+			kint.visiblePluses = [];
+			kint.each('.kint nav, .kint-tabs>li:not(.kint-active-tab)', function( el ) {
+				if ( el.offsetWidth !== 0 || el.offsetHeight !== 0 ) {
+					kint.visiblePluses.push(el)
+				}
+			});
+		},
+
+		openInNewWindow : function( kintContainer ) {
+			var newWindow;
+
+			if ( newWindow = window.open() ) {
+				newWindow.document.open();
+				newWindow.document.write(
+					'<html>'
+					+ '<head>'
+					+ '<title>Kint (' + new Date().toISOString() + ')</title>'
+					+ '<meta charset="utf-8">'
+					+ document.getElementsByClassName('-kint-js')[0].outerHTML
+					+ document.getElementsByClassName('-kint-css')[0].outerHTML
+					+ '</head>'
+					+ '<body>'
+					+ '<input style="width: 100%" placeholder="Take some notes!">'
+					+ '<div class="kint">'
+					+ kintContainer.parentNode.outerHTML
+					+ '</div></body>'
+				);
+				newWindow.document.close();
+			}
+		},
+
+		sortTable : function( table, column ) {
+			var tbody = table.tBodies[0];
+
+			var format = function( s ) {
+				var n = column === 1 ? s.replace(/^#/, '') : s;
+				if ( isNaN(n) ) {
+					return s.trim().toLocaleLowerCase();
+				} else {
+					n = parseFloat(n);
+					return isNaN(n) ? s.trim() : n;
+				}
+			};
+
+
+			[].slice.call(table.tBodies[0].rows)
+				.sort(function( a, b ) {
+					a = format(a.cells[column].textContent);
+					b = format(b.cells[column].textContent);
+					if ( a < b ) return -1;
+					if ( a > b ) return 1;
+
+					return 0;
+				})
+				.forEach(function( el ) {
+					tbody.appendChild(el);
+				});
+		},
+
+		keyCallBacks : {
+			cleanup : function( i ) {
+				var focusedClass = 'kint-focused';
+				var prevElement = document.querySelector('.' + focusedClass);
+				prevElement && kint.removeClass(prevElement, focusedClass);
+
+				if ( i !== -1 ) {
+					var el = kint.visiblePluses[i];
+					kint.addClass(el, focusedClass);
+
+
+					var offsetTop = function( el ) {
+						return el.offsetTop + ( el.offsetParent ? offsetTop(el.offsetParent) : 0 );
+					};
+
+					var top = offsetTop(el) - (window.innerHeight / 2 );
+					window.scrollTo(0, top);
+				}
+
+				kint.currentPlus = i;
+			},
+
+			moveCursor : function( up, i ) {
+				// todo make the first VISIBLE plus active
+				if ( up ) {
+					if ( --i < 0 ) {
+						i = kint.visiblePluses.length - 1;
+					}
+				} else {
+					if ( ++i >= kint.visiblePluses.length ) {
+						i = 0;
+					}
+				}
+
+				kint.keyCallBacks.cleanup(i);
+				return false;
+			}
+		}
+	};
+
+	window.addEventListener("click", function( e ) {
+		var target = e.target
+			, nodeName = target.nodeName.toLowerCase();
+
+		if ( !kint.isSibling(target) ) return;
+
+		// auto-select name of variable
+		if ( nodeName === 'dfn' ) {
+			kint.selectText(target);
+			target = target.parentNode;
+		} else if ( nodeName === 'var' ) { // stupid workaround for misc elements
+			target = target.parentNode;    // to not stop event from further propagating
+			nodeName = target.nodeName.toLowerCase()
+		} else if ( nodeName === 'th' ) {
+			if ( !e.ctrlKey ) {
+				kint.sortTable(target.parentNode.parentNode.parentNode, target.cellIndex)
+			}
+			return false;
+		}
+
+		// switch tabs
+		if ( nodeName === 'li' && target.parentNode.className === 'kint-tabs' ) {
+			if ( target.className !== 'kint-active-tab' ) {
+				kint.switchTab(target);
+				if ( kint.currentPlus !== -1 ) kint.fetchVisiblePluses();
+			}
+			return false;
+		}
+
+		// handle clicks on the navigation caret
+		if ( nodeName === 'nav' ) {
+			// special case for nav in footer
+			if ( target.parentNode.nodeName.toLowerCase() === 'footer' ) {
+				target = target.parentNode;
+				if ( kint.hasClass(target) ) {
+					kint.removeClass(target)
+				} else {
+					kint.addClass(target)
+				}
+			} else {
+				// ensure doubleclick has different behaviour, see below
+				setTimeout(function() {
+					var timer = parseInt(target.kintTimer, 10);
+					if ( timer > 0 ) {
+						target.kintTimer--;
+					} else {
+						kint.toggleChildren(target.parentNode); // <dt>
+						if ( kint.currentPlus !== -1 ) kint.fetchVisiblePluses();
+					}
+				}, 300);
+			}
+
+			e.stopPropagation();
+			return false;
+		} else if ( kint.hasClass(target, 'kint-parent') ) {
+			kint.toggle(target);
+			if ( kint.currentPlus !== -1 ) kint.fetchVisiblePluses();
+			return false;
+		} else if ( kint.hasClass(target, 'kint-ide-link') ) {
+			e.preventDefault();
+			var ajax = new XMLHttpRequest(); // add ajax call to contact editor but prevent link default action
+			ajax.open('GET', target.href);
+			ajax.send(null);
+			return false;
+		} else if ( kint.hasClass(target, 'kint-popup-trigger') ) {
+			var kintContainer = target.parentNode;
+			if ( kintContainer.nodeName.toLowerCase() === 'footer' ) {
+				kintContainer = kintContainer.previousSibling;
+			} else {
+				while ( kintContainer && !kint.hasClass(kintContainer, 'kint-parent') ) {
+					kintContainer = kintContainer.parentNode;
+				}
+			}
+
+			kint.openInNewWindow(kintContainer);
+		} else if ( nodeName === 'pre' && e.detail === 3 ) { // triple click pre to select it all
+			kint.selectText(target);
+		}
+	}, false);
+
+	window.addEventListener("dblclick", function( e ) {
+		var target = e.target;
+		if ( !kint.isSibling(target) ) return;
+
+		if ( target.nodeName.toLowerCase() === 'nav' ) {
+			target.kintTimer = 2;
+			kint.toggleAll(target);
+			if ( kint.currentPlus !== -1 ) kint.fetchVisiblePluses();
+			e.stopPropagation();
+		}
+	}, false);
+
+	// keyboard navigation
+	window.onkeydown = function( e ) { // direct assignment is used to have priority over ex FAYT
+
+		// do nothing if alt/ctrl key is pressed or if we're actually typing somewhere
+		if ( e.target !== document.body || e.altKey || e.ctrlKey ) return;
+
+		var keyCode = e.keyCode
+			, shiftKey = e.shiftKey
+			, i = kint.currentPlus;
+
+
+		if ( keyCode === 68 ) { // 'd' : toggles navigation on/off
+			if ( i === -1 ) {
+				kint.fetchVisiblePluses();
+				return kint.keyCallBacks.moveCursor(false, i);
+			} else {
+				kint.keyCallBacks.cleanup(-1);
+				return false;
+			}
+		} else {
+			if ( i === -1 ) return;
+
+			if ( keyCode === 9 ) { // TAB : moves up/down depending on shift key
+				return kint.keyCallBacks.moveCursor(shiftKey, i);
+			} else if ( keyCode === 38 ) { // ARROW UP : moves up
+				return kint.keyCallBacks.moveCursor(true, i);
+			} else if ( keyCode === 40 ) { // ARROW DOWN : down
+				return kint.keyCallBacks.moveCursor(false, i);
+			}
+		}
+
+
+		var kintNode = kint.visiblePluses[i];
+		if ( kintNode.nodeName.toLowerCase() === 'li' ) { // we're on a trace tab
+			if ( keyCode === 32 || keyCode === 13 ) { // SPACE/ENTER
+				kint.switchTab(kintNode);
+				kint.fetchVisiblePluses();
+				return kint.keyCallBacks.moveCursor(true, i);
+			} else if ( keyCode === 39 ) { // arrows
+				return kint.keyCallBacks.moveCursor(false, i);
+			} else if ( keyCode === 37 ) {
+				return kint.keyCallBacks.moveCursor(true, i);
+			}
+		}
+
+		kintNode = kintNode.parentNode; // simple dump
+		if ( keyCode === 32 || keyCode === 13 ) { // SPACE/ENTER : toggles
+			kint.toggle(kintNode);
+			kint.fetchVisiblePluses();
+			return false;
+		} else if ( keyCode === 39 || keyCode === 37 ) { // ARROW LEFT/RIGHT : respectively hides/shows and traverses
+			var visible = kint.hasClass(kintNode);
+			var hide = keyCode === 37;
+
+			if ( visible ) {
+				kint.toggleChildren(kintNode, hide); // expand/collapse all children if immediate ones are showing
+			} else {
+				if ( hide ) { // LEFT
+					// traverse to parent and THEN hide
+					do {kintNode = kintNode.parentNode} while ( kintNode && kintNode.nodeName.toLowerCase() !== 'dd' );
+
+					if ( kintNode ) {
+						kintNode = kintNode.previousElementSibling;
+
+						i = -1;
+						var parentPlus = kintNode.querySelector('nav');
+						while ( parentPlus !== kint.visiblePluses[++i] ) {}
+						kint.keyCallBacks.cleanup(i)
+					} else { // we are at root
+						kintNode = kint.visiblePluses[i].parentNode;
+					}
+				}
+				kint.toggle(kintNode, hide);
+			}
+			kint.fetchVisiblePluses();
+			return false;
+		}
+	};
+
+	window.addEventListener("load", function( e ) { // colorize microtime results relative to others
+		var elements = Array.prototype.slice.call(document.querySelectorAll('.kint-microtime'), 0);
+		elements.forEach(function( el ) {
+			var value = parseFloat(el.innerHTML)
+				, min = Infinity
+				, max = -Infinity
+				, ratio;
+
+			elements.forEach(function( el ) {
+				var val = parseFloat(el.innerHTML);
+
+				if ( min > val ) min = val;
+				if ( max < val ) max = val;
+			});
+
+			ratio = 1 - (value - min) / (max - min);
+
+			el.style.background = 'hsl(' + Math.round(ratio * 120) + ',60%,70%)';
+		});
+	});
+}
+
+// debug purposes only, removed in minified source
+function clg( i ) {
+	if ( !window.console )return;
+	var l = arguments.length, o = 0;
+	while ( o < l )console.log(arguments[o++])
+}

Some files were not shown because too many files changed in this diff