{"id":16,"date":"1999-06-06T04:08:00","date_gmt":"1999-06-06T04:08:00","guid":{"rendered":""},"modified":"2020-08-01T20:55:02","modified_gmt":"2020-08-01T20:55:02","slug":"growing-frameworks-plugins","status":"publish","type":"post","link":"https:\/\/billwake.com\/growing-frameworks-plugins\/","title":{"rendered":"Growing Frameworks: Plugins"},"content":{"rendered":"<div>What<\/div>\n<div> &nbsp;<\/div>\n<div>Why<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> vs external program<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> vs source code<\/div>\n<div> &nbsp;<\/div>\n<div>Mechanics of plugin client<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Code to interface<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Move class files to plugin directory<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Watch it work<\/div>\n<div> &nbsp;<\/div>\n<div>Mechanics of server<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Define interface<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Define directory<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Load classes<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Instantiate &amp; call<\/div>\n<div> &nbsp;<\/div>\n<div>Plugins in Java<\/div>\n<div> &nbsp;<\/div>\n<div> Consequences<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Security<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Security Manager<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> CPU<\/div>\n<div> &nbsp;<\/div>\n<div>Applications in the Site Manager<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<p><b><i><span style=\"font-family: Arial; font-size: 10pt;\"> <\/span><\/i><\/b><\/p>\n<h2><span style=\"font-size: 10pt;\">Plugins<\/span><\/h2>\n<div>Sometimes, we\u2019d like to treat a whole application as a black-box framework. We might like a sophisticated end user to be able to extend the application.<\/div>\n<div> &nbsp;<\/div>\n<div>A <i>plugin<\/i> is code, typically developed by a framework user, that provides extra capabilities to an application. It is useful when the application provides a framework (in the broadest sense), but different users might need their own handling of the details.<\/div>\n<div> &nbsp;<\/div>\n<div>Adobe Photoshop\u2122, a top-end graphics tool, is probably the biggest popularizer of the plugin approach. Adobe didn\u2019t want to be responsible for creating and marketing every cool image filter imaginable. Instead, they provide a mechanism where you can buy a plugin from a third party, and install it into Photoshop. The plugin becomes a new tool available to the user, as if it had been built in originally.<\/div>\n<div> &nbsp;<\/div>\n<div>A \u201ctraditional\u201d way to provide such a feature is to provide a pipeline to a separate process. For example, web servers have traditionally used CGI scripts in this way. When a web page is requested that uses a CGI script, the web server creates a process for the script, builds a pipeline to it, sends the script the data from the request, and sends the output of the pipline as the result of the request.<\/div>\n<div> &nbsp;<\/div>\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"border-collapse: collapse; margin-left: 45.9pt;\">\n<tbody>\n<tr>\n<td colspan=\"2\" style=\"border-color: windowtext -moz-use-text-color; border-style: solid none; border-width: 0.75pt medium; padding: 0in 5.4pt; width: 382.5pt;\" valign=\"top\" width=\"510\">\n<div align=\"center\" style=\"text-align: center;\"> <b>Separate process<\/b><\/div>\n<\/td>\n<\/tr>\n<tr>\n<td style=\"border-color: -moz-use-text-color windowtext gray -moz-use-text-color; border-style: none solid solid none; border-width: medium 0.75pt 0.75pt medium; padding: 0in 5.4pt; width: 189pt;\" valign=\"top\" width=\"252\">\n<div align=\"center\" style=\"text-align: center;\"> <b>Advantages<\/b><\/div>\n<\/td>\n<td style=\"border-color: -moz-use-text-color -moz-use-text-color gray; border-style: none none solid; border-width: medium medium 0.75pt; padding: 0in 5.4pt; width: 193.5pt;\" valign=\"top\" width=\"258\">\n<div align=\"center\" style=\"text-align: center;\"> <b>Disadvantages<\/b><\/div>\n<\/td>\n<\/tr>\n<tr>\n<td style=\"border-color: -moz-use-text-color windowtext gray -moz-use-text-color; border-style: none solid solid none; border-width: medium 0.75pt 1.5pt medium; padding: 0in 5.4pt; width: 189pt;\" valign=\"top\" width=\"252\">\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Well-defined interface.<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Separate address space prevents a bad script from crashing the whole process.<\/div>\n<\/td>\n<td style=\"border-color: -moz-use-text-color -moz-use-text-color gray; border-style: none none solid; border-width: medium medium 1.5pt; padding: 0in 5.4pt; width: 193.5pt;\" valign=\"top\" width=\"258\">\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Separate address space requires explicit transfer of information.<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Creating processes adds overhead (mitigated by pooling).<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> May require multiple copies of data.<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div> &nbsp;<\/div>\n<div>An alternative is to use threads, running the script in a separate thread within the server.<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"border-collapse: collapse; margin-left: 45.9pt;\">\n<tbody>\n<tr>\n<td colspan=\"2\" style=\"border-color: windowtext -moz-use-text-color; border-style: solid none; border-width: 0.75pt medium; padding: 0in 5.4pt; width: 382.5pt;\" valign=\"top\" width=\"510\">\n<div align=\"center\" style=\"text-align: center;\"> <b>Separate thread in one process<\/b><\/div>\n<\/td>\n<\/tr>\n<tr>\n<td style=\"border-color: -moz-use-text-color windowtext gray -moz-use-text-color; border-style: none solid solid none; border-width: medium 0.75pt 0.75pt medium; padding: 0in 5.4pt; width: 189pt;\" valign=\"top\" width=\"252\">\n<div align=\"center\" style=\"text-align: center;\"> <b>Advantages<\/b><\/div>\n<\/td>\n<td style=\"border-color: -moz-use-text-color -moz-use-text-color gray; border-style: none none solid; border-width: medium medium 0.75pt; padding: 0in 5.4pt; width: 193.5pt;\" valign=\"top\" width=\"258\">\n<div align=\"center\" style=\"text-align: center;\"> <b>Disadvantages<\/b><\/div>\n<\/td>\n<\/tr>\n<tr>\n<td style=\"border-color: -moz-use-text-color windowtext gray -moz-use-text-color; border-style: none solid solid none; border-width: medium 0.75pt 1.5pt medium; padding: 0in 5.4pt; width: 189pt;\" valign=\"top\" width=\"252\">\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Well-defined interface.<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Easier to pass information to the script.<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Less overhead to create thread (rather than process).<\/div>\n<\/td>\n<td style=\"border-color: -moz-use-text-color -moz-use-text-color gray; border-style: none none solid; border-width: medium medium 1.5pt; padding: 0in 5.4pt; width: 193.5pt;\" valign=\"top\" width=\"258\">\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Trouble in one thread can hurt the whole process.<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> The thread has access to the internals of the whole application.<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div> &nbsp;<\/div>\n<div>In Java, servlets take this approach. (Because Java is a relatively safe language, we run less risk of the script crashing the server than we would for, say, C programs.) Some web servers, such as Apache, have been modified to take this approach for languages other than Java.<\/div>\n<div> &nbsp;<\/div>\n<div>Another alternative would be to provide the whole framework of the application.<\/div>\n<div> &nbsp;<\/div>\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"border-collapse: collapse; margin-left: 45.9pt;\">\n<tbody>\n<tr>\n<td colspan=\"2\" style=\"border-color: windowtext -moz-use-text-color; border-style: solid none; border-width: 0.75pt medium; padding: 0in 5.4pt; width: 382.5pt;\" valign=\"top\" width=\"510\">\n<div align=\"center\" style=\"text-align: center;\"> <b>Make whole framework\/application available<\/b><\/div>\n<\/td>\n<\/tr>\n<tr>\n<td style=\"border-color: -moz-use-text-color windowtext gray -moz-use-text-color; border-style: none solid solid none; border-width: medium 0.75pt 0.75pt medium; padding: 0in 5.4pt; width: 189pt;\" valign=\"top\" width=\"252\">\n<div align=\"center\" style=\"text-align: center;\"> <b>Advantages<\/b><\/div>\n<\/td>\n<td style=\"border-color: -moz-use-text-color -moz-use-text-color gray; border-style: none none solid; border-width: medium medium 0.75pt; padding: 0in 5.4pt; width: 193.5pt;\" valign=\"top\" width=\"258\">\n<div align=\"center\" style=\"text-align: center;\"> <b>Disadvantages<\/b><\/div>\n<\/td>\n<\/tr>\n<tr>\n<td style=\"border-color: -moz-use-text-color windowtext gray -moz-use-text-color; border-style: none solid solid none; border-width: medium 0.75pt 1.5pt medium; padding: 0in 5.4pt; width: 189pt;\" valign=\"top\" width=\"252\">\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Allows developer to control all aspects.<\/div>\n<div> &nbsp;<\/div>\n<\/td>\n<td style=\"border-color: -moz-use-text-color -moz-use-text-color gray; border-style: none none solid; border-width: medium medium 1.5pt; padding: 0in 5.4pt; width: 193.5pt;\" valign=\"top\" width=\"258\">\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Requires developer to control all aspects.<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Gives away too much intellectual property.<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<div>A plugin provides an intermediate point in this design space.<\/div>\n<div> &nbsp;<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Only part of the application framework is exposed. The preserves much of the developer\u2019s intellectual property, but still exposes a well-defined piece. (This exposure is the price of letting others extend the application.)<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> The plugin code typically runs in the main thread, or a separate thread in the application. It is quick enough to start up that it can be used to extend a menu or palette.<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> \u201cIntegration\u201d of the plugin with the application is done at run-time. (The developer has to integrate and test with the application, but to the end user it\u2019s \u201cplug-n-play\u201d.)<\/div>\n<div> &nbsp;<\/div>\n<div>We&#8217;ll look at plugins from the perspective of the end user, the plugin developer, and the framework developer. We&#8217;ll explore how<span>&nbsp;<\/span> plugins can be implemented in Java. Finally, we&#8217;ll add plugin support to the web site manager we developed in a previous chapter.<\/div>\n<div> &nbsp;<\/div>\n<p><b><i><span style=\"font-family: Arial; font-size: 10pt;\"> <\/span><\/i><\/b><\/p>\n<h2><span style=\"font-size: 10pt;\">Plugins as Seen by the End-User<\/span><\/h2>\n<div> &nbsp;<\/div>\n<div>Plugins are simple from the end-user&#8217;s point of view. The user has the main application, and decides to add a plugin. Once the plugin is installed, the user has a new feature in the application.<\/div>\n<div> &nbsp;<\/div>\n<div>How does the user install the plugin? Several possibilities are common:<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> The main application detects the need for the plugin, and asks permission to<span>&nbsp;<\/span> install it. (Netscape Communicator (TM) does this.)<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> The user can instruct the main application to install a new plugin. The main application typically<span>&nbsp;<\/span> uses a file dialog to help the user locate the plugin.<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> The plugin may control the process, by having an installation program the user must run. (Then the user is often prompted to locate the main application.)<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Installation is \u201cby convention.\u201d The user may be instructed to drag a file (or files) to a particular directory of the main application.<\/div>\n<div> &nbsp;<\/div>\n<div>Any of these mechanisms are workable. The key is to make it easy for the user.<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<h2><span style=\"font-size: 10pt;\">Plugins as Seen by the Plugin Developer<\/span><\/h2>\n<div>The plugin developer typically works with a software development kit (SDK) for the plugin, provided by the developer of the main application.<\/div>\n<div> &nbsp;<\/div>\n<div>The SDK will contain documentation, source code, object code, miscellaneous scripts and tools, and most importantly, examples. (Some SDKs will include tools such as compilers.)<\/div>\n<div> &nbsp;<\/div>\n<div>The plugin developer will need to know the interface to which the plugin code must conform. (In Java, this will often be a Java \u201cinterface\u201d, rather than inheriting from a particular class.) There may be important support classes as well. There may be information passed <i>to<\/i> the plugin that the plugin must understand.<\/div>\n<div> &nbsp;<\/div>\n<div>The first example is the most critical. It&#8217;s the equivalent of &#8220;Hello, World&#8221; in C. It needn&#8217;t do much, but when the developer completes the steps, they will have created and installed a plugin from scratch.<\/div>\n<div> &nbsp;<\/div>\n<div>Once completed, the plugin developer will test the plugin, and develop an installation mechanism (if one isn\u2019t provided by the application directly).<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<h2><span style=\"font-size: 10pt;\">Plugins as Seen by the Framework\/Application Developer<\/span><\/h2>\n<div>The framework developer must define the interface for the plugin developer. In many ways, this is similar to defining any other framework interface. You want to keep it &#8220;narrow&#8221; &#8211; dependent on as few types as possible. This way, you only expose a limited amount of information to the plugin developer.<\/div>\n<div> &nbsp;<\/div>\n<div>An easy way to allow for plugins is to designate a directory as the target location. This should be in the tree of class files: the plugin mechanism must be able to locate them.<\/div>\n<div> &nbsp;<\/div>\n<div>The framework needs a mechanism for loading the plugin files. (We&#8217;ll see the details in the next section.)<\/div>\n<div> &nbsp;<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Locate the plugins<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Load their classes<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Instantiate and hook up instances<\/div>\n<div> &nbsp;<\/div>\n<div>Once instantiated, the plugins look like any other class. Usually, they\u2019re added to a special menu or palette, to make them available to the end user at runtime.<\/div>\n<div> &nbsp;<\/div>\n<div>Next, the framework developer must develop documentation and examples, as described in the previous section.<\/div>\n<div> &nbsp;<\/div>\n<div>[TBD: The SDK]<\/div>\n<div> &nbsp;<\/div>\n<p><span style=\"font-family: &quot;Times New Roman&quot;; font-size: 10pt;\"> <\/span><\/p>\n<div> &nbsp;<\/div>\n<h2><span style=\"font-size: 10pt;\">Plugins in Java<\/span><\/h2>\n<div>Set directory<\/div>\n<div> Class.forName(&#8220;file&#8221;) -&gt; Class<\/div>\n<div> Class.newInstance()<\/div>\n<div> &nbsp;<\/div>\n<div>Use reflection:<\/div>\n<div>Class c = Class.forName(&#8220;Package.classname&#8221;);<\/div>\n<div>Object o = c.newInstance();<\/div>\n<div>MyClass c = (MyClass) obj;<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<p><b><i><span style=\"font-family: Arial; font-size: 10pt;\"> <\/span><\/i><\/b><\/p>\n<h2><span style=\"font-size: 10pt;\">The Site Manager as a Plugin<\/span><\/h2>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<div>Site manager plugins:<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Look up plugins<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Create main form<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> For each plugin, make listener &amp; insert panel<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Select top node<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<div>Make graph:<\/div>\n<div><span>&nbsp;<\/span> getCanReverseLinks()<\/div>\n<div>to tell if in-links accessible.<\/div>\n<div> &nbsp;<\/div>\n<div>If false, enum always empty (not null).<\/div>\n<div style=\"border-color: -moz-use-text-color -moz-use-text-color windowtext; border-style: none none double; border-width: medium medium 2.25pt; padding: 0in 0in 1pt;\">\n<div style=\"border: medium none; padding: 0in;\"> &nbsp;<\/div>\n<\/div>\n<div> &nbsp;<\/div>\n<div> PageSelectionListener<\/div>\n<div> &nbsp;<\/div>\n<div>PageHandler implements PageSelectionListener<\/div>\n<div><span>&nbsp;<\/span> void pageSelected (PageSelectionEvent e) { &#8230;}<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<div>Page view Plugin extends PageSelectionListener<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> No-arg constructor () required<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> void pageSelected (PageSelectionEvent e) { &#8230;}<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> String getShortName() { &#8230;}<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> String getLongName() { &#8230;}<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> JPanel getPanel() { &#8230;}<\/div>\n<div> &nbsp;<\/div>\n<div>Or an ObjectSelectionListener?<\/div>\n<div> &nbsp;<\/div>\n<div> PageScorePlugin<\/div>\n<div><span>&nbsp;<\/span> columns<\/div>\n<div><span>&nbsp;<\/span> values<\/div>\n<div><span>&nbsp;<\/span> min?<span>&nbsp;<\/span> max?<\/div>\n<div><span>&nbsp;<\/span> Range limits? (red\/yellow\/green?)<\/div>\n<div><span>&nbsp;<\/span> int valueFor (page)<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<p><b><i><span style=\"font-family: Arial; font-size: 10pt;\"> <\/span><\/i><\/b><\/p>\n<h2><span style=\"font-size: 10pt;\">Plugin<\/span><\/h2>\n<div> &nbsp;<\/div>\n<div>Root directory<\/div>\n<div>Directory to search<\/div>\n<div>Class to match<\/div>\n<div>Return array of all classes in the list that match the class<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<div> DefaultMutableTreeNode<\/div>\n<div> &nbsp;<\/div>\n<div>public class FileTree extends DefaultTreeModel {<\/div>\n<div><span>&nbsp;&nbsp;<\/span> public FileTree(File base) {<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> super(new FileTreeNode(base));<\/div>\n<div><span>&nbsp;<\/span> }<\/div>\n<div>}<\/div>\n<div> &nbsp;<\/div>\n<div>public class FileTreeNode extends DefaultMutableTreeNode {<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> public FileTreeNode(File base) { super(base); base.isDirectory();}<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> protected boolean loaded;<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> public int getChildCount() {<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> if (!loaded) {<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> File thisFile = (File)userObject;<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> String files[] = thisFile.list();<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> for (int i = 0; i &lt; files.length; i++) {<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> add(new FileTreeNode(new File(thisFile, files[i])));<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> }<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> loaded = true;<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> }<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> return super.getChildCount();<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> }<\/div>\n<div> &nbsp;<\/div>\n<div>Note:<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> File.toString() is full path<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Not alphabetical<\/div>\n<div style=\"margin-left: 0.25in; text-indent: -0.25in;\">  <span style=\"font-family: Symbol;\">\u00b7<span style=\"font: 7pt &quot;Times New Roman&quot;;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><\/span> Method to select row given file<\/div>\n<div> &nbsp;<\/div>\n<p><span style=\"font-family: &quot;Times New Roman&quot;; font-size: 10pt;\"> <\/span><\/p>\n<div>public class GraphBrowser extends JPanel<span>&nbsp;<\/span> implements GraphListener {<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> GraphBrowser(Graph)<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> GraphBrowser(Graph, Node)<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> GraphBrowser()<span>&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> &#8211;??<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> addObjectSelectionListener (ObjectSelectionListener osl) { &#8230;}<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> removeObjectSelectionListener(ObjectSelectionListener osl) { &#8230;}<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> setGraph(Graph)<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> setNode(Node)<span>&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> \/\/ may be null<\/div>\n<div>}<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<div>UI:<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> List<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Label=current<span>&nbsp;&nbsp;<\/span> List<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<p><b><i><span style=\"font-family: Arial; font-size: 10pt;\"> <\/span><\/i><\/b><\/p>\n<h2><span style=\"font-size: 10pt;\">Graph Browser<\/span><\/h2>\n<div> &nbsp;<\/div>\n<div>Graph graph = null<\/div>\n<div>Node current = null<\/div>\n<div> &nbsp;<\/div>\n<div>JList inList = new JList();<span>&nbsp;&nbsp;&nbsp;<\/span> \/\/ single-sel<\/div>\n<div>JList outList = new JList();<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> \/\/ single-sel<\/div>\n<div>JLabel currentNode = new JLabel();<\/div>\n<div> &nbsp;<\/div>\n<div> GraphBrowser() {<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> setLayout(new GridLayout(1,3));<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> add(new JScrollPane(inList));<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> add(currentNode);<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> add(new JScrollPane(outList));<\/div>\n<div>}<\/div>\n<div> &nbsp;<\/div>\n<div> GraphBrowser(Graph) { &#8230;}<\/div>\n<div> GraphBrowser(Graph, Node) { &#8230;}<\/div>\n<div> &nbsp;<\/div>\n<div>void setGraph (Graph g) { graph = g; setNode(null);}<\/div>\n<div> &nbsp;<\/div>\n<div>void setNode (Node n) {<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> if (current != n) {<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> inList.setModel(new listModel w\/in-nodes for enum);<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Object o = n.getUserObject();<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> currentNode.setText(n==null?&#8221;&#8221;:n.toString());<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> outList.setModel(new model w\/out-nodes);<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> fireSelectionChanged();<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> }<\/div>\n<div>}<\/div>\n<div> &nbsp;<\/div>\n<div>Listeners must make the selection be the new node.<\/div>\n<div> addObjectSelectionListener (osl o) { &#8230;}<\/div>\n<div> removeObjectSelectionListener(osl O) { &#8230;}<\/div>\n<div> &nbsp;<\/div>\n<p><span style=\"font-family: &quot;Times New Roman&quot;; font-size: 10pt;\"> <\/span><\/p>\n<div> NodeToFileTreeAdapter extends objectSelectionListener {<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> public void objectSelected (ObjectSelectionEvent e) {<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Node n = (Node)e.getSelection();<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Page p = (Page)n.getUserObject();<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> File f = p.getFile();<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> find f in tree<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> Set selector to that<\/div>\n<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span> }<\/div>\n<div>}<\/div>\n<div> &nbsp;<\/div>\n<p><b><i><span style=\"font-family: Arial; font-size: 10pt;\"> <\/span><\/i><\/b><\/p>\n<h2><span style=\"font-size: 10pt;\">PLUGINS &#8211; NETSCAPE<\/span><\/h2>\n<div> &nbsp;<\/div>\n<div> http:\/\/developer.netscape.com\/docs\/manuals\/communicator\/plugin\/index.html<\/div>\n<div> &nbsp;<\/div>\n<div>Checks directory<\/div>\n<div>Registers<\/div>\n<div>Queries to see if they can handle it<\/div>\n<div> &nbsp;<\/div>\n<div>Check type<\/div>\n<div>Load plugin<\/div>\n<div> Initialize<\/div>\n<div>Create instance<\/div>\n<div> &nbsp;<\/div>\n<div>Plug-in methods: Functions you implement<\/div>\n<div>Netscape methods: In Communicator, plugin calls them<\/div>\n<div>Data structures<\/div>\n<div> &nbsp;<\/div>\n<div> &nbsp;<\/div>\n<div>When does it apply?<\/div>\n<div>Beans as programs<\/div>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What &nbsp; Why &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vs external program &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vs source code &nbsp; Mechanics of plugin client &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Code to interface &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Move class files to plugin directory &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Watch it work &nbsp; Mechanics of server &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Define interface &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Define directory &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Load classes &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Instantiate &amp; call &nbsp; Plugins in Java &nbsp; Consequences &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"nf_dc_page":"","om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-16","post","type-post","status-publish","format-standard","hentry","category-frameworks"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Growing Frameworks: Plugins - Bill Wake&#039;s Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"http:\/\/billwake.com\/growing-frameworks-plugins\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Growing Frameworks: Plugins - Bill Wake&#039;s Blog\" \/>\n<meta property=\"og:description\" content=\"What &nbsp; Why &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vs external program &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vs source code &nbsp; Mechanics of plugin client &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Code to interface &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Move class files to plugin directory &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Watch it work &nbsp; Mechanics of server &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Define interface &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Define directory &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Load classes &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Instantiate &amp; call &nbsp; Plugins in Java &nbsp; Consequences &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"http:\/\/billwake.com\/growing-frameworks-plugins\/\" \/>\n<meta property=\"og:site_name\" content=\"Bill Wake&#039;s Blog\" \/>\n<meta property=\"article:published_time\" content=\"1999-06-06T04:08:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-08-01T20:55:02+00:00\" \/>\n<meta name=\"author\" content=\"Bill Wake\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Bill Wake\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"http:\\\/\\\/billwake.com\\\/growing-frameworks-plugins\\\/#article\",\"isPartOf\":{\"@id\":\"http:\\\/\\\/billwake.com\\\/growing-frameworks-plugins\\\/\"},\"author\":{\"name\":\"Bill Wake\",\"@id\":\"https:\\\/\\\/billwake.com\\\/#\\\/schema\\\/person\\\/b551cc572ce5d025b081e031a73eec0c\"},\"headline\":\"Growing Frameworks: Plugins\",\"datePublished\":\"1999-06-06T04:08:00+00:00\",\"dateModified\":\"2020-08-01T20:55:02+00:00\",\"mainEntityOfPage\":{\"@id\":\"http:\\\/\\\/billwake.com\\\/growing-frameworks-plugins\\\/\"},\"wordCount\":3257,\"commentCount\":0,\"articleSection\":[\"frameworks\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"http:\\\/\\\/billwake.com\\\/growing-frameworks-plugins\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"http:\\\/\\\/billwake.com\\\/growing-frameworks-plugins\\\/\",\"url\":\"http:\\\/\\\/billwake.com\\\/growing-frameworks-plugins\\\/\",\"name\":\"Growing Frameworks: Plugins - Bill Wake&#039;s Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/billwake.com\\\/#website\"},\"datePublished\":\"1999-06-06T04:08:00+00:00\",\"dateModified\":\"2020-08-01T20:55:02+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/billwake.com\\\/#\\\/schema\\\/person\\\/b551cc572ce5d025b081e031a73eec0c\"},\"breadcrumb\":{\"@id\":\"http:\\\/\\\/billwake.com\\\/growing-frameworks-plugins\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"http:\\\/\\\/billwake.com\\\/growing-frameworks-plugins\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"http:\\\/\\\/billwake.com\\\/growing-frameworks-plugins\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/billwake.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Growing Frameworks: Plugins\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/billwake.com\\\/#website\",\"url\":\"https:\\\/\\\/billwake.com\\\/\",\"name\":\"Bill Wake&#039;s Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/billwake.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/billwake.com\\\/#\\\/schema\\\/person\\\/b551cc572ce5d025b081e031a73eec0c\",\"name\":\"Bill Wake\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/8e2b28fe375cac050dad2f141da886dde7ff7a1edc00116f801ec96cf3849fa1?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/8e2b28fe375cac050dad2f141da886dde7ff7a1edc00116f801ec96cf3849fa1?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/8e2b28fe375cac050dad2f141da886dde7ff7a1edc00116f801ec96cf3849fa1?s=96&d=mm&r=g\",\"caption\":\"Bill Wake\"},\"url\":\"https:\\\/\\\/billwake.com\\\/author\\\/bill-wake\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Growing Frameworks: Plugins - Bill Wake&#039;s Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"http:\/\/billwake.com\/growing-frameworks-plugins\/","og_locale":"en_US","og_type":"article","og_title":"Growing Frameworks: Plugins - Bill Wake&#039;s Blog","og_description":"What &nbsp; Why &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vs external program &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vs source code &nbsp; Mechanics of plugin client &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Code to interface &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Move class files to plugin directory &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Watch it work &nbsp; Mechanics of server &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Define interface &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Define directory &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Load classes &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Instantiate &amp; call &nbsp; Plugins in Java &nbsp; Consequences &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [&hellip;]","og_url":"http:\/\/billwake.com\/growing-frameworks-plugins\/","og_site_name":"Bill Wake&#039;s Blog","article_published_time":"1999-06-06T04:08:00+00:00","article_modified_time":"2020-08-01T20:55:02+00:00","author":"Bill Wake","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Bill Wake","Est. reading time":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"http:\/\/billwake.com\/growing-frameworks-plugins\/#article","isPartOf":{"@id":"http:\/\/billwake.com\/growing-frameworks-plugins\/"},"author":{"name":"Bill Wake","@id":"https:\/\/billwake.com\/#\/schema\/person\/b551cc572ce5d025b081e031a73eec0c"},"headline":"Growing Frameworks: Plugins","datePublished":"1999-06-06T04:08:00+00:00","dateModified":"2020-08-01T20:55:02+00:00","mainEntityOfPage":{"@id":"http:\/\/billwake.com\/growing-frameworks-plugins\/"},"wordCount":3257,"commentCount":0,"articleSection":["frameworks"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["http:\/\/billwake.com\/growing-frameworks-plugins\/#respond"]}]},{"@type":"WebPage","@id":"http:\/\/billwake.com\/growing-frameworks-plugins\/","url":"http:\/\/billwake.com\/growing-frameworks-plugins\/","name":"Growing Frameworks: Plugins - Bill Wake&#039;s Blog","isPartOf":{"@id":"https:\/\/billwake.com\/#website"},"datePublished":"1999-06-06T04:08:00+00:00","dateModified":"2020-08-01T20:55:02+00:00","author":{"@id":"https:\/\/billwake.com\/#\/schema\/person\/b551cc572ce5d025b081e031a73eec0c"},"breadcrumb":{"@id":"http:\/\/billwake.com\/growing-frameworks-plugins\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["http:\/\/billwake.com\/growing-frameworks-plugins\/"]}]},{"@type":"BreadcrumbList","@id":"http:\/\/billwake.com\/growing-frameworks-plugins\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/billwake.com\/"},{"@type":"ListItem","position":2,"name":"Growing Frameworks: Plugins"}]},{"@type":"WebSite","@id":"https:\/\/billwake.com\/#website","url":"https:\/\/billwake.com\/","name":"Bill Wake&#039;s Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/billwake.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/billwake.com\/#\/schema\/person\/b551cc572ce5d025b081e031a73eec0c","name":"Bill Wake","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/8e2b28fe375cac050dad2f141da886dde7ff7a1edc00116f801ec96cf3849fa1?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/8e2b28fe375cac050dad2f141da886dde7ff7a1edc00116f801ec96cf3849fa1?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/8e2b28fe375cac050dad2f141da886dde7ff7a1edc00116f801ec96cf3849fa1?s=96&d=mm&r=g","caption":"Bill Wake"},"url":"https:\/\/billwake.com\/author\/bill-wake\/"}]}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/billwake.com\/wp-json\/wp\/v2\/posts\/16","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/billwake.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/billwake.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/billwake.com\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/billwake.com\/wp-json\/wp\/v2\/comments?post=16"}],"version-history":[{"count":1,"href":"https:\/\/billwake.com\/wp-json\/wp\/v2\/posts\/16\/revisions"}],"predecessor-version":[{"id":60,"href":"https:\/\/billwake.com\/wp-json\/wp\/v2\/posts\/16\/revisions\/60"}],"wp:attachment":[{"href":"https:\/\/billwake.com\/wp-json\/wp\/v2\/media?parent=16"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/billwake.com\/wp-json\/wp\/v2\/categories?post=16"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/billwake.com\/wp-json\/wp\/v2\/tags?post=16"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}