Guides/Webform-Integration-Sub-Folder.md
... ...
@@ -0,0 +1,481 @@
1
+#Izenda MVC Kit Integration Guide Phase I
2
+
3
+[[_TOC_]]
4
+
5
+##About
6
+
7
+This guide is designed to instruct first-time users how to integrate Izenda with simple MVC application.
8
+This guide will use Izenda mvc5r3 kit, a simple MVC application, which is downloadable at [http://wiki.izenda.us/Guides/MVC-Integration/Sample_MVCApp.zip](http://wiki.izenda.us/Guides/MVC-Integration/Sample_MVCApp.zip), and Visual Studio Express 2013 for Web.
9
+
10
+[mvc5r3 download link](http://archives.izenda.us/ri/mvc/mvc5r3/)
11
+##Instructions
12
+
13
+###Step 1. Open the simple MVC application in Visual Studio
14
+
15
+
16
+![Open the Application](/Guides/MVC-Integration/Open_Application.png)
17
+
18
+
19
+###Step 2. Add Izenda.AdHoc.dll and log4net.dll to the project’s reference
20
+
21
+Right click on 'References' under project name in Solution Explorer window, then click 'Add Reference'.
22
+
23
+Click the 'Browse' button and browse to \mvc5r3\bin, where Izenda.AdHoc.dll and log4net.dll are. Add them to reference.
24
+
25
+![DLL files](/Guides/MVC-Integration/DLLs.png)
26
+
27
+
28
+###Step 3. Add IzendaStaticResourcesController.cs and IzendaReportingController.cs to the project
29
+
30
+IzendaStaticResourcesController.cs and IzendaReportingController.cs are at mvc5r3\Controllers. Add them under Controllers as below (You can add by either 'drag and drop' or 'right click->Add->Existing Item)
31
+
32
+![Controllers](/Guides/MVC-Integration/Controllers.png)
33
+
34
+
35
+###Step 4. Change Namespaces of Controllers
36
+
37
+Change namespaces of IzendaStaticResourcesController.cs and IzendaReportingController.cs to match all other controllers in the application.
38
+Ex) if the namespace is in other controller file is ABC.Controllers, then MVC3SK.Controllers -> ABC.Controllers
39
+
40
+![Controllers](/Guides/MVC-Integration/Namespace.png)
41
+
42
+###Step 5. Add Reporting and Resources folders to the project
43
+
44
+**a.** Add 'Reporting'and 'Resources'from \mvc5r3 to project by dragging and dropping them in Solution Explorer as below
45
+
46
+![Controllers](/Guides/MVC-Integration/Resources_Reporting.png)
47
+
48
+**b.** In Solution Explorer, exclude Dashboards-Body.ascx and Dashboards-Head.ascx from \Resources\html by right click on them and click 'Exclude From Project'
49
+
50
+![Controllers](/Guides/MVC-Integration/Exclude.png)
51
+
52
+**c.** Copy /Resources folder from the root of the application into the /Reporting folder
53
+
54
+**d.** Copy rs.aspx from /Reporting and paste it in /Resources/html as below
55
+
56
+![](/Guides/MVC-Integration/rs.png)
57
+
58
+
59
+**** If Izenda toolbar icons don't appear, check if Reporting folder contains rs.aspx and Resources folder ****
60
+
61
+
62
+###Step 6. Add mvc5r3\Views\Reporting folder
63
+
64
+Add the Reporting folder in mvc5r3\Views to the project's Views
65
+
66
+![Controllers](/Guides/MVC-Integration/VR.png)
67
+
68
+###Step 7. Add _sitelayout to project’s Views\Shared
69
+
70
+Add _sitelayout from mvc5r3\Views\Shared to project’s Views\Shared
71
+
72
+![Controllers](/Guides/MVC-Integration/SiteLayout.png)
73
+
74
+###Step 8. Copy code from Global.asax except the first line
75
+
76
+**a.** Copy code from Global.asax except the first line
77
+
78
+###Global.asax from mvc5r3(C♯)
79
+
80
+```csharp
81
+
82
+<%@ Application Codebehind="Global.asax.cs" Inherits="MVC4Razor2.MvcApplication" Language="C#" %> //Copy except this line
83
+
84
+<%@ Import Namespace="Izenda.AdHoc"%>
85
+<%@ Import Namespace="System.IO"%>
86
+
87
+<script runat="server">
88
+ void Application_AcquireRequestState(object sender, EventArgs e) {
89
+ CustomAdHocConfig.InitializeReporting();
90
+ }
91
+
92
+ [Serializable]
93
+ public class CustomAdHocConfig : FileSystemAdHocConfig {
94
+ public static void InitializeReporting() {
95
+ if (HttpContext.Current.Session == null || HttpContext.Current.Session["ReportingInitialized"] != null)
96
+ return;
97
+ AdHocSettings.LicenseKey = "INSERT_LICENSE_KEY_HERE";
98
+ AdHocSettings.SqlServerConnectionString = @"INSERT_CONNECTION_STRING_HERE";
99
+ AdHocSettings.GenerateThumbnails = true;
100
+ AdHocSettings.ShowSimpleModeViewer = true;
101
+ AdHocSettings.IdentifiersRegex = "^.*[iI][Dd]$";
102
+ AdHocSettings.TabsCssUrl = "/Resources/css/tabs.css";
103
+ AdHocSettings.ReportCssUrl = "../Resources/css/Report.css";
104
+ AdHocSettings.ShowBetweenDateCalendar = true;
105
+ AdHocSettings.DashboardViewer = "Dashboards";
106
+ AdHocSettings.ReportViewer = "ReportViewer";
107
+ AdHocSettings.InstantReport = "InstantReport";
108
+ AdHocSettings.ReportDesignerUrl = "ReportDesigner";
109
+ AdHocSettings.DashboardDesignerUrl = "DashboardDesigner";
110
+ AdHocSettings.ReportList = "ReportList";
111
+ AdHocSettings.SettingsPageUrl = "Settings";
112
+ AdHocSettings.ParentSettingsUrl = "Settings";
113
+ AdHocSettings.ResponseServer = "rs.aspx";
114
+ AdHocSettings.ReportsPath = Path.Combine(HttpContext.Current.Server.MapPath("~/"), "Reports");
115
+ AdHocSettings.PrintMode = PrintMode.Html2PdfAndHtml;
116
+ AdHocSettings.ChartingEngine = ChartingEngine.HtmlChart;
117
+ AdHocSettings.AdHocConfig = new CustomAdHocConfig();
118
+ HttpContext.Current.Session["ReportingInitialized"] = true;
119
+ }
120
+ }
121
+</script>
122
+
123
+```
124
+
125
+**b.** Paste it in project’s Global.asax
126
+
127
+###Global.asax from Sample_MVCApp(C♯)
128
+```csharp
129
+<%@ Application Codebehind="Global.asax.cs" Inherits="Sample_MVCApp.MvcApplication" Language="C#" %>
130
+
131
+//THE BELOW IS PASTED CODE
132
+
133
+<%@ Import Namespace="Izenda.AdHoc"%>
134
+<%@ Import Namespace="System.IO"%>
135
+
136
+<script runat="server">
137
+ void Application_AcquireRequestState(object sender, EventArgs e) {
138
+ CustomAdHocConfig.InitializeReporting();
139
+ }
140
+
141
+ [Serializable]
142
+ public class CustomAdHocConfig : FileSystemAdHocConfig {
143
+ public static void InitializeReporting() {
144
+ if (HttpContext.Current.Session == null || HttpContext.Current.Session["ReportingInitialized"] != null)
145
+ return;
146
+ AdHocSettings.LicenseKey = "INSERT_LICENSE_KEY_HERE";
147
+ AdHocSettings.SqlServerConnectionString = @"INSERT_CONNECTION_STRING_HERE";
148
+ AdHocSettings.GenerateThumbnails = true;
149
+ AdHocSettings.ShowSimpleModeViewer = true;
150
+ AdHocSettings.IdentifiersRegex = "^.*[iI][Dd]$";
151
+ AdHocSettings.TabsCssUrl = "/Resources/css/tabs.css";
152
+ AdHocSettings.ReportCssUrl = "../Resources/css/Report.css";
153
+ AdHocSettings.ShowBetweenDateCalendar = true;
154
+ AdHocSettings.DashboardViewer = "Dashboards";
155
+ AdHocSettings.ReportViewer = "ReportViewer";
156
+ AdHocSettings.InstantReport = "InstantReport";
157
+ AdHocSettings.ReportDesignerUrl = "ReportDesigner";
158
+ AdHocSettings.DashboardDesignerUrl = "DashboardDesigner";
159
+ AdHocSettings.ReportList = "ReportList";
160
+ AdHocSettings.SettingsPageUrl = "Settings";
161
+ AdHocSettings.ParentSettingsUrl = "Settings";
162
+ AdHocSettings.ResponseServer = "rs.aspx";
163
+ AdHocSettings.ReportsPath = Path.Combine(HttpContext.Current.Server.MapPath("~/"), "Reports");
164
+ AdHocSettings.PrintMode = PrintMode.Html2PdfAndHtml;
165
+ AdHocSettings.ChartingEngine = ChartingEngine.HtmlChart;
166
+ AdHocSettings.AdHocConfig = new CustomAdHocConfig();
167
+ HttpContext.Current.Session["ReportingInitialized"] = true;
168
+ }
169
+ }
170
+</script>
171
+```
172
+
173
+
174
+###Step 9. Copy constraints classes from Global.asax.cs
175
+
176
+
177
+**a.** Copy below two constraints from Global.asax.cs of mvc5r3
178
+```csharp
179
+
180
+//IRouteConstraint
181
+public class SpecificFileRouterConstraint : IRouteConstraint {
182
+ private string extensionToBeRouted = null;
183
+ private string fileToBeRouted = null;
184
+
185
+ public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
186
+ return !String.IsNullOrEmpty(extensionToBeRouted) && !String.IsNullOrEmpty(fileToBeRouted) && values[extensionToBeRouted] != null && values[extensionToBeRouted].ToString().ToLower().Contains(fileToBeRouted);
187
+ }
188
+
189
+ public SpecificFileRouterConstraint() { }
190
+
191
+ public SpecificFileRouterConstraint(string extension, string fileName) {
192
+ extensionToBeRouted = extension.ToLower();
193
+ fileToBeRouted = fileName.ToLower();
194
+ }
195
+ }
196
+
197
+
198
+
199
+
200
+//IRouteConstraint
201
+public class IzendaResourceConstraint : IRouteConstraint {
202
+ private string extensionToBeRouted = null;
203
+
204
+ public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
205
+ if (String.IsNullOrEmpty(extensionToBeRouted) || values[extensionToBeRouted] == null) {
206
+ return false;
207
+ }
208
+ string requestUrl = values[extensionToBeRouted].ToString().ToLower();
209
+ bool result = false;
210
+ if (extensionToBeRouted == "js") {
211
+ result = result || requestUrl.Contains("reportviewerfilters.js");
212
+ result = result || requestUrl.Contains("reportlist.js");
213
+ result = result || requestUrl.Contains("data-sources.js");
214
+ result = result || requestUrl.Contains("data-sources-preview.js");
215
+ result = result || requestUrl.Contains("charts.js");
216
+ result = result || requestUrl.Contains("datasources-search.js");
217
+ result = result || requestUrl.Contains("jquery-1.6.1.min.js");
218
+ result = result || requestUrl.Contains("jquery-ui-1.8.13.custom.min.js");
219
+ result = result || requestUrl.Contains("elrte.full.js");
220
+ result = result || requestUrl.Contains("elrte.ru.js");
221
+ result = result || requestUrl.Contains("fieldproperties.js");
222
+ result = result || requestUrl.Contains("shrinkable-grid.js");
223
+ }
224
+ if (extensionToBeRouted == "css") {
225
+ result = result || requestUrl.Contains("tabs.css");
226
+ result = result || requestUrl.Contains("report.css");
227
+ result = result || requestUrl.Contains("filters.css");
228
+ result = result || requestUrl.Contains("base.css");
229
+ result = result || requestUrl.Contains("report-list-modal.css");
230
+ result = result || requestUrl.Contains("data-sources.css");
231
+ result = result || requestUrl.Contains("charts.css");
232
+ result = result || requestUrl.Contains("jquery-ui-1.8.13.custom.css");
233
+ result = result || requestUrl.Contains("elrte.min.css");
234
+ result = result || requestUrl.Contains("elrte-inner.css");
235
+ result = result || requestUrl.Contains("shrinkable-grid.css");
236
+ }
237
+ if (extensionToBeRouted == "png") {
238
+ result = result || requestUrl.Contains("elrtebg.png");
239
+ result = result || requestUrl.Contains("elrte-toolbar.png");
240
+ }
241
+ if (extensionToBeRouted == "gif") {
242
+ result = result || requestUrl.Contains("elrte/images/pixel.gif");
243
+ }
244
+ return result;
245
+ }
246
+
247
+ public IzendaResourceConstraint() { }
248
+
249
+ public IzendaResourceConstraint(string extension) {
250
+ extensionToBeRouted = extension.ToLower();
251
+ }
252
+ }
253
+
254
+```
255
+
256
+**b.** Paste it above MVCapplication class in Global.asax.cs of project
257
+
258
+```csharp
259
+
260
+namespace Sample_MVCApp
261
+{
262
+ public class SpecificFileRouterConstraint : IRouteConstraint
263
+ {
264
+ private string extensionToBeRouted = null;
265
+ private string fileToBeRouted = null;
266
+
267
+ public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
268
+ {
269
+ return !String.IsNullOrEmpty(extensionToBeRouted) && !String.IsNullOrEmpty(fileToBeRouted) && values[extensionToBeRouted] != null && values[extensionToBeRouted].ToString().ToLower().Contains(fileToBeRouted);
270
+ }
271
+
272
+ public SpecificFileRouterConstraint() { }
273
+
274
+ public SpecificFileRouterConstraint(string extension, string fileName)
275
+ {
276
+ extensionToBeRouted = extension.ToLower();
277
+ fileToBeRouted = fileName.ToLower();
278
+ }
279
+ }
280
+
281
+ public class IzendaResourceConstraint : IRouteConstraint
282
+ {
283
+ private string extensionToBeRouted = null;
284
+
285
+ public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
286
+ {
287
+ if (String.IsNullOrEmpty(extensionToBeRouted) || values[extensionToBeRouted] == null)
288
+ {
289
+ return false;
290
+ }
291
+ string requestUrl = values[extensionToBeRouted].ToString().ToLower();
292
+ bool result = false;
293
+ if (extensionToBeRouted == "js")
294
+ {
295
+ result = result || requestUrl.Contains("reportviewerfilters.js");
296
+ result = result || requestUrl.Contains("reportlist.js");
297
+ result = result || requestUrl.Contains("data-sources.js");
298
+ result = result || requestUrl.Contains("data-sources-preview.js");
299
+ result = result || requestUrl.Contains("charts.js");
300
+ result = result || requestUrl.Contains("datasources-search.js");
301
+ result = result || requestUrl.Contains("jquery-1.6.1.min.js");
302
+ result = result || requestUrl.Contains("jquery-ui-1.8.13.custom.min.js");
303
+ result = result || requestUrl.Contains("elrte.full.js");
304
+ result = result || requestUrl.Contains("elrte.ru.js");
305
+ result = result || requestUrl.Contains("fieldproperties.js");
306
+ result = result || requestUrl.Contains("shrinkable-grid.js");
307
+ }
308
+ if (extensionToBeRouted == "css")
309
+ {
310
+ result = result || requestUrl.Contains("tabs.css");
311
+ result = result || requestUrl.Contains("report.css");
312
+ result = result || requestUrl.Contains("filters.css");
313
+ result = result || requestUrl.Contains("base.css");
314
+ result = result || requestUrl.Contains("report-list-modal.css");
315
+ result = result || requestUrl.Contains("data-sources.css");
316
+ result = result || requestUrl.Contains("charts.css");
317
+ result = result || requestUrl.Contains("jquery-ui-1.8.13.custom.css");
318
+ result = result || requestUrl.Contains("elrte.min.css");
319
+ result = result || requestUrl.Contains("elrte-inner.css");
320
+ result = result || requestUrl.Contains("shrinkable-grid.css");
321
+ }
322
+ if (extensionToBeRouted == "png")
323
+ {
324
+ result = result || requestUrl.Contains("elrtebg.png");
325
+ result = result || requestUrl.Contains("elrte-toolbar.png");
326
+ }
327
+ if (extensionToBeRouted == "gif")
328
+ {
329
+ result = result || requestUrl.Contains("elrte/images/pixel.gif");
330
+ }
331
+ return result;
332
+ }
333
+
334
+ public IzendaResourceConstraint() { }
335
+
336
+ public IzendaResourceConstraint(string extension)
337
+ {
338
+ extensionToBeRouted = extension.ToLower();
339
+ }
340
+ }
341
+
342
+
343
+
344
+ // Note: For instructions on enabling IIS6 or IIS7 classic mode,
345
+ // visit http://go.microsoft.com/?LinkId=9394801
346
+
347
+ public class MvcApplication : System.Web.HttpApplication
348
+ {
349
+ protected void Application_Start()
350
+ {
351
+ AreaRegistration.RegisterAllAreas();
352
+
353
+ WebApiConfig.Register(GlobalConfiguration.Configuration);
354
+ FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
355
+ RouteConfig.RegisterRoutes(RouteTable.Routes);
356
+ BundleConfig.RegisterBundles(BundleTable.Bundles);
357
+ AuthConfig.RegisterAuth();
358
+ }
359
+ }
360
+}
361
+
362
+
363
+```
364
+
365
+
366
+###Step 10. Copy over RegisterRoutes in MvcApplication
367
+
368
+**a.** Copy the below class from Global.asax.cs of mvc5r3
369
+
370
+```csharp
371
+public static void RegisterRoutes(RouteCollection routes) {
372
+ routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
373
+ routes.MapRoute("IzendaResources", "Reporting/Resources/{*resource}", new { controller = "IzendaStaticResources", action = "Index" });
374
+ routes.MapRoute("IzendaJsResources", "{*js}", new { controller = "IzendaStaticResources", action = "Index" }, new { irc = new IzendaResourceConstraint("js") });
375
+ routes.MapRoute("IzendaCssResources", "{*css}", new { controller = "IzendaStaticResources", action = "Index" }, new { irc = new IzendaResourceConstraint("css") });
376
+ routes.MapRoute("IzendaPngResources", "{*png}", new { controller = "IzendaStaticResources", action = "Index" }, new { irc = new IzendaResourceConstraint("png") });
377
+ routes.MapRoute("IzendaGifResources", "{*gif}", new { controller = "IzendaStaticResources", action = "Index" }, new { irc = new IzendaResourceConstraint("gif") });
378
+ routes.MapRoute("IzendaReporting", "{controller}/{action}/{id}", new { controller = "Reporting", id = UrlParameter.Optional });
379
+ routes.MapRoute("StarterKitDefault", "{controller}/{action}/{id}", new { controller = "Reporting", action = "ReportList", id = UrlParameter.Optional });
380
+ routes.MapRoute("HomeDefault", "{*pathInfo}", new { controller = "Home", action = "Index", id = UrlParameter.Optional });
381
+ }
382
+```
383
+
384
+**b.** Paste it inside MvcApplication class of tproject’s Global.asax.cs
385
+
386
+```csharp
387
+public class MvcApplication : System.Web.HttpApplication
388
+ {
389
+
390
+ public static void RegisterRoutes(RouteCollection routes)
391
+ {
392
+ routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
393
+ routes.MapRoute("IzendaResources", "Reporting/Resources/{*resource}", new { controller = "IzendaStaticResources", action = "Index" });
394
+ routes.MapRoute("IzendaJsResources", "{*js}", new { controller = "IzendaStaticResources", action = "Index" }, new { irc = new IzendaResourceConstraint("js") });
395
+ routes.MapRoute("IzendaCssResources", "{*css}", new { controller = "IzendaStaticResources", action = "Index" }, new { irc = new IzendaResourceConstraint("css") });
396
+ routes.MapRoute("IzendaPngResources", "{*png}", new { controller = "IzendaStaticResources", action = "Index" }, new { irc = new IzendaResourceConstraint("png") });
397
+ routes.MapRoute("IzendaGifResources", "{*gif}", new { controller = "IzendaStaticResources", action = "Index" }, new { irc = new IzendaResourceConstraint("gif") });
398
+ routes.MapRoute("IzendaReporting", "{controller}/{action}/{id}", new { controller = "Reporting", id = UrlParameter.Optional });
399
+ routes.MapRoute("StarterKitDefault", "{controller}/{action}/{id}", new { controller = "Reporting", action = "ReportList", id = UrlParameter.Optional });
400
+ routes.MapRoute("HomeDefault", "{*pathInfo}", new { controller = "Home", action = "Index", id = UrlParameter.Optional });
401
+ }
402
+
403
+ protected void Application_Start()
404
+ {
405
+ AreaRegistration.RegisterAllAreas();
406
+
407
+ WebApiConfig.Register(GlobalConfiguration.Configuration);
408
+ FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
409
+ RouteConfig.RegisterRoutes(RouteTable.Routes);
410
+ BundleConfig.RegisterBundles(BundleTable.Bundles);
411
+ AuthConfig.RegisterAuth();
412
+ }
413
+ }
414
+
415
+```
416
+
417
+
418
+###Step 11. Change the LicenseKey and ConnnectionString in Global.asax of project
419
+
420
+ To get a new trial key, you may contact [sales@izenda.com](mailto:sales@izenda.com).
421
+
422
+```csharp
423
+
424
+AdHocSettings.LicenseKey = "INSERT_LICENSE_KEY_HERE";
425
+AdHocSettings.SqlServerConnectionString = @"INSERT_CONNECTION_STRING_HERE";
426
+
427
+```
428
+
429
+###Step 12. Run it!
430
+
431
+After Step#11, the Sample_MVCApp should build and work without a problem. To see if Izenda is integrated with this web application,
432
+
433
+**a.** Open _Layout.cshtml in Views\Shared\ in Solution Explorer
434
+
435
+**b.** Add an ActionLink which leads to Izenda as below
436
+
437
+```html
438
+<li>@Html.ActionLink("Home", "Index", "Home")</li>
439
+<li>@Html.ActionLink("About", "About", "Home")</li>
440
+<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
441
+<li>@Html.ActionLink("Izenda", "ReportList", "Reporting")</li> //Add this line
442
+```
443
+
444
+**c.** Notice 'Izenda' item added to the menu as below. Click it and see if it leads to Izenda ReportList page.
445
+
446
+![Test](/Guides/MVC-Integration/Test.PNG)
447
+
448
+
449
+###Step 13. Change the Logo
450
+
451
+**a.** Open _SiteLayout.cshtml in Views\Shared\ in Solution Explorer
452
+
453
+**b.** Find below two lines in the body of the html and edit the source image directory, alt, and the link address for top-right image
454
+
455
+```html
456
+<img src="~/Resources/FromDLL/Resources/ModernImages/bi-logo.png" alt="Business intelligence" /> //top-left image
457
+
458
+<a href="http://izenda.com" style="position: relative; top: 4px;"><img class="right-logo" src="~/Resources/FromDLL/Resources/ModernImages/IzendaNewLogoBlue.png" alt="Izenda Reports" /></a> //top-right image
459
+
460
+```
461
+**c.** Run the application and check if the images appear as edited.
462
+
463
+
464
+In this guide, two images, Logo.png and SeaEagle.png, were put in the project folder, /Sample_MVCApp, and the above two lines were edited as below
465
+
466
+```html
467
+<img src="~/Logo.png" alt="Angry Sea Eagle" /> //top-left image
468
+
469
+<a href="http://SeaEagle.com" style="position: relative; top: 4px;"><img class="right-logo" src="~/SeaEagle.png" alt="SeaEagle.Com" /></a> //top-right image
470
+```
471
+
472
+
473
+
474
+Two top logos have changed as below
475
+
476
+![Test](/Guides/MVC-Integration/Logo_Change2.png)
477
+
478
+[Izenda MVC Kit Integration Guide Phase II](http://wiki.izenda.us/Guides/MVC-Integration/Phase-II-Draft)
479
+
480
+
481
+
... ...
\ No newline at end of file