1 00:00:00,000 --> 00:00:05,159 2 00:00:05,159 --> 00:00:09,240 >> DAN ARMENDARIZ: Hello, and welcome to a CS50 seminar on Customizing Cloud 9, 3 00:00:09,240 --> 00:00:11,724 and the CS50 IDE. 4 00:00:11,724 --> 00:00:13,640 So today we're going to just talk a little bit 5 00:00:13,640 --> 00:00:16,090 about some of the technical information that 6 00:00:16,090 --> 00:00:19,380 goes behind the architecture of Cloud 9, and how 7 00:00:19,380 --> 00:00:25,560 we have implemented some of the plug-ins as part of Cloud 9 to provide CS50 IDE. 8 00:00:25,560 --> 00:00:28,820 So let's just jump right in and start talking about plug-ins. 9 00:00:28,820 --> 00:00:32,659 >> So plug-ins are really at the core of the Cloud 9 experience. 10 00:00:32,659 --> 00:00:37,590 Cloud 9 is the underlying technology that provides to us the IDE, 11 00:00:37,590 --> 00:00:42,160 and also the terminal window at the bottom, along with the workspace-- 12 00:00:42,160 --> 00:00:46,430 the Ubuntu workspace-- that we use to compile all of our projects 13 00:00:46,430 --> 00:00:49,190 and perform our problem sets, complete our problem sets. 14 00:00:49,190 --> 00:00:51,820 But at the heart of all of it, all the technology 15 00:00:51,820 --> 00:00:54,590 is really just a bunch of plug-ins. 16 00:00:54,590 --> 00:00:58,740 Everything is a plug-in that can be modified, 17 00:00:58,740 --> 00:01:00,710 extended, you can create your own plug-ins, 18 00:01:00,710 --> 00:01:03,060 you can remove other plug-ins, to really alter 19 00:01:03,060 --> 00:01:07,540 quite a lot of the functionality of the existing Cloud 9 IDE. 20 00:01:07,540 --> 00:01:12,040 >> So this is an existing Cloud 9 environment. 21 00:01:12,040 --> 00:01:14,750 This is really just the default Cloud 9 environment. 22 00:01:14,750 --> 00:01:18,450 And take a look at how it actually is different from the CS50 IDE. 23 00:01:18,450 --> 00:01:20,340 So this is the CS50 IDE. 24 00:01:20,340 --> 00:01:25,060 Notice that there are some visual changes between the regular Cloud 9 25 00:01:25,060 --> 00:01:28,000 environment and the CS50 IDE. 26 00:01:28,000 --> 00:01:30,010 Specifically, you'll notice a couple of changes. 27 00:01:30,010 --> 00:01:34,201 First of all, there's fewer menu items to begin with. 28 00:01:34,201 --> 00:01:36,200 There's actually a way that you can change that. 29 00:01:36,200 --> 00:01:37,270 It's called Simple Mode. 30 00:01:37,270 --> 00:01:40,910 >> By default, Simple Mode is enabled, and that simplifies some of the menu items. 31 00:01:40,910 --> 00:01:43,032 It removes some of the more advanced ones, 32 00:01:43,032 --> 00:01:45,240 because frankly, a lot of students that are coming in 33 00:01:45,240 --> 00:01:48,550 and don't need to know about some of the more advanced features 34 00:01:48,550 --> 00:01:50,530 are not overwhelmed with a bunch of options. 35 00:01:50,530 --> 00:01:55,610 But we do provide the ability to take off those so-called training wheels 36 00:01:55,610 --> 00:01:57,360 and remove that scaffolding so that people 37 00:01:57,360 --> 00:02:00,832 can become more accustomed to the advanced features of the IDE. 38 00:02:00,832 --> 00:02:02,540 Immediately to the right of that, there's 39 00:02:02,540 --> 00:02:05,435 also a debug button, which in the standard Cloud 40 00:02:05,435 --> 00:02:08,199 9 environment is simply called run. 41 00:02:08,199 --> 00:02:11,990 But by default, we have configured the debug button in the CS50 IDE 42 00:02:11,990 --> 00:02:15,500 to bring up the debugger, automatically compile the source code, 43 00:02:15,500 --> 00:02:17,940 connect the debugger to the underlying GDB-- 44 00:02:17,940 --> 00:02:21,430 and since that's running to perform the debugging-- and some other steps 45 00:02:21,430 --> 00:02:22,580 as well. 46 00:02:22,580 --> 00:02:25,370 Also the terminal window at the very-- or rather the terminal 47 00:02:25,370 --> 00:02:29,010 tab at the console section at the window at the very bottom of the screen, 48 00:02:29,010 --> 00:02:31,004 was renamed to simply be terminal. 49 00:02:31,004 --> 00:02:32,837 Whereas in the standard Cloud 9 environment, 50 00:02:32,837 --> 00:02:35,830 it actually shows the running application. 51 00:02:35,830 --> 00:02:39,140 This way, it simplifies, again, the GUI, just a little bit. 52 00:02:39,140 --> 00:02:42,310 >> We also added some buttons to the upper right of the IDE 53 00:02:42,310 --> 00:02:45,740 to show some basic information about the underlying instance. 54 00:02:45,740 --> 00:02:49,700 And also we have removed one of the options on the items 55 00:02:49,700 --> 00:02:51,730 from the far right. 56 00:02:51,730 --> 00:02:55,620 So all of this is implemented not by modifying necessarily the Cloud 9 57 00:02:55,620 --> 00:02:58,550 source code, but instead through a couple 58 00:02:58,550 --> 00:03:03,460 of plug-ins that we have implemented throughout the past year or so. 59 00:03:03,460 --> 00:03:08,840 And Cloud 9 has hosted and has running in the CS50 workspace. 60 00:03:08,840 --> 00:03:13,680 Or rather in the workspaces that are designated as CS50 IDEs. 61 00:03:13,680 --> 00:03:17,140 >> So really that's the main difference between the Cloud 9 and the CS50 62 00:03:17,140 --> 00:03:18,130 workspaces. 63 00:03:18,130 --> 00:03:21,780 There's also, in the underlying instance, the primary change is 64 00:03:21,780 --> 00:03:25,350 that we install some pre-configured items like GDB, 65 00:03:25,350 --> 00:03:29,530 and some other basic things that we've created, like Update 50, 66 00:03:29,530 --> 00:03:33,310 and a couple of other steps that make the whole experience a little bit more 67 00:03:33,310 --> 00:03:34,550 unified. 68 00:03:34,550 --> 00:03:38,520 But overall, this is just a modification of an existing system 69 00:03:38,520 --> 00:03:40,979 that Cloud 9 has created for us. 70 00:03:40,979 --> 00:03:42,770 What we're going to show a little bit later 71 00:03:42,770 --> 00:03:45,920 is how to actually create a somewhat basic plug-in that 72 00:03:45,920 --> 00:03:49,461 allows us to insert something into the menu system, and open up a dialogue. 73 00:03:49,461 --> 00:03:51,210 And if we have enough time, we'll actually 74 00:03:51,210 --> 00:03:54,210 see how we can populate that dialogue with some information 75 00:03:54,210 --> 00:03:56,089 from the underlying instance. 76 00:03:56,089 --> 00:03:58,880 In order for us to get to that point, let's first talk a little bit 77 00:03:58,880 --> 00:04:01,740 about the architecture of Cloud 9. 78 00:04:01,740 --> 00:04:05,290 >> So the way that we're used to interacting with Cloud 9 79 00:04:05,290 --> 00:04:06,610 is entirely through the client. 80 00:04:06,610 --> 00:04:10,610 We open up a web browser, we type in the CS50.io. 81 00:04:10,610 --> 00:04:14,431 We eventually, after authentication, are presented with the IDE. 82 00:04:14,431 --> 00:04:16,180 But realize that there's a couple of steps 83 00:04:16,180 --> 00:04:18,180 that actually get us to this point. 84 00:04:18,180 --> 00:04:22,390 The very first thing is that my client, the web browser, 85 00:04:22,390 --> 00:04:27,440 upon request and after authentication, loads the GUI and the plug-ins 86 00:04:27,440 --> 00:04:30,170 from some CDN, from some Content Delivery Network. 87 00:04:30,170 --> 00:04:32,700 This can be frankly anywhere. 88 00:04:32,700 --> 00:04:35,390 >> And this is actually separate from the underlying instance. 89 00:04:35,390 --> 00:04:38,890 It's important to realize that this is actually just a bunch of static files. 90 00:04:38,890 --> 00:04:42,600 It's a bunch of JavaScript that is downloaded from the CDN 91 00:04:42,600 --> 00:04:45,200 on to my web browser, and all of the GUI that you 92 00:04:45,200 --> 00:04:48,460 see here-- this is really key-- all of the GUI that you see here 93 00:04:48,460 --> 00:04:50,480 is run on the client side. 94 00:04:50,480 --> 00:04:53,820 Everything that you see in the Cloud 9 workspace 95 00:04:53,820 --> 00:04:56,010 is actually run in the browser. 96 00:04:56,010 --> 00:04:59,950 And anything that you send along to the underlying instance 97 00:04:59,950 --> 00:05:04,000 is communicated with the instance along this second separate channel, 98 00:05:04,000 --> 00:05:07,240 and is then saved onto that docker instance. 99 00:05:07,240 --> 00:05:09,660 >> So the reason that I'm saying this is a docker instance 100 00:05:09,660 --> 00:05:12,650 is that the underlying technology is not using virtual machines, 101 00:05:12,650 --> 00:05:16,040 but instead is using a technology called docker, 102 00:05:16,040 --> 00:05:20,200 which basically allows-- the closest analogy is a virtual machine. 103 00:05:20,200 --> 00:05:24,800 But it is subtly different in that there are 104 00:05:24,800 --> 00:05:28,900 plenty of opportunities to run a combination of different docker 105 00:05:28,900 --> 00:05:30,760 instances on a single machine. 106 00:05:30,760 --> 00:05:34,660 And they can be spun up in very rapid succession. 107 00:05:34,660 --> 00:05:38,920 It is not quite the more strict differentiation 108 00:05:38,920 --> 00:05:42,840 between different docker instances as there are in virtual machines, 109 00:05:42,840 --> 00:05:45,730 but still there's a lot of differentiation and separation 110 00:05:45,730 --> 00:05:48,330 between these different instances. 111 00:05:48,330 --> 00:05:48,830 OK. 112 00:05:48,830 --> 00:05:50,980 So the two steps here that are important to realize 113 00:05:50,980 --> 00:05:57,370 is that when we go to CS50.io, we are downloading the GUI and the plug-ins, 114 00:05:57,370 --> 00:06:01,640 which are written in JavaScript, on to the browser or in to the browser. 115 00:06:01,640 --> 00:06:05,980 And this is maybe a couple megabytes worth of information. 116 00:06:05,980 --> 00:06:09,460 At that point, once the GUI has loaded and the plug-ins have started, 117 00:06:09,460 --> 00:06:12,530 then it begins to communicate with the docker instance, which doesn't 118 00:06:12,530 --> 00:06:15,210 necessarily have to be the same server. 119 00:06:15,210 --> 00:06:16,940 >> Now there is one exception to this. 120 00:06:16,940 --> 00:06:22,130 We can actually have both the delivery mechanism for the GUI itself 121 00:06:22,130 --> 00:06:25,740 and the docker instance in all of the same server, which 122 00:06:25,740 --> 00:06:29,660 is actually something that we do for the offline version of Cloud 9. 123 00:06:29,660 --> 00:06:33,470 This is not something that we've publicized very much this Fall, 124 00:06:33,470 --> 00:06:35,930 but we do also have an offline version that 125 00:06:35,930 --> 00:06:40,010 allows you to download a packaged version of all of these things 126 00:06:40,010 --> 00:06:43,670 and allow you to run Cloud 9 in an offline environment. 127 00:06:43,670 --> 00:06:48,325 >> Moving this off the cloud and onto your local machine has some impact. 128 00:06:48,325 --> 00:06:50,200 In particular, you no longer have the ability 129 00:06:50,200 --> 00:06:52,280 to share your workspace with others. 130 00:06:52,280 --> 00:06:58,630 You no longer can open Cloud 9 from, and the CS50 IDE, from any computer 131 00:06:58,630 --> 00:07:02,950 and see the same files that you were working with before. 132 00:07:02,950 --> 00:07:06,310 But instead it works wholly on your own local machine 133 00:07:06,310 --> 00:07:09,270 without needing access to the internet. 134 00:07:09,270 --> 00:07:13,330 But still even in that model, even though we have one virtual machine 135 00:07:13,330 --> 00:07:15,200 that is essentially running these things. 136 00:07:15,200 --> 00:07:19,480 >> We have a separate server that is delivering essentially the Cloud 9 137 00:07:19,480 --> 00:07:23,640 content, and then we have a docker instance 138 00:07:23,640 --> 00:07:32,280 that is responsible for communicating with that IDE for the back end. 139 00:07:32,280 --> 00:07:32,780 OK. 140 00:07:32,780 --> 00:07:38,700 So the entire GUI is written entirely in JavaScript 141 00:07:38,700 --> 00:07:42,800 using Node.js and the Cloud 9 SDK, which we'll get to in just a minute. 142 00:07:42,800 --> 00:07:46,650 And all of the plug-ins are run on the client side. 143 00:07:46,650 --> 00:07:51,780 So let's focus then a little bit by assuming 144 00:07:51,780 --> 00:07:55,670 that this first step has actually completed successfully, 145 00:07:55,670 --> 00:07:58,990 and look only at this docker instance. 146 00:07:58,990 --> 00:08:01,220 >> So in this case, this is the standard way 147 00:08:01,220 --> 00:08:04,870 of thinking about doing Cloud 9 plug-in development is that you are going 148 00:08:04,870 --> 00:08:07,940 to be writing code that will be run in the user's browser, 149 00:08:07,940 --> 00:08:11,610 and you have the opportunity of using some APIs to communicate 150 00:08:11,610 --> 00:08:16,470 with the underlying docker instance, run some code there, and do anything 151 00:08:16,470 --> 00:08:18,860 that you might want to do. 152 00:08:18,860 --> 00:08:22,000 So this is going to be the context that we'll 153 00:08:22,000 --> 00:08:24,340 be using for the rest of this talk. 154 00:08:24,340 --> 00:08:26,400 And just keep this model in mind. 155 00:08:26,400 --> 00:08:28,966 This will be very important in just a few minutes. 156 00:08:28,966 --> 00:08:30,840 There's a couple of links I want to show you. 157 00:08:30,840 --> 00:08:34,150 First of all, Cloud 9 has provided quite a lot of documentation 158 00:08:34,150 --> 00:08:38,740 that's pretty good, that shows how to do basic plug-in development. 159 00:08:38,740 --> 00:08:43,320 So if you go to this URL, cloud9-sdk.readme.io, 160 00:08:43,320 --> 00:08:45,261 you'll see the documentation there. 161 00:08:45,261 --> 00:08:47,510 And a lot of this information that you're about to see 162 00:08:47,510 --> 00:08:50,310 can also be found there, plus more. 163 00:08:50,310 --> 00:08:55,880 You can also find the open source version of Cloud 9 at this URL, 164 00:08:55,880 --> 00:09:04,270 github.com/c9/core, which we use as part of the offline version of the IDE, 165 00:09:04,270 --> 00:09:07,540 so that you will be able to have the same Cloud 9 experience, 166 00:09:07,540 --> 00:09:09,660 but in an offline way. 167 00:09:09,660 --> 00:09:10,160 All right. 168 00:09:10,160 --> 00:09:15,560 So let's take a look at an actual Cloud 9 workspace here. 169 00:09:15,560 --> 00:09:17,880 And again, I want to point out a couple of things. 170 00:09:17,880 --> 00:09:21,560 This is, right here, a normal CS50 IDE. 171 00:09:21,560 --> 00:09:26,830 And I have disabled a less comfortable mode under the View menu 172 00:09:26,830 --> 00:09:28,807 so that I can see all of the menu options. 173 00:09:28,807 --> 00:09:31,140 What I want to show you right now is a couple of things. 174 00:09:31,140 --> 00:09:33,140 First off, if I go into the Preferences and then 175 00:09:33,140 --> 00:09:37,040 click on Plug-in manager, and type in CS50 here, 176 00:09:37,040 --> 00:09:40,590 we can see that there are, in fact, a couple of CS50 plug-ins that 177 00:09:40,590 --> 00:09:46,280 were installed and our running to enable the modifications that we've 178 00:09:46,280 --> 00:09:48,670 seen for the CS50 IDE. 179 00:09:48,670 --> 00:09:51,450 >> Right now there's essentially two plug-ins that are running. 180 00:09:51,450 --> 00:09:54,980 There's one called Simple, which is the simplified mode that 181 00:09:54,980 --> 00:10:00,020 allows you to reduce the number of menu options along the top, 182 00:10:00,020 --> 00:10:03,070 and have this so-called less comfortable mode. 183 00:10:03,070 --> 00:10:07,280 And then there's also CS50 Stats, which is maybe only slightly misnamed. 184 00:10:07,280 --> 00:10:09,550 Because this is what shows you the information 185 00:10:09,550 --> 00:10:10,850 about the underlying workspace. 186 00:10:10,850 --> 00:10:13,560 It injects these buttons along the top right. 187 00:10:13,560 --> 00:10:18,620 It also injects a menu item into the window item, into the Window menu 188 00:10:18,620 --> 00:10:21,730 right here, CS50 IDE Info. 189 00:10:21,730 --> 00:10:27,380 And it's responsible for instantiating this dialogue that we've seen here, 190 00:10:27,380 --> 00:10:31,460 with all the information that we're accustomed to seeing in a CS50 IDE 191 00:10:31,460 --> 00:10:32,870 workspace. 192 00:10:32,870 --> 00:10:33,370 OK. 193 00:10:33,370 --> 00:10:36,910 So there's actually one more plug-in that we have developed as well. 194 00:10:36,910 --> 00:10:40,110 And there's a couple of others that we also haven't publicly released. 195 00:10:40,110 --> 00:10:45,880 But one of them is the overall plug-in that allows GDB to function. 196 00:10:45,880 --> 00:10:50,190 So one of the aspects of Cloud 9 is that they have provided already 197 00:10:50,190 --> 00:10:53,210 this GUI to implement a debugger. 198 00:10:53,210 --> 00:10:57,360 And one of the plug-ins that we have created basically 199 00:10:57,360 --> 00:11:02,380 hooks GDB with this GUI based version of a debugger. 200 00:11:02,380 --> 00:11:07,680 And is responsible for mediating all of the requests that a user might have, 201 00:11:07,680 --> 00:11:10,310 between stepping over or creating breakpoints or anything 202 00:11:10,310 --> 00:11:15,390 along those lines, to translating that to commands that GDB can understand, 203 00:11:15,390 --> 00:11:16,920 issuing those commands to GDB. 204 00:11:16,920 --> 00:11:19,260 And as soon as GDB issues a response, then 205 00:11:19,260 --> 00:11:23,250 we interpret that and update the GUI as necessary. 206 00:11:23,250 --> 00:11:25,130 >> That's probably one of the more complicated 207 00:11:25,130 --> 00:11:28,840 of the plug-ins, so instead what we're going to focus on today is in fact 208 00:11:28,840 --> 00:11:34,590 the Stats plug-in, and we'll talk a little bit about Simple, as well. 209 00:11:34,590 --> 00:11:39,100 So I mentioned before, and I really want to make very, very clear, that again, 210 00:11:39,100 --> 00:11:41,600 all of this that we're seeing here is essentially 211 00:11:41,600 --> 00:11:43,300 operating on the client side. 212 00:11:43,300 --> 00:11:45,810 We do see a terminal window below, and that, of course, 213 00:11:45,810 --> 00:11:49,230 if we type in commands into that, that will be then issued 214 00:11:49,230 --> 00:11:50,690 to the underlying instance. 215 00:11:50,690 --> 00:11:55,280 Similarly, if we open a new file and type some stuff into it and save it, 216 00:11:55,280 --> 00:11:58,240 that file will be saved on the underlying instance. 217 00:11:58,240 --> 00:12:02,310 >> But the editor itself, this terminal window itself, 218 00:12:02,310 --> 00:12:05,700 is all implemented in JavaScript and is all a plug-in 219 00:12:05,700 --> 00:12:09,800 that we can interact with, and therefore modify. 220 00:12:09,800 --> 00:12:11,450 There's a lot of extensibility here. 221 00:12:11,450 --> 00:12:14,690 I recommend taking a look at Cloud 9's GitHub account 222 00:12:14,690 --> 00:12:17,790 to see the vast quantity of plug-ins that are available, 223 00:12:17,790 --> 00:12:23,070 and just how well written a lot of the code is for extensibility. 224 00:12:23,070 --> 00:12:24,920 So there's something that I want to mention 225 00:12:24,920 --> 00:12:30,480 about this as well, which is that there are a lot of-- there's 226 00:12:30,480 --> 00:12:33,450 a lot of functionality that's provided in the preferences 227 00:12:33,450 --> 00:12:37,970 window, which we've seen just alluded to just a few minutes ago. 228 00:12:37,970 --> 00:12:43,690 >> One of the things that we can do as IDE developers, or as Cloud 9 developers, 229 00:12:43,690 --> 00:12:47,410 is to actually inject some preference panels of our own. 230 00:12:47,410 --> 00:12:50,660 So the simple mode, or the less comfortable mode, 231 00:12:50,660 --> 00:12:54,780 and also the IDE information, or the stats plug-in, 232 00:12:54,780 --> 00:12:58,560 has each some preference panels that allow us to modify 233 00:12:58,560 --> 00:13:00,620 the behavior of each of those. 234 00:13:00,620 --> 00:13:04,140 You'll notice that if I go to the Preferences and go to User settings, 235 00:13:04,140 --> 00:13:07,100 there's a CS50 tab, one that says IDE information. 236 00:13:07,100 --> 00:13:09,810 And I can change the information refresh rate. 237 00:13:09,810 --> 00:13:12,250 >> Effectively, what's happening in the stats plug-in 238 00:13:12,250 --> 00:13:16,690 is that every n-seconds, where n-seconds is defined by this preference 239 00:13:16,690 --> 00:13:22,250 panel, information is being fetched from the underlying instance, being sent 240 00:13:22,250 --> 00:13:25,490 back to the client side, the plug-in is then 241 00:13:25,490 --> 00:13:28,650 interpreting the information from the underlying instance 242 00:13:28,650 --> 00:13:31,470 and updating the GUI as necessary. 243 00:13:31,470 --> 00:13:34,710 We can see that right now this is set to 30 seconds, and that's the default. 244 00:13:34,710 --> 00:13:37,950 But I can definitely change how quickly this happens just 245 00:13:37,950 --> 00:13:40,520 by modifying this value. 246 00:13:40,520 --> 00:13:44,330 >> Now one of the interesting things is that this preference panel, GUI, 247 00:13:44,330 --> 00:13:49,560 is really just a GUI version of a lot of underlying settings 248 00:13:49,560 --> 00:13:52,220 that are presented in JSON. 249 00:13:52,220 --> 00:13:56,336 So if I go, for example, under the CS50 IDE menu, or the Cloud 9 menu, 250 00:13:56,336 --> 00:13:58,210 depending on which version you're looking at, 251 00:13:58,210 --> 00:14:00,460 and go to one of these settings-- in this case, 252 00:14:00,460 --> 00:14:03,420 the project settings-- the project settings in this case 253 00:14:03,420 --> 00:14:07,740 applies to all of the settings for this one workspace. 254 00:14:07,740 --> 00:14:11,620 Whereas user settings apply to all of the workspaces 255 00:14:11,620 --> 00:14:15,110 that you might have in your account. 256 00:14:15,110 --> 00:14:18,520 >> So just as an aside here, to be extra clear, 257 00:14:18,520 --> 00:14:22,570 there's a separation between the two because although by default we 258 00:14:22,570 --> 00:14:26,490 have one workspace, which is the CS50 IDE, if you 259 00:14:26,490 --> 00:14:31,900 were to click on your little avatar up here and go to dashboard, 260 00:14:31,900 --> 00:14:35,820 you'll find that you can actually create additional workspaces as well. 261 00:14:35,820 --> 00:14:39,140 You can see here that I do have an IDE 50 workspace, and also 262 00:14:39,140 --> 00:14:41,930 for the purposes of this seminar, a workspace 263 00:14:41,930 --> 00:14:45,084 called workspace, which is right here. 264 00:14:45,084 --> 00:14:46,750 So anyway, I have different preferences. 265 00:14:46,750 --> 00:14:49,910 Each one of these might have separate project preferences, 266 00:14:49,910 --> 00:14:54,091 but the user preferences are shared amongst all my workspaces. 267 00:14:54,091 --> 00:14:55,840 By the way, this is also very handy if you 268 00:14:55,840 --> 00:14:59,080 want to create a workspace with different customization options. 269 00:14:59,080 --> 00:15:01,640 And it's very handy to create a new workspace. 270 00:15:01,640 --> 00:15:04,230 And choose one that might be pre-configured in some other way, 271 00:15:04,230 --> 00:15:07,000 perhaps for PHP specifically, or Django specifically. 272 00:15:07,000 --> 00:15:08,960 Or even just custom. 273 00:15:08,960 --> 00:15:11,320 The CS50 workspace template is the one that we 274 00:15:11,320 --> 00:15:15,420 use that automatically installs Update 50 and all of the settings 275 00:15:15,420 --> 00:15:20,531 that we have there, including all the plug-ins that we have for the CS50 IDE. 276 00:15:20,531 --> 00:15:21,030 OK. 277 00:15:21,030 --> 00:15:22,200 But let's come back to this. 278 00:15:22,200 --> 00:15:25,640 So again, there are projects settings, and those are the ones 279 00:15:25,640 --> 00:15:27,140 that we are looking at here. 280 00:15:27,140 --> 00:15:29,056 And notice that there are a bunch of settings, 281 00:15:29,056 --> 00:15:32,720 many of them correspond to preference panels, but not all of them. 282 00:15:32,720 --> 00:15:40,800 But we can see that here, in this-- oh no, did I put it in the user settings? 283 00:15:40,800 --> 00:15:43,280 Perhaps I put it in the user settings. 284 00:15:43,280 --> 00:15:45,480 And this, here we go. 285 00:15:45,480 --> 00:15:49,840 In the user settings, we can see that we have a CS50 section, 286 00:15:49,840 --> 00:15:53,762 and this is being written to by these Cloud 9 plug-ins 287 00:15:53,762 --> 00:15:54,720 that we've implemented. 288 00:15:54,720 --> 00:15:57,400 There's the simple one to correspond with that simple plug-in, 289 00:15:57,400 --> 00:16:00,930 and the stats one which corresponds to that GUI based 290 00:16:00,930 --> 00:16:02,440 version of the preference panel. 291 00:16:02,440 --> 00:16:05,740 The refresh rate, in this case, is set to 20 seconds. 292 00:16:05,740 --> 00:16:09,740 >> This is all, hopefully, the beginnings of some information 293 00:16:09,740 --> 00:16:14,420 that we'll actually see in a little bit more detail, momentarily. 294 00:16:14,420 --> 00:16:14,920 OK. 295 00:16:14,920 --> 00:16:17,520 So let's say we want to actually get down to it. 296 00:16:17,520 --> 00:16:20,600 We understand that all of the stuff that's happening on the client side 297 00:16:20,600 --> 00:16:24,560 is done actually on the browser, which means that any plug-ins that I write 298 00:16:24,560 --> 00:16:27,990 are going to be written with the browser in mind. 299 00:16:27,990 --> 00:16:30,830 And if I actually want to do anything on the workspace, 300 00:16:30,830 --> 00:16:33,360 I will perhaps have to initiate some sort of communication 301 00:16:33,360 --> 00:16:35,970 between the browser and the workspace to be sure 302 00:16:35,970 --> 00:16:38,212 that that is actually accomplished. 303 00:16:38,212 --> 00:16:40,170 But let's say that now I want to get down to it 304 00:16:40,170 --> 00:16:43,440 and actually create my first plug-in. 305 00:16:43,440 --> 00:16:48,970 Well, the way that you would be able to do that is actually pretty easy. 306 00:16:48,970 --> 00:16:51,370 It's given in the Cloud 9 SDK. 307 00:16:51,370 --> 00:16:55,520 But it's to take your existing workspace name, which 308 00:16:55,520 --> 00:16:59,810 is the URL that you have at the top of your bar, and add the following to it. 309 00:16:59,810 --> 00:17:00,310 ? 310 00:17:00,310 --> 00:17:00,893 Sdk=1&debub=2. 311 00:17:00,893 --> 00:17:04,369 312 00:17:04,369 --> 00:17:08,260 Now what this is going to enable is that the sdk=1 will actually set the SDK 313 00:17:08,260 --> 00:17:11,430 mode to true, which will enable a couple of additional things. 314 00:17:11,430 --> 00:17:15,770 And debug=2 will allow error messages to be a little bit more verbose. 315 00:17:15,770 --> 00:17:20,170 >> And so if you bring up the JavaScript console in your Chrome developer tab, 316 00:17:20,170 --> 00:17:22,829 you will actually be able to see a lot more information 317 00:17:22,829 --> 00:17:24,349 than you would otherwise. 318 00:17:24,349 --> 00:17:28,310 So I recommend turning both of these on at the same time, because it really 319 00:17:28,310 --> 00:17:31,170 is useful to have all this additional information. 320 00:17:31,170 --> 00:17:35,330 It's important to note, however, that turning on debug to the value of 2 321 00:17:35,330 --> 00:17:38,120 means that it's very verbose, and it actually 322 00:17:38,120 --> 00:17:42,590 will somewhat noticeably slow down your IDE, especially when loading 323 00:17:42,590 --> 00:17:45,657 or when do doing heavy tasks. 324 00:17:45,657 --> 00:17:46,740 So just keep that in mind. 325 00:17:46,740 --> 00:17:51,500 It's useful for development, but you may not want to have it on all the time. 326 00:17:51,500 --> 00:17:53,080 >> So let's actually do that. 327 00:17:53,080 --> 00:17:59,374 But in this case, I actually have already set up a workspace with this. 328 00:17:59,374 --> 00:18:00,540 So let's see, sdk=1&debug=2. 329 00:18:00,540 --> 00:18:03,140 330 00:18:03,140 --> 00:18:07,770 With a couple of plug-ins hopefully already installed. 331 00:18:07,770 --> 00:18:08,340 All right. 332 00:18:08,340 --> 00:18:15,050 So now that I've turned on the SDK debug mode, notice that we are in debug mode, 333 00:18:15,050 --> 00:18:20,430 so we can look at the dev tools to see any errors, which I will do offscreen. 334 00:18:20,430 --> 00:18:23,110 We can see that there's a bunch of errors here. 335 00:18:23,110 --> 00:18:28,090 Now it's actually pretty common for Cloud 9 to have a couple of errors, 336 00:18:28,090 --> 00:18:30,680 and I wouldn't worry about them until you 337 00:18:30,680 --> 00:18:32,930 see something that might be specific to the plug-in 338 00:18:32,930 --> 00:18:34,510 that you happen to be creating. 339 00:18:34,510 --> 00:18:37,620 >> So here, for example, we get a couple of 404s-- not found. 340 00:18:37,620 --> 00:18:42,910 We see we're unable to load some information off the underlying instance 341 00:18:42,910 --> 00:18:43,670 itself. 342 00:18:43,670 --> 00:18:46,545 And there's a bunch of additional information, but most of this we're 343 00:18:46,545 --> 00:18:47,970 actually going to ignore for now. 344 00:18:47,970 --> 00:18:50,130 Because this is pretty common for a workspace 345 00:18:50,130 --> 00:18:53,200 to have just a couple of errors. 346 00:18:53,200 --> 00:18:53,700 OK. 347 00:18:53,700 --> 00:18:56,680 I'm going to move this out of the way and come back here. 348 00:18:56,680 --> 00:19:01,860 And now the easy way, the nice thing about having this developer 349 00:19:01,860 --> 00:19:07,330 mode enabled is that it allows me to easily create a new plug-in. 350 00:19:07,330 --> 00:19:12,390 >> So whereas before I actually did not have this new plug-in option available, 351 00:19:12,390 --> 00:19:16,460 which we can see if I go back to my non developer mode over here, 352 00:19:16,460 --> 00:19:18,510 there's no new plug-in. 353 00:19:18,510 --> 00:19:23,220 By enabling the SDK mode, I have a new plug-in available 354 00:19:23,220 --> 00:19:25,660 and I can easily create one. 355 00:19:25,660 --> 00:19:28,160 In this case, there's a couple of different options, simple, 356 00:19:28,160 --> 00:19:30,850 an empty plug-in, a full plug-in, installer, Cloud 9 bundle. 357 00:19:30,850 --> 00:19:33,030 Let's just choose an empty plug-in for now 358 00:19:33,030 --> 00:19:37,670 so that we can see a very simple version of one. 359 00:19:37,670 --> 00:19:41,520 >> Now notice that along the left side that's there is now 360 00:19:41,520 --> 00:19:45,080 something under Favorites, which is listing a couple of plug-ins 361 00:19:45,080 --> 00:19:47,020 that are now available to me. 362 00:19:47,020 --> 00:19:50,420 If I expand that, we will be able to see those. 363 00:19:50,420 --> 00:19:52,730 Now I want you to notice something here, which 364 00:19:52,730 --> 00:19:58,260 is that this is not actually contained within the workspace directory 365 00:19:58,260 --> 00:20:03,190 on my underlying Ubuntu instance, but it is contained on the hard drive. 366 00:20:03,190 --> 00:20:06,330 And where this is located, because this is very useful to know, 367 00:20:06,330 --> 00:20:09,570 especially if you're going to be doing anything with Git, 368 00:20:09,570 --> 00:20:16,870 where this is located is in a .c9 folder, /plugins. 369 00:20:16,870 --> 00:20:21,110 So if I go there, we can see that now the list of plug-ins that are here 370 00:20:21,110 --> 00:20:26,390 matches the list the plug-ins that I saw on the left side of my workspace. 371 00:20:26,390 --> 00:20:28,610 >> Now by default, and this is kind of strange, 372 00:20:28,610 --> 00:20:31,760 by default when I create a new plug-in in a workspace, 373 00:20:31,760 --> 00:20:36,620 it creates this plug-in that by default has a name of an underscore. 374 00:20:36,620 --> 00:20:39,760 Generally that might cause some problems. 375 00:20:39,760 --> 00:20:42,340 So the very next step that I usually perform 376 00:20:42,340 --> 00:20:45,880 is just to remove that particular plug-in 377 00:20:45,880 --> 00:20:52,810 and leave only the simple plug-in that was there initially, plugin.simple. 378 00:20:52,810 --> 00:20:55,430 And that's the only one that's there. 379 00:20:55,430 --> 00:20:55,930 OK. 380 00:20:55,930 --> 00:20:58,380 >> So what does this actually look like? 381 00:20:58,380 --> 00:21:01,210 Well, this is, again, a JavaScript package 382 00:21:01,210 --> 00:21:05,220 that includes some files, including a plugin.js file, where 383 00:21:05,220 --> 00:21:07,700 the main content of my plug-in is located, 384 00:21:07,700 --> 00:21:10,590 a package.json file, which actually specifies 385 00:21:10,590 --> 00:21:13,760 some metadata about this plug-in, such as who the author is, 386 00:21:13,760 --> 00:21:19,240 any additional information about it, a description of the plug-in, and so on. 387 00:21:19,240 --> 00:21:22,190 And also by default, it creates a blank README file, 388 00:21:22,190 --> 00:21:26,100 and an empty test file for you to create some additional documentation, 389 00:21:26,100 --> 00:21:29,430 and a testing harness if you'd like to do that. 390 00:21:29,430 --> 00:21:34,160 >> So let's just take a look first at, very quickly, at the package.json file. 391 00:21:34,160 --> 00:21:38,240 It's easy enough to just go through it and fill in the areas of this 392 00:21:38,240 --> 00:21:42,510 that you would want to fill in, like provide it a name, give a description, 393 00:21:42,510 --> 00:21:45,010 iterate the version number every so often, provide 394 00:21:45,010 --> 00:21:47,570 an author for every person that contributes, 395 00:21:47,570 --> 00:21:53,000 add them to the contributors section, and the rest of this you 396 00:21:53,000 --> 00:21:56,390 can pretty much just leave as it is for now. 397 00:21:56,390 --> 00:21:58,490 >> There's one thing that's important to notice, 398 00:21:58,490 --> 00:22:04,990 that under the plug-ins section, there is a key called plug-in. 399 00:22:04,990 --> 00:22:11,800 And this is matched to the name of the JavaScript file called plugin.js. 400 00:22:11,800 --> 00:22:18,290 So this is how Cloud 9 knows, when it reads this package.json file, which 401 00:22:18,290 --> 00:22:20,720 of the js files to actually load. 402 00:22:20,720 --> 00:22:25,440 If I create additional js files or want to rename that js file from plug-in, 403 00:22:25,440 --> 00:22:30,380 I also have to change it in the package.json file. 404 00:22:30,380 --> 00:22:33,660 >> Any questions from the audience? 405 00:22:33,660 --> 00:22:34,160 No. 406 00:22:34,160 --> 00:22:38,100 That one person who is following along with me so far. 407 00:22:38,100 --> 00:22:38,760 >> OK. 408 00:22:38,760 --> 00:22:42,300 So I actually have created a couple of plug-ins already, 409 00:22:42,300 --> 00:22:44,100 I think, in this workspace. 410 00:22:44,100 --> 00:22:53,800 So let's get rid of some of these, add sdk=1&debug=2, reload this workspace, 411 00:22:53,800 --> 00:22:58,780 and let's see if we have those plug-ins now. 412 00:22:58,780 --> 00:23:01,430 c9/plugins. 413 00:23:01,430 --> 00:23:01,930 Here we go. 414 00:23:01,930 --> 00:23:06,910 We can see now in my c9/plugins of this one, we have plugin.1 and plugin.2. 415 00:23:06,910 --> 00:23:15,260 So we're going to just step up the-- just increase the amount of difficulty 416 00:23:15,260 --> 00:23:16,660 in each of these plug-ins. 417 00:23:16,660 --> 00:23:20,140 But here if I create a new plug-in, I can add it to my favorites. 418 00:23:20,140 --> 00:23:25,560 And I'll just delete those from the underlying file system. 419 00:23:25,560 --> 00:23:28,050 >> Let's remove that. 420 00:23:28,050 --> 00:23:33,206 Now if I open my first plug-in, and open plugin.js, 421 00:23:33,206 --> 00:23:39,980 we can see here the underlying simple version of a plug-in. 422 00:23:39,980 --> 00:23:42,170 Let me actually go back to this other workspace 423 00:23:42,170 --> 00:23:47,160 because you can at least, here see, what a blank plug-in actually looks like. 424 00:23:47,160 --> 00:23:51,810 So underneath the hood, this looks very similar to technology called, 425 00:23:51,810 --> 00:23:53,780 I think, it's RequireJS. 426 00:23:53,780 --> 00:23:56,000 Notice that this doesn't really look, perhaps, 427 00:23:56,000 --> 00:23:59,150 the same as some other JavaScript files that we might have seen. 428 00:23:59,150 --> 00:24:04,250 But instead, there's a couple of just basic lines that it actually has. 429 00:24:04,250 --> 00:24:06,900 >> All of this stuff is first interpreted by the IDE, 430 00:24:06,900 --> 00:24:09,940 but it's not actually run until specified. 431 00:24:09,940 --> 00:24:13,610 And I'll tell you about when that actually means in just a moment. 432 00:24:13,610 --> 00:24:17,840 But notice that here there's a main.consumes line in line 2, 433 00:24:17,840 --> 00:24:23,270 and this lists all of the plug-ins that this plug-in is dependent on. 434 00:24:23,270 --> 00:24:27,150 So by default, we perhaps don't to have any dependencies on other plug-ins, 435 00:24:27,150 --> 00:24:30,530 but when we actually need to depend on features supplied 436 00:24:30,530 --> 00:24:34,900 by other plug-ins in the IDE, we need to list those plug-ins 437 00:24:34,900 --> 00:24:36,890 in the main.consumes line. 438 00:24:36,890 --> 00:24:39,230 And then we need to link them to the code 439 00:24:39,230 --> 00:24:42,860 below, which I'll show you in just a moment about how we can do that. 440 00:24:42,860 --> 00:24:46,100 >> Main.provides gives a name to this plug-in 441 00:24:46,100 --> 00:24:49,190 that other plug-ins could use in their consumes line. 442 00:24:49,190 --> 00:24:52,480 So in this case, my plug-in is just set there by default, 443 00:24:52,480 --> 00:24:55,820 and we should change that to be applicable to our own plug-in, 444 00:24:55,820 --> 00:24:57,540 as we'll see in just moment. 445 00:24:57,540 --> 00:25:01,230 Now here in the function main, this function main 446 00:25:01,230 --> 00:25:05,630 is actually run and interpreted, but it doesn't actually do very much. 447 00:25:05,630 --> 00:25:08,970 It just gets everything set up, but it doesn't actually start the plug-in, 448 00:25:08,970 --> 00:25:11,220 despite what the name sounds like. 449 00:25:11,220 --> 00:25:14,690 That actually happens through a sequence of methods that 450 00:25:14,690 --> 00:25:16,820 are contained throughout this plug-in. 451 00:25:16,820 --> 00:25:20,830 >> So if I scroll down, we can see that we have a life cycle where 452 00:25:20,830 --> 00:25:25,100 on some event called load, or some event called unload, 453 00:25:25,100 --> 00:25:26,940 some events actually happen. 454 00:25:26,940 --> 00:25:33,500 It's really in here where as the plug-in starts that those methods are called. 455 00:25:33,500 --> 00:25:37,240 So let's be a little bit more concrete about this and look at an example. 456 00:25:37,240 --> 00:25:41,010 So here for plugin.1, what we are basically going to do 457 00:25:41,010 --> 00:25:46,010 is to create a menu item called CS50 Seminar Dialog 1-- 458 00:25:46,010 --> 00:25:48,070 because we have two of them-- and we're going 459 00:25:48,070 --> 00:25:50,300 to inject it into the Window menu. 460 00:25:50,300 --> 00:25:54,590 And when we click on it, we're going to open up a dialogue that 461 00:25:54,590 --> 00:25:56,290 shows us some very basic information. 462 00:25:56,290 --> 00:25:58,050 >> In this case, just a hello world. 463 00:25:58,050 --> 00:26:01,880 So this is a very simple hello world dialogue 464 00:26:01,880 --> 00:26:05,260 that we can implement as a plug-in in Cloud 9. 465 00:26:05,260 --> 00:26:07,960 So let's see how this actually looks. 466 00:26:07,960 --> 00:26:12,730 We'll step through it, just relatively quickly so we 467 00:26:12,730 --> 00:26:15,580 can look at the next plug-in as well. 468 00:26:15,580 --> 00:26:19,510 Notice that here we are consuming a variety of plug-ins. 469 00:26:19,510 --> 00:26:26,080 We're consuming a dialogue plug-in, commands, menus, and UI. 470 00:26:26,080 --> 00:26:30,440 Looks like I actually am consuming dialogue twice, so I can remove that. 471 00:26:30,440 --> 00:26:32,560 >> And notice that the way that I'm connecting them, 472 00:26:32,560 --> 00:26:37,940 this is sort of metadata that's telling the plug-in system what requirements 473 00:26:37,940 --> 00:26:41,480 are actually necessary for this plug-in to load. 474 00:26:41,480 --> 00:26:46,400 It's also important to note that the order that plug-ins are loaded 475 00:26:46,400 --> 00:26:48,300 is not guaranteed. 476 00:26:48,300 --> 00:26:53,400 But what is guaranteed is that if I specify some plug-in as a requirement, 477 00:26:53,400 --> 00:26:56,900 that plug-in will be loaded before this one is loaded. 478 00:26:56,900 --> 00:27:00,390 >> So that means that if your plug-in requires on some functionality provided 479 00:27:00,390 --> 00:27:04,380 by something else in the IDE, you should be sure that your plug-in consumes 480 00:27:04,380 --> 00:27:09,260 that plug-in so that the dependencies are certain to create your plug-in, 481 00:27:09,260 --> 00:27:15,010 or instantiate your plug-in, only after that existing framework exists. 482 00:27:15,010 --> 00:27:18,870 So here I have mentioned the metadata to the plug-in manager, 483 00:27:18,870 --> 00:27:20,990 which ones I'm going to consume. 484 00:27:20,990 --> 00:27:24,910 And in the main function here, I'm going to then connect 485 00:27:24,910 --> 00:27:30,240 my code to those imported plug-ins. 486 00:27:30,240 --> 00:27:33,420 >> So I'm just going to create some variables that 487 00:27:33,420 --> 00:27:36,620 match the names of each of those so that I can very quickly reference them 488 00:27:36,620 --> 00:27:37,840 throughout my code. 489 00:27:37,840 --> 00:27:41,840 The reason I'm importing dialogue is because I want my plug-in 490 00:27:41,840 --> 00:27:44,560 to act as a dialogue plug-in. 491 00:27:44,560 --> 00:27:49,320 And the way that I'm able to do that is to, of course, 492 00:27:49,320 --> 00:27:52,740 connect my code to the dialogue plug-in by importing it 493 00:27:52,740 --> 00:27:57,210 and then by specifying by creating a new dialogue variable 494 00:27:57,210 --> 00:28:00,460 and connecting it to that imported plug-in. 495 00:28:00,460 --> 00:28:04,820 And then by defining my plug-in as a new dialogue. 496 00:28:04,820 --> 00:28:07,650 >> So in the initialization, I want to define my plug-in. 497 00:28:07,650 --> 00:28:10,440 And this variable called plug-in you'll see 498 00:28:10,440 --> 00:28:14,030 is just used commonly throughout Cloud 9 plug-ins. 499 00:28:14,030 --> 00:28:16,980 I'm going to instantiate a new dialogue with some attributes, 500 00:28:16,980 --> 00:28:22,300 give it a specific name, say that it is possible for users to close it. 501 00:28:22,300 --> 00:28:24,960 That it'll show a little x in the upper right hand corner, 502 00:28:24,960 --> 00:28:27,529 or a little button in the lower right hand corner. 503 00:28:27,529 --> 00:28:30,570 Whether or not I can select text from it, what the title of that dialogue 504 00:28:30,570 --> 00:28:32,400 would be, and so on. 505 00:28:32,400 --> 00:28:36,330 Now this just defines the dialogue, but it doesn't yet show it. 506 00:28:36,330 --> 00:28:40,780 I actually have to define an action for it to be shown. 507 00:28:40,780 --> 00:28:43,490 >> And again, I encourage you to take a look at the Cloud 9 SDK, 508 00:28:43,490 --> 00:28:46,930 because there are a variety dialogues and they are really well documented. 509 00:28:46,930 --> 00:28:50,500 You can see the different types that there are, and use them 510 00:28:50,500 --> 00:28:55,380 in whatever plug-in you have in mind. 511 00:28:55,380 --> 00:28:58,790 Now there's going to be a load section, and this load 512 00:28:58,790 --> 00:29:03,390 function as you recall is used by the plug-in life cycle 513 00:29:03,390 --> 00:29:07,060 to actually instantiate everything and get everything ready to go. 514 00:29:07,060 --> 00:29:11,440 Now when this plug-in loads, I don't want it to immediately show a dialogue, 515 00:29:11,440 --> 00:29:14,160 because this plug-in will load along with the rest of the IDE. 516 00:29:14,160 --> 00:29:17,850 And when I load that IDE, I don't want the dialogue to show up automatically. 517 00:29:17,850 --> 00:29:24,170 I only want it to show when I click on the menu option in my Window menu item 518 00:29:24,170 --> 00:29:26,760 that I will add to it momentarily. 519 00:29:26,760 --> 00:29:29,480 >> So there's two distinct steps here that have to happen. 520 00:29:29,480 --> 00:29:32,640 I have to create a command, and the command 521 00:29:32,640 --> 00:29:37,940 will be responsible for actually showing the dialogue on the Cloud 9 IDE. 522 00:29:37,940 --> 00:29:42,670 And then I have to connect, I have to create a new window menu 523 00:29:42,670 --> 00:29:46,070 item, that runs that command. 524 00:29:46,070 --> 00:29:49,740 So that when I click on that Window menu item, that command is then run 525 00:29:49,740 --> 00:29:52,290 and therefore my dialogue is then shown. 526 00:29:52,290 --> 00:29:55,690 And so this is actually a pretty nice way of thinking about it. 527 00:29:55,690 --> 00:30:01,480 >> Because first I can create a command whose name is CS50 Seminar Dialog 1, 528 00:30:01,480 --> 00:30:04,860 that provides some general context for it. 529 00:30:04,860 --> 00:30:08,930 And the important bit here is to notice the EXEC attribute, which 530 00:30:08,930 --> 00:30:15,160 lists a function that will be called in my plug-in when this command is run. 531 00:30:15,160 --> 00:30:21,980 So this command is sort of like a-- it's just an arbitrary Cloud 9 532 00:30:21,980 --> 00:30:25,780 command that's available to any Cloud 9 plug-in. 533 00:30:25,780 --> 00:30:30,290 But the actual function that it's going to call when this command is run 534 00:30:30,290 --> 00:30:35,010 is the show dialogue function in my plugin.js file. 535 00:30:35,010 --> 00:30:38,550 >> And we can actually see these plug-ins and the list 536 00:30:38,550 --> 00:30:45,480 of commands that are available to us in Preferences, scroll all the way down-- 537 00:30:45,480 --> 00:30:48,180 let's see, actually do we see this now? 538 00:30:48,180 --> 00:30:53,180 Plug-in manager, no, I think I-- it's definitely around here somewhere. 539 00:30:53,180 --> 00:31:00,016 Well, there's a list of commands somewhere, but I must have, 540 00:31:00,016 --> 00:31:01,140 I've forgotten where it is. 541 00:31:01,140 --> 00:31:02,430 So OK, we'll move on. 542 00:31:02,430 --> 00:31:02,930 All right. 543 00:31:02,930 --> 00:31:05,790 So we have a list of commands that are available to us, 544 00:31:05,790 --> 00:31:08,550 and those commands are these just arbitrary Cloud 9 545 00:31:08,550 --> 00:31:10,870 commands that run specific code. 546 00:31:10,870 --> 00:31:13,620 So just keep that in mind, that we're going to run the show dialog 547 00:31:13,620 --> 00:31:15,640 function momentarily. 548 00:31:15,640 --> 00:31:19,740 Now when I actually want to add a menu item, I can add that item by path, 549 00:31:19,740 --> 00:31:25,570 and just specify exactly where I want it to be, Window/CS50 Seminar Dialog 1. 550 00:31:25,570 --> 00:31:28,380 And at that point, I want to create a new item that 551 00:31:28,380 --> 00:31:32,040 is going to run a command, CS50 Seminar Dialog 1. 552 00:31:32,040 --> 00:31:36,140 Notice that again, this is the Cloud 9 command I've created just above. 553 00:31:36,140 --> 00:31:38,630 >> Now I also want to create a little divider, 554 00:31:38,630 --> 00:31:42,260 and so I can do the same in the subsequent line. 555 00:31:42,260 --> 00:31:46,040 Now you might notice that as part of defining this menu item, 556 00:31:46,040 --> 00:31:48,200 there's a number associated with it which 557 00:31:48,200 --> 00:31:51,260 actually says where exactly I want that menu item to be 558 00:31:51,260 --> 00:31:53,441 located in the list of menus. 559 00:31:53,441 --> 00:31:55,190 But you might notice that I don't actually 560 00:31:55,190 --> 00:31:59,540 see any numbers with these menus, by default. 561 00:31:59,540 --> 00:32:04,630 So there's a little hidden thing that we can do, a little change to our URL. 562 00:32:04,630 --> 00:32:12,920 So in addition to sdk=1&debug=2, I'll set menu to 1-- 563 00:32:12,920 --> 00:32:14,690 and hopefully it's menu, not menus. 564 00:32:14,690 --> 00:32:17,001 Oh, it's menus=1. 565 00:32:17,001 --> 00:32:17,500 Hold on. 566 00:32:17,500 --> 00:32:20,150 567 00:32:20,150 --> 00:32:24,690 >> And what we will see upon reloading that IDE is that I am still in debug mode, 568 00:32:24,690 --> 00:32:27,540 but now there are numbers associated with all the menus. 569 00:32:27,540 --> 00:32:29,630 And this tells you exactly what the number 570 00:32:29,630 --> 00:32:34,730 is when you're trying to inject something anywhere in this menu system. 571 00:32:34,730 --> 00:32:40,365 So in the Window menu, I can see that item 45 is collaborate, 572 00:32:40,365 --> 00:32:43,820 and item 38 before it is installer. 573 00:32:43,820 --> 00:32:47,530 So when I want to inject an item between those two, 574 00:32:47,530 --> 00:32:50,570 I would just select a number between those two items. 575 00:32:50,570 --> 00:32:56,200 So I selected 41 and inserted my Seminar Dialog 1 menu item at that location. 576 00:32:56,200 --> 00:33:03,640 >> And that's why this number that appears here is number 41. 577 00:33:03,640 --> 00:33:08,010 That is the location of that menu item in the Cloud 9 menu. 578 00:33:08,010 --> 00:33:11,045 Now similarly, I wanted to create a divider 579 00:33:11,045 --> 00:33:13,920 and add it so that there's a nice division between each of these menu 580 00:33:13,920 --> 00:33:14,490 items. 581 00:33:14,490 --> 00:33:18,600 So I added that at location 43. 582 00:33:18,600 --> 00:33:20,260 So far, so good, I hope? 583 00:33:20,260 --> 00:33:23,920 So now let's actually look at the specific code in show dialog 584 00:33:23,920 --> 00:33:28,050 that's actually responsible for opening this dialog window. 585 00:33:28,050 --> 00:33:32,710 >> Scrolling down, I see that I want to have this function show dialog, 586 00:33:32,710 --> 00:33:34,730 and it's extremely simple. 587 00:33:34,730 --> 00:33:38,570 I'm going to run the show method on the plug-in variable. 588 00:33:38,570 --> 00:33:43,900 And remember that we defined this plug-in variable above as a dialogue. 589 00:33:43,900 --> 00:33:48,530 So bar plug-in, in this case, is this object that we've defined internally. 590 00:33:48,530 --> 00:33:53,030 And it's going to be a new dialogue contained within this plug-in. 591 00:33:53,030 --> 00:33:57,020 And so we actually referenced this plug-in variable in many places 592 00:33:57,020 --> 00:33:59,790 in a typical Cloud 9 development environment. 593 00:33:59,790 --> 00:34:00,867 >> We'll see it here. 594 00:34:00,867 --> 00:34:03,450 Notice that as we scroll down, there's additional life cycles. 595 00:34:03,450 --> 00:34:06,970 So notice that these respond to events that are fired 596 00:34:06,970 --> 00:34:10,500 by this object, this dialogue object. 597 00:34:10,500 --> 00:34:12,710 By default, there's load and unload, which 598 00:34:12,710 --> 00:34:14,760 are available to all Cloud 9 plug-ins. 599 00:34:14,760 --> 00:34:17,139 But in the event of this dialogue, there's 600 00:34:17,139 --> 00:34:19,139 another event that can fire as well called 601 00:34:19,139 --> 00:34:23,239 Draw, which is fired when that is about to be drawn on screen, 602 00:34:23,239 --> 00:34:27,239 at the first instance of the dialogue showing. 603 00:34:27,239 --> 00:34:29,590 >> So when it is actually going to be shown, 604 00:34:29,590 --> 00:34:31,739 there is going to provide to us some HTML. 605 00:34:31,739 --> 00:34:34,710 And using just standard HTML practices can we 606 00:34:34,710 --> 00:34:41,030 inject some very simple information, our hello world, in that dialogue. 607 00:34:41,030 --> 00:34:47,780 So if we then scroll up, we can see then the procession of things 608 00:34:47,780 --> 00:34:48,989 that it's occurring. 609 00:34:48,989 --> 00:34:54,070 First we created a Cloud 9 command that when executed by Cloud 9, 610 00:34:54,070 --> 00:34:55,765 is going to fire this function. 611 00:34:55,765 --> 00:34:58,390 It's going to run this function called show dialogue, that I've 612 00:34:58,390 --> 00:34:59,720 written in my code. 613 00:34:59,720 --> 00:35:04,350 >> I created a menu item and attached to it that same command 614 00:35:04,350 --> 00:35:08,550 that when that item is clicked in the menu, that command is then run 615 00:35:08,550 --> 00:35:10,780 and that function is then run. 616 00:35:10,780 --> 00:35:14,080 And inside of the function I'm just going to call the-- I'm 617 00:35:14,080 --> 00:35:17,250 just going to execute the show method of this plug-in, which 618 00:35:17,250 --> 00:35:20,800 is going to first call the draw method, and going 619 00:35:20,800 --> 00:35:28,050 to fire this method down below, the draw event handler, in our life cycle. 620 00:35:28,050 --> 00:35:30,820 And then it will actually show the dialogue. 621 00:35:30,820 --> 00:35:34,870 >> There's also a hide method, so that if I need the opportunity to hide 622 00:35:34,870 --> 00:35:37,610 my dialogue, I can do the same thing. 623 00:35:37,610 --> 00:35:42,060 So that's pretty much it to get all of this to work. 624 00:35:42,060 --> 00:35:45,160 Notice that's if we scroll down further there's a freeze public API. 625 00:35:45,160 --> 00:35:51,020 This basically just says that I want these methods to effectively 626 00:35:51,020 --> 00:35:56,670 be public, but not overwriteable outside of the context of this plug-in. 627 00:35:56,670 --> 00:36:00,410 And below, at the very bottom, is perhaps the last thing 628 00:36:00,410 --> 00:36:03,180 that we really need to pay much attention to here, which 629 00:36:03,180 --> 00:36:09,540 is that we are going to register our plug-in with the name C9 Seminar 1, 630 00:36:09,540 --> 00:36:11,920 and the object plug-in. 631 00:36:11,920 --> 00:36:14,870 >> Which as you'll recall, is that plug-in that plug-in 632 00:36:14,870 --> 00:36:18,200 object that we've been defining throughout the entirety of this source 633 00:36:18,200 --> 00:36:18,840 code. 634 00:36:18,840 --> 00:36:23,790 And C9 Seminar 1 is the string that we promised 635 00:36:23,790 --> 00:36:26,350 to provide at the top of this definition. 636 00:36:26,350 --> 00:36:29,280 637 00:36:29,280 --> 00:36:29,780 OK. 638 00:36:29,780 --> 00:36:34,160 So let's ramp it up a little bit and see if we can do something 639 00:36:34,160 --> 00:36:36,020 a little bit more interesting. 640 00:36:36,020 --> 00:36:38,350 Now this is only so great. 641 00:36:38,350 --> 00:36:41,380 I mean, this is, it's actually pretty cool that in so few lines of code, 642 00:36:41,380 --> 00:36:45,570 can we modify the existing IDE and add an existing menu item 643 00:36:45,570 --> 00:36:48,850 or add a new menu item, add a command, and show a dialogue, 644 00:36:48,850 --> 00:36:51,040 and just a bunch of functionality that exists. 645 00:36:51,040 --> 00:36:54,550 It's really pretty great. 646 00:36:54,550 --> 00:36:59,470 >> But it doesn't do a lot because it can't communicate with the underlying Ubuntu 647 00:36:59,470 --> 00:37:00,450 instance. 648 00:37:00,450 --> 00:37:02,560 So let's say that I actually want to find out 649 00:37:02,560 --> 00:37:05,400 some information about the underlying Ubuntu instance, 650 00:37:05,400 --> 00:37:08,260 like the stats plug-in does. 651 00:37:08,260 --> 00:37:11,090 So let's take a look at a little bit more information 652 00:37:11,090 --> 00:37:13,730 about how the stats plug-in works. 653 00:37:13,730 --> 00:37:15,900 And in fact, it is very similar to this. 654 00:37:15,900 --> 00:37:17,680 You might recall that there's a dialogue. 655 00:37:17,680 --> 00:37:21,680 You might recall that there's some information that's 656 00:37:21,680 --> 00:37:24,860 shown just along the menu bar along the top, which hopefully you are now 657 00:37:24,860 --> 00:37:27,450 getting a flavor of how we implemented this, 658 00:37:27,450 --> 00:37:32,360 just by inserting menu items at specific points and by instantiating a dialogue 659 00:37:32,360 --> 00:37:34,360 and displaying that dialogue. 660 00:37:34,360 --> 00:37:36,580 >> But we haven't yet shown you how we can connect it 661 00:37:36,580 --> 00:37:40,790 to a command in the underlying Ubuntu instance. 662 00:37:40,790 --> 00:37:46,930 So let's take a look then at plugin.2, which does precisely this thing. 663 00:37:46,930 --> 00:37:50,540 We're going to open plugin.js, which is the code for this. 664 00:37:50,540 --> 00:37:54,570 But under the Window menu, if I click on dialog 2, 665 00:37:54,570 --> 00:37:58,290 we can see that it says this instead, hello CS50, which 666 00:37:58,290 --> 00:38:01,800 doesn't look all that enticing, right? 667 00:38:01,800 --> 00:38:04,310 Except, watch this. 668 00:38:04,310 --> 00:38:07,020 Let me change something down here. 669 00:38:07,020 --> 00:38:11,540 >> I'm going to go to my workspace and change seminar 670 00:38:11,540 --> 00:38:15,990 to say something else, like Hello, Dan. 671 00:38:15,990 --> 00:38:18,150 I'm going to close it and save it. 672 00:38:18,150 --> 00:38:22,740 And now I'm going to re-run my dialogue menu item. 673 00:38:22,740 --> 00:38:25,590 And notice that it has now changed what it says. 674 00:38:25,590 --> 00:38:26,880 Hello, Dan. 675 00:38:26,880 --> 00:38:30,680 I seem to have done something down here in the underlying Ubuntu instance 676 00:38:30,680 --> 00:38:34,370 without having manipulated any code that again is running solely 677 00:38:34,370 --> 00:38:35,720 on the client side. 678 00:38:35,720 --> 00:38:40,380 So there's obviously some sort of communication that's happening here. 679 00:38:40,380 --> 00:38:44,550 >> Now this is where a lot of the power of the Cloud 9 SDK comes in, 680 00:38:44,550 --> 00:38:49,440 is that in this plugin.2, we can actually cause 681 00:38:49,440 --> 00:38:52,910 a call to happen to the underlying instance, 682 00:38:52,910 --> 00:38:55,750 and run some arbitrary command. 683 00:38:55,750 --> 00:39:00,230 So in this case, I have actually created a very simple bash script 684 00:39:00,230 --> 00:39:02,350 in my workspace called Seminar. 685 00:39:02,350 --> 00:39:03,610 So let me open that up. 686 00:39:03,610 --> 00:39:05,370 And we can see that it looks like this. 687 00:39:05,370 --> 00:39:08,310 It's just a very simple bash script whose sole purpose in life 688 00:39:08,310 --> 00:39:11,920 is going to be to echo out this text, Hello, Dan. 689 00:39:11,920 --> 00:39:14,360 Or before it, it said Hello, CS50. 690 00:39:14,360 --> 00:39:16,000 And that's all it's going to do. 691 00:39:16,000 --> 00:39:21,030 >> Because this is now a command that I can run. 692 00:39:21,030 --> 00:39:23,750 I can actually run it down here. 693 00:39:23,750 --> 00:39:28,440 We can see that it actually is just a command that I run naturally. 694 00:39:28,440 --> 00:39:32,850 I can ask my plug-in to execute this command on the underlying workspace 695 00:39:32,850 --> 00:39:36,510 and parse the information that was returned from it, 696 00:39:36,510 --> 00:39:40,300 and do something with it, and modify my plug-in and the behavior that I 697 00:39:40,300 --> 00:39:43,240 have in my plug-in as a result. OK. 698 00:39:43,240 --> 00:39:45,450 So let's see how this happens. 699 00:39:45,450 --> 00:39:48,380 We saw this very simple Seminar batch script that I 700 00:39:48,380 --> 00:39:51,080 [INAUDIBLE] that it can actually run. 701 00:39:51,080 --> 00:39:54,560 >> And now let's see the modifications that are necessary to tie this together 702 00:39:54,560 --> 00:39:57,620 with the dialog window, and run it. 703 00:39:57,620 --> 00:40:02,030 So here we're going to do pretty much the same thing as we saw before. 704 00:40:02,030 --> 00:40:05,500 But notice that among the things that I've consumed now-- 705 00:40:05,500 --> 00:40:09,090 in addition to the dialogue, which again I happen to have done twice, 706 00:40:09,090 --> 00:40:14,300 which isn't necessary-- in addition to the dialogue and the commands 707 00:40:14,300 --> 00:40:17,780 and the menus plug-ins, which were necessary in the first one for me 708 00:40:17,780 --> 00:40:21,560 to define a new command and inject an item into the menus, 709 00:40:21,560 --> 00:40:25,010 I also have this proc plug-in. 710 00:40:25,010 --> 00:40:28,500 >> And this proc plug-in allows us to manipulate processes 711 00:40:28,500 --> 00:40:30,950 on the underlying instance. 712 00:40:30,950 --> 00:40:34,970 I've connected it after I've said that my plug-in requires it. 713 00:40:34,970 --> 00:40:38,320 I've then connected it to code, as we saw in the main function. 714 00:40:38,320 --> 00:40:40,970 Again, I'm going to initialize my dialogue. 715 00:40:40,970 --> 00:40:45,500 And if we move down now, we can see how this is different. 716 00:40:45,500 --> 00:40:49,040 The load function is the same, so it's just going to create a command 717 00:40:49,040 --> 00:40:54,250 and create a menu item and connect that menu item to that command. 718 00:40:54,250 --> 00:40:56,690 But if we now scroll down to show dialogue, 719 00:40:56,690 --> 00:40:59,990 we can start to see where the differences arise. 720 00:40:59,990 --> 00:41:04,170 >> We have function show dialogue, which is just going to show the dialogue. 721 00:41:04,170 --> 00:41:12,410 But when I show this dialogue, and when the show method is called, 722 00:41:12,410 --> 00:41:14,430 it fires the draw function. 723 00:41:14,430 --> 00:41:18,990 And I'm going to then specify some content inside of that. 724 00:41:18,990 --> 00:41:21,910 So I'm just going to create a div, provide to it 725 00:41:21,910 --> 00:41:24,020 some basic text, Hello, world. 726 00:41:24,020 --> 00:41:27,250 But notice that here I'm going to attach to it an ID. 727 00:41:27,250 --> 00:41:32,350 And the very next line I am going to find that ID using JavaScript, 728 00:41:32,350 --> 00:41:36,210 and store that object into another variable 729 00:41:36,210 --> 00:41:38,280 that I'm just going to call content. 730 00:41:38,280 --> 00:41:41,780 >> So now whenever I have content, all I need to do 731 00:41:41,780 --> 00:41:46,100 is just modify this object's inner HTML. 732 00:41:46,100 --> 00:41:51,300 And the dialogue HTML will then be modified as well. 733 00:41:51,300 --> 00:41:55,500 So when this plug-in is then shown, which can happen 734 00:41:55,500 --> 00:41:59,820 and this is a new event that is new to this plug-in, 735 00:41:59,820 --> 00:42:03,380 but happens in every plug-in with the dialogue, when this is now shown, 736 00:42:03,380 --> 00:42:07,100 I'm going to call a function called fetch info. 737 00:42:07,100 --> 00:42:10,520 And this function is the meat of it here. 738 00:42:10,520 --> 00:42:14,930 I'm going to use that proc plug-in that we described before, which by the way, 739 00:42:14,930 --> 00:42:19,790 is really just a Node.js library that Cloud 9 is using here. 740 00:42:19,790 --> 00:42:21,730 >> So you can actually look up about how this 741 00:42:21,730 --> 00:42:25,340 works if you go into the Node.js documentation 742 00:42:25,340 --> 00:42:29,220 and look up the exec file method for processes there. 743 00:42:29,220 --> 00:42:33,110 I'm going to run this specific command, home Ubuntu workspace 744 00:42:33,110 --> 00:42:38,000 seminar, which is that same one, that same command that I created before. 745 00:42:38,000 --> 00:42:40,680 Provide to it a current working directory, just 746 00:42:40,680 --> 00:42:45,440 to be ultra safe in terms of the context of where this is running. 747 00:42:45,440 --> 00:42:49,150 And once that has been completed and returned, 748 00:42:49,150 --> 00:42:54,040 I'm going to run this function called parse output. 749 00:42:54,040 --> 00:42:54,540 OK. 750 00:42:54,540 --> 00:42:58,670 So this then is going to execute a command on the local, or rather 751 00:42:58,670 --> 00:43:01,700 the remote Ubuntu instance. 752 00:43:01,700 --> 00:43:03,490 When I get back some information, I'm then 753 00:43:03,490 --> 00:43:06,940 going to call a separate function called parse output, that 754 00:43:06,940 --> 00:43:13,790 has this signature here, err, stdout, stderr, 755 00:43:13,790 --> 00:43:15,910 and perform some computation on this. 756 00:43:15,910 --> 00:43:18,930 So if I received an error of some kind at all, 757 00:43:18,930 --> 00:43:22,340 I will actually check to see if error actually has some data. 758 00:43:22,340 --> 00:43:27,204 And if so, then I will modify the inner HTML of that content object, which 759 00:43:27,204 --> 00:43:28,995 is you recall, we connected to the dialogue 760 00:43:28,995 --> 00:43:32,210 at the instantiattion of that dialogue, or at the first drawing 761 00:43:32,210 --> 00:43:33,370 of that dialogue. 762 00:43:33,370 --> 00:43:35,650 I'm going to just say that some error has happened. 763 00:43:35,650 --> 00:43:37,140 >> Now this is overly simplistic. 764 00:43:37,140 --> 00:43:40,170 The error value will typically contain something that was useful, 765 00:43:40,170 --> 00:43:45,520 perhaps an error number and an error from the script itself. 766 00:43:45,520 --> 00:43:48,430 Or if the script wrote something to standard error, 767 00:43:48,430 --> 00:43:50,890 that data would be populated in that parameter as well. 768 00:43:50,890 --> 00:43:53,765 And I could be a little bit more careful about what error 769 00:43:53,765 --> 00:43:55,332 I'm actually showing people. 770 00:43:55,332 --> 00:43:57,415 But this simplistic example is good enough for now 771 00:43:57,415 --> 00:43:59,715 to at least see how all this functions. 772 00:43:59,715 --> 00:44:01,590 Otherwise if there is no error, then I'm just 773 00:44:01,590 --> 00:44:05,500 going to provide the raw output of that function 774 00:44:05,500 --> 00:44:10,070 into the inner HTML of this content element, and then update my plug-in 775 00:44:10,070 --> 00:44:12,490 and show it here. 776 00:44:12,490 --> 00:44:17,550 And that's pretty much all that's necessary to get this to run. 777 00:44:17,550 --> 00:44:22,860 And so let's think about then how this operates, overall. 778 00:44:22,860 --> 00:44:29,330 When I first loaded this plug-in, just like the first plug-in, 779 00:44:29,330 --> 00:44:32,670 I'm going to add a command that's available to anything, to any plug-in 780 00:44:32,670 --> 00:44:37,120 in Cloud 9, called CS50 Seminar Dialog 2, whose responsibility 781 00:44:37,120 --> 00:44:39,670 will be to run this show dialogue, which is you recall, 782 00:44:39,670 --> 00:44:42,730 will actually show the dialogue that I requested below. 783 00:44:42,730 --> 00:44:45,980 >> Then I will add that command into a window menu 784 00:44:45,980 --> 00:44:48,070 so that I have access to that. 785 00:44:48,070 --> 00:44:51,420 And when that dialogue is requested to be shown, 786 00:44:51,420 --> 00:44:55,170 I will fetch some info from the underlying Ubuntu instance 787 00:44:55,170 --> 00:44:58,890 by using the exec file command. 788 00:44:58,890 --> 00:44:59,920 Excuse me. 789 00:44:59,920 --> 00:45:04,140 Once that is returned and I receive some information, then on the client side 790 00:45:04,140 --> 00:45:08,370 again, I will be able to parse the output of that command 791 00:45:08,370 --> 00:45:12,650 and update the inner HTML of the elements 792 00:45:12,650 --> 00:45:16,440 that we had connected to earlier. 793 00:45:16,440 --> 00:45:19,910 >> And with that, we then have this fully functional plug-in 794 00:45:19,910 --> 00:45:24,520 that allows me to fetch information from this arbitrary script 795 00:45:24,520 --> 00:45:27,170 that we have created on our underlying instance. 796 00:45:27,170 --> 00:45:29,660 But again, it's really important and really key 797 00:45:29,660 --> 00:45:33,030 to separate out where each of these things is happening, 798 00:45:33,030 --> 00:45:38,320 that we have all of this client side code that is being run in the browser, 799 00:45:38,320 --> 00:45:41,640 and doesn't yet have access to the underlying file system 800 00:45:41,640 --> 00:45:44,895 until we actually run some of these commands that are provided by the Cloud 801 00:45:44,895 --> 00:45:49,055 9 SDK like proc, and some other ones that allow us to read some data, 802 00:45:49,055 --> 00:45:53,500 or read some files if we need to do anything of the kind. 803 00:45:53,500 --> 00:45:56,650 >> Now this is a somewhat simple example. 804 00:45:56,650 --> 00:46:00,570 There are other things that we would perhaps want to do as well. 805 00:46:00,570 --> 00:46:03,470 For example, perhaps we actually want to save some information 806 00:46:03,470 --> 00:46:04,630 to the preferences. 807 00:46:04,630 --> 00:46:07,900 Or perhaps we want to add a new preference pane 808 00:46:07,900 --> 00:46:09,690 or something along those lines. 809 00:46:09,690 --> 00:46:13,370 Then that is something that you can take a look at the Cloud 9 SDK 810 00:46:13,370 --> 00:46:15,300 to get more information on. 811 00:46:15,300 --> 00:46:19,990 But this really is enough to get started. 812 00:46:19,990 --> 00:46:26,410 So just to be a little bit more concrete about the way that some of these things 813 00:46:26,410 --> 00:46:31,370 function, I did want to show just one more example, which is just some 814 00:46:31,370 --> 00:46:35,580 of the code from the Stats 50 plug-in. 815 00:46:35,580 --> 00:46:39,780 >> And this code is basically based on these examples 816 00:46:39,780 --> 00:46:43,310 that you've actually seen, but has some more safeguards 817 00:46:43,310 --> 00:46:47,460 and has some more complexity in order to achieve some of the additional things 818 00:46:47,460 --> 00:46:48,930 that we want to achieve. 819 00:46:48,930 --> 00:46:54,510 For example, if I want to be able to save some settings, 820 00:46:54,510 --> 00:46:57,700 then I need to have access to the Settings plug-in, 821 00:46:57,700 --> 00:47:01,820 and every time I want to read some settings, 822 00:47:01,820 --> 00:47:08,340 I can, for example, attach to various events in the Settings plug-in. 823 00:47:08,340 --> 00:47:13,630 So every time the settings is red, for example, in my own plug-in, 824 00:47:13,630 --> 00:47:18,450 if I am going to read some settings from the saved storage 825 00:47:18,450 --> 00:47:24,540 preferences of the user, then I can set defaults for a specific location, 826 00:47:24,540 --> 00:47:31,250 for specific preference, in that JSON style options file that we've 827 00:47:31,250 --> 00:47:33,890 saved earlier, that we've seen earlier. 828 00:47:33,890 --> 00:47:36,370 >> And if I'm going to write some settings to it, 829 00:47:36,370 --> 00:47:40,440 then I can-- or as soon as we detect that the settings have been written 830 00:47:40,440 --> 00:47:44,420 to-- because for example, those settings have been modified by the user 831 00:47:44,420 --> 00:47:47,335 either directly in their settings file, or the preference pane 832 00:47:47,335 --> 00:47:49,370 has changed the settings file directly, then 833 00:47:49,370 --> 00:47:53,590 I can actually update some of the code or update the behavior of my plug-in 834 00:47:53,590 --> 00:47:58,710 based on those changes that have occurred on the settings file as well. 835 00:47:58,710 --> 00:48:03,380 But really, the rest of it is pretty much this that you've already seen. 836 00:48:03,380 --> 00:48:06,040 >> We add some, perhaps something that's new. 837 00:48:06,040 --> 00:48:09,440 So we add a preference file, or rather a preference pane, 838 00:48:09,440 --> 00:48:14,250 to the preferences window, which again you can find out more information 839 00:48:14,250 --> 00:48:16,220 in the Cloud 9 SDK read me. 840 00:48:16,220 --> 00:48:18,460 But everything else is pretty much, pretty 841 00:48:18,460 --> 00:48:25,810 similar to what we saw before, just with some additional error checking 842 00:48:25,810 --> 00:48:30,150 and some additional protections and some additional functionality 843 00:48:30,150 --> 00:48:33,314 to feature all of the various things that we've seen. 844 00:48:33,314 --> 00:48:35,230 If you haven't actually seen it yet, you might 845 00:48:35,230 --> 00:48:40,955 be wondering what the underlying command is in the Stats 50 window. 846 00:48:40,955 --> 00:48:42,840 It's actually function. 847 00:48:42,840 --> 00:48:48,100 Well, it is-- oh, dammit. 848 00:48:48,100 --> 00:48:49,410 One second. 849 00:48:49,410 --> 00:48:49,910 Hold on. 850 00:48:49,910 --> 00:48:52,270 OK. 851 00:48:52,270 --> 00:48:58,090 Let me move this up so we can actually see what happens when I type Stats 50. 852 00:48:58,090 --> 00:49:02,140 Notice that in this case, the command that I'm out putting 853 00:49:02,140 --> 00:49:06,310 is really again, just the script that's going to output a bunch of information 854 00:49:06,310 --> 00:49:08,040 in JSON format. 855 00:49:08,040 --> 00:49:10,800 And the reason that we do it this way is that because we 856 00:49:10,800 --> 00:49:15,480 are operating, because we've written the client side code in JavaScript, 857 00:49:15,480 --> 00:49:19,500 we can very easily just parse JavaScript objects, 858 00:49:19,500 --> 00:49:23,050 and really be able to manipulate those objects just like we would 859 00:49:23,050 --> 00:49:24,610 any other JavaScript object. 860 00:49:24,610 --> 00:49:27,650 >> And so this is a very convenient way of providing some information 861 00:49:27,650 --> 00:49:31,950 from the underlying Ubuntu instance, such as the version number, the host 862 00:49:31,950 --> 00:49:36,360 name, whether a server is listening, what the server is, so on and so forth, 863 00:49:36,360 --> 00:49:39,150 and parse that very easily and very quickly 864 00:49:39,150 --> 00:49:44,870 in the plug-in that is then going to show us all of that information. 865 00:49:44,870 --> 00:49:47,920 So again, the key insight here to keep in mind 866 00:49:47,920 --> 00:49:54,260 is this separation between the underlying instance, 867 00:49:54,260 --> 00:49:57,490 and also where the code is being loaded. 868 00:49:57,490 --> 00:49:59,870 That when I have a client, it's first loading. 869 00:49:59,870 --> 00:50:03,951 Just this static JavaScript file from somewhere, perhaps CDN of some kind. 870 00:50:03,951 --> 00:50:06,450 We don't really have to care too much about this first step. 871 00:50:06,450 --> 00:50:08,970 >> We just know that it's running on the client side 872 00:50:08,970 --> 00:50:12,740 and that's when I'm going to communicate with this docker instance. 873 00:50:12,740 --> 00:50:15,970 That we're going to do so through the Cloud 9 SDK. 874 00:50:15,970 --> 00:50:20,460 We don't actually have the ability, using JavaScript or Node.js, 875 00:50:20,460 --> 00:50:21,750 to write directly to it. 876 00:50:21,750 --> 00:50:29,400 We just use those existing SDK APIs to do that action for us. 877 00:50:29,400 --> 00:50:32,490 And again, one of the really important things 878 00:50:32,490 --> 00:50:38,990 is that when I have created this, when I've created this plug-in, 879 00:50:38,990 --> 00:50:42,510 and as I am working on it, one of the important things to do 880 00:50:42,510 --> 00:50:44,840 is to bring up the JavaScript console. 881 00:50:44,840 --> 00:50:49,400 >> Because since this is all operating on the JavaScript, 882 00:50:49,400 --> 00:50:54,700 on the client side, if I use a console.log method-- so just 883 00:50:54,700 --> 00:50:56,550 to show an example here. 884 00:50:56,550 --> 00:51:07,630 Let's try modifying this simple plug-in to also log some data. 885 00:51:07,630 --> 00:51:09,895 And we'll add standard out. 886 00:51:09,895 --> 00:51:13,010 887 00:51:13,010 --> 00:51:16,810 So let's change that to be right here. 888 00:51:16,810 --> 00:51:19,560 Now when I execute console.log, keep in mind 889 00:51:19,560 --> 00:51:21,630 that since this is running on the client side, 890 00:51:21,630 --> 00:51:24,900 I will see this in my own JavaScript console, which 891 00:51:24,900 --> 00:51:28,540 is how I will then be able to try to troubleshoot and debug 892 00:51:28,540 --> 00:51:30,330 some of the problems that I have. 893 00:51:30,330 --> 00:51:34,110 >> Notice that because I am in SDK mode, I'm 894 00:51:34,110 --> 00:51:37,820 then able to manipulate plug-ins on this instance. 895 00:51:37,820 --> 00:51:39,800 So even though it is saved on this instance, 896 00:51:39,800 --> 00:51:47,130 this is the one example of that previous rule being violated, where the Cloud 9 897 00:51:47,130 --> 00:51:51,030 SDK will actually pull plug-ins from the underlying instance and then run them. 898 00:51:51,030 --> 00:51:54,440 So that in this way, I'm then able to manipulate and construct 899 00:51:54,440 --> 00:51:55,750 some plug-ins here. 900 00:51:55,750 --> 00:51:58,080 But in order for me to see updates to this plug-in, 901 00:51:58,080 --> 00:52:01,880 because it's on the client side, I need to save that plug-in 902 00:52:01,880 --> 00:52:04,950 and then reload the entire workspace, so that the new plug-in is then 903 00:52:04,950 --> 00:52:09,230 downloaded onto my client, onto my web browser, and then is being used. 904 00:52:09,230 --> 00:52:14,460 >> So now when I click on this Seminar Dialog 2, we still see this. 905 00:52:14,460 --> 00:52:21,311 But now hopefully in my JavaScript dialogue, should we see my-- wait, 906 00:52:21,311 --> 00:52:21,810 hold on. 907 00:52:21,810 --> 00:52:24,420 I might have to open the dialogue fresh. 908 00:52:24,420 --> 00:52:30,230 We should see my received data here. 909 00:52:30,230 --> 00:52:32,780 Received data, Hello, Dan, which is you recall, 910 00:52:32,780 --> 00:52:37,770 was a console.log operation that we requested in the plug-in. 911 00:52:37,770 --> 00:52:42,140 So this description then that I mentioned before, 912 00:52:42,140 --> 00:52:45,460 this dialogue, or this diagram rather, that I 913 00:52:45,460 --> 00:52:49,140 mentioned before is what happens. 914 00:52:49,140 --> 00:52:53,150 But there's an important exception only for development, 915 00:52:53,150 --> 00:52:55,490 which is that the plug-in itself might actually 916 00:52:55,490 --> 00:52:59,160 be stored on the docker instance temporarily, since presumably Cloud 9 917 00:52:59,160 --> 00:53:02,210 doesn't want us to be able to manipulate objects on their CDN. 918 00:53:02,210 --> 00:53:08,650 >> And the Cloud 9 clients, upon loading, will find those plug-ins in that . 919 00:53:08,650 --> 00:53:11,540 C9 plug-in folder, and load those. 920 00:53:11,540 --> 00:53:15,780 But those are still happening only on the client side. 921 00:53:15,780 --> 00:53:19,440 So then this is just the an exception that occurs only 922 00:53:19,440 --> 00:53:23,220 for development of Cloud 9 plug-ins. 923 00:53:23,220 --> 00:53:25,000 But the rest of the time-- and the reason 924 00:53:25,000 --> 00:53:26,708 that we want to really hammer this home-- 925 00:53:26,708 --> 00:53:30,140 is because most of the time this is going to be running from the CDN, 926 00:53:30,140 --> 00:53:33,030 and just going to be run purely from the client side. 927 00:53:33,030 --> 00:53:36,110 >> Normally there'll be no interaction with the plug-in, 928 00:53:36,110 --> 00:53:39,840 or there doesn't even have to be any reason that the plug-ins themselves 929 00:53:39,840 --> 00:53:42,970 are actually stored on the underlying docker instance, 930 00:53:42,970 --> 00:53:47,240 except in the case of this SDK development. 931 00:53:47,240 --> 00:53:51,510 So again, this changes just slightly because of the fact 932 00:53:51,510 --> 00:53:54,650 that we are running SDK mode. 933 00:53:54,650 --> 00:53:57,160 It's going to then load those plug-ins from development, 934 00:53:57,160 --> 00:54:01,690 and the sole purpose here is so that I can use Cloud 9 to do development 935 00:54:01,690 --> 00:54:04,620 for Cloud 9 plugins. 936 00:54:04,620 --> 00:54:07,220 But even so, this doesn't change again how any of this works. 937 00:54:07,220 --> 00:54:09,650 It's still being run entirely on the client side. 938 00:54:09,650 --> 00:54:16,260 >> It just means that whenever I want to create Cloud 9 plug-ins in Cloud 9, 939 00:54:16,260 --> 00:54:19,320 I create those plug-ins, put them in my . 940 00:54:19,320 --> 00:54:25,110 C9/plugins folder in my home directory, make sure I'm in SDK mode, 941 00:54:25,110 --> 00:54:29,290 reload the page every time I actually make changes to that plug-in, 942 00:54:29,290 --> 00:54:33,590 and see what happens in my JavaScript console. 943 00:54:33,590 --> 00:54:36,240 Just manage my JavaScript console to make sure 944 00:54:36,240 --> 00:54:38,930 that any troubleshooting information that I place to console, 945 00:54:38,930 --> 00:54:41,920 or anything else that might occur because of errors that I've written 946 00:54:41,920 --> 00:54:44,940 in my code or the like, appears there. 947 00:54:44,940 --> 00:54:48,007 >> And with that, it's really enough to get started, I think, 948 00:54:48,007 --> 00:54:49,090 with the Cloud 9 plug-ins. 949 00:54:49,090 --> 00:54:53,120 Especially taking a look at the SDK documentation that Cloud 9 provides. 950 00:54:53,120 --> 00:54:56,650 It's a great way to get started, and very easily 951 00:54:56,650 --> 00:54:59,900 create some plug-ins for Cloud 9. 952 00:54:59,900 --> 00:55:02,820 And with that, I want to thank you all very much for joining me. 953 00:55:02,820 --> 00:55:05,550 I hope you'll have fun writing plug-ins for Cloud 9. 954 00:55:05,550 --> 00:55:09,600 Perhaps improving plug-ins that we have now, or maybe even 955 00:55:09,600 --> 00:55:11,360 adding some functionality of your own. 956 00:55:11,360 --> 00:55:14,540 We look forward to seeing what it is you create. 957 00:55:14,540 --> 00:55:16,330 Until then, bye. 958 00:55:16,330 --> 00:55:18,734