├── .gitignore
├── FireRating
├── DoorData.cs
├── FireRating.csproj
├── Properties
│ └── AssemblyInfo.cs
├── README.md
└── Util.cs
├── FireRatingClient
├── 2Up32.ico
├── App.config
├── FireRatingClient.csproj
├── Form1.Designer.cs
├── Form1.cs
├── Form1.resx
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── README.md
└── packages.config
├── FireRatingCloud.sln
├── FireRatingCloud
├── App.cs
├── BimUpdater.cs
├── Cmd_0_About.cs
├── Cmd_1_CreateAndBindSharedParameter.cs
├── Cmd_2a_ExportSharedParameterValues.cs
├── Cmd_2b_ExportSharedParameterValuesBatch.cs
├── Cmd_3_ImportSharedParameterValues.cs
├── Cmd_4_Subscribe.cs
├── DbAccessor.cs
├── DoorData.cs
├── FireRatingCloud.addin
├── FireRatingCloud.csproj
├── Icon
│ ├── 1Down.png
│ ├── 1Down16.png
│ ├── 1Down32.png
│ ├── 1Up.png
│ ├── 1Up16.png
│ ├── 1Up32.png
│ ├── 2Up.png
│ ├── 2Up16.png
│ ├── 2Up32.png
│ ├── Knot.png
│ ├── Knot16.png
│ ├── Knot32.png
│ ├── Question.png
│ ├── Question16.png
│ ├── Question32.png
│ ├── ZigZagRed.png
│ ├── ZigZagRed16.png
│ └── ZigZagRed32.png
├── Properties
│ └── AssemblyInfo.cs
├── Util.cs
├── exercise.txt
└── packages.config
├── LICENSE
├── README.md
└── img
├── ._fireratingcloud_architecture.png
├── firerating_2017_ribbon_tab.png
├── fireratingcloud_architecture.png
├── fireratingcloud_architecture.svg
└── fireratingcloud_architecture.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studo 2015 cache/options directory
26 | .vs/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | # NUNIT
33 | *.VisualState.xml
34 | TestResult.xml
35 |
36 | # Build Results of an ATL Project
37 | [Dd]ebugPS/
38 | [Rr]eleasePS/
39 | dlldata.c
40 |
41 | *_i.c
42 | *_p.c
43 | *_i.h
44 | *.ilk
45 | *.meta
46 | *.obj
47 | *.pch
48 | *.pdb
49 | *.pgc
50 | *.pgd
51 | *.rsp
52 | *.sbr
53 | *.tlb
54 | *.tli
55 | *.tlh
56 | *.tmp
57 | *.tmp_proj
58 | *.log
59 | *.vspscc
60 | *.vssscc
61 | .builds
62 | *.pidb
63 | *.svclog
64 | *.scc
65 |
66 | # Chutzpah Test files
67 | _Chutzpah*
68 |
69 | # Visual C++ cache files
70 | ipch/
71 | *.aps
72 | *.ncb
73 | *.opensdf
74 | *.sdf
75 | *.cachefile
76 |
77 | # Visual Studio profiler
78 | *.psess
79 | *.vsp
80 | *.vspx
81 |
82 | # TFS 2012 Local Workspace
83 | $tf/
84 |
85 | # Guidance Automation Toolkit
86 | *.gpState
87 |
88 | # ReSharper is a .NET coding add-in
89 | _ReSharper*/
90 | *.[Rr]e[Ss]harper
91 | *.DotSettings.user
92 |
93 | # JustCode is a .NET coding addin-in
94 | .JustCode
95 |
96 | # TeamCity is a build add-in
97 | _TeamCity*
98 |
99 | # DotCover is a Code Coverage Tool
100 | *.dotCover
101 |
102 | # NCrunch
103 | _NCrunch_*
104 | .*crunch*.local.xml
105 |
106 | # MightyMoose
107 | *.mm.*
108 | AutoTest.Net/
109 |
110 | # Web workbench (sass)
111 | .sass-cache/
112 |
113 | # Installshield output folder
114 | [Ee]xpress/
115 |
116 | # DocProject is a documentation generator add-in
117 | DocProject/buildhelp/
118 | DocProject/Help/*.HxT
119 | DocProject/Help/*.HxC
120 | DocProject/Help/*.hhc
121 | DocProject/Help/*.hhk
122 | DocProject/Help/*.hhp
123 | DocProject/Help/Html2
124 | DocProject/Help/html
125 |
126 | # Click-Once directory
127 | publish/
128 |
129 | # Publish Web Output
130 | *.[Pp]ublish.xml
131 | *.azurePubxml
132 | # TODO: Comment the next line if you want to checkin your web deploy settings
133 | # but database connection strings (with potential passwords) will be unencrypted
134 | *.pubxml
135 | *.publishproj
136 |
137 | # NuGet Packages
138 | *.nupkg
139 | # The packages folder can be ignored because of Package Restore
140 | **/packages/*
141 | # except build/, which is used as an MSBuild target.
142 | !**/packages/build/
143 | # Uncomment if necessary however generally it will be regenerated when needed
144 | #!**/packages/repositories.config
145 |
146 | # Windows Azure Build Output
147 | csx/
148 | *.build.csdef
149 |
150 | # Windows Store app package directory
151 | AppPackages/
152 |
153 | # Others
154 | *.[Cc]ache
155 | ClientBin/
156 | [Ss]tyle[Cc]op.*
157 | ~$*
158 | *~
159 | *.dbmdl
160 | *.dbproj.schemaview
161 | *.pfx
162 | *.publishsettings
163 | node_modules/
164 | bower_components/
165 |
166 | # RIA/Silverlight projects
167 | Generated_Code/
168 |
169 | # Backup & report files from converting an old project file
170 | # to a newer Visual Studio version. Backup files are not needed,
171 | # because we have git ;-)
172 | _UpgradeReport_Files/
173 | Backup*/
174 | UpgradeLog*.XML
175 | UpgradeLog*.htm
176 |
177 | # SQL Server files
178 | *.mdf
179 | *.ldf
180 |
181 | # Business Intelligence projects
182 | *.rdl.data
183 | *.bim.layout
184 | *.bim_*.settings
185 |
186 | # Microsoft Fakes
187 | FakesAssemblies/
188 |
189 | # Node.js Tools for Visual Studio
190 | .ntvs_analysis.dat
191 |
192 | # Visual Studio 6 build log
193 | *.plg
194 |
195 | # Visual Studio 6 workspace options file
196 | *.opt
197 |
--------------------------------------------------------------------------------
/FireRating/DoorData.cs:
--------------------------------------------------------------------------------
1 | #region Namespaces
2 | using System;
3 | #endregion // Namespaces
4 |
5 | namespace FireRating
6 | {
7 | public class DoorData
8 | {
9 | public string _id { get; set; }
10 | public string project_id { get; set; }
11 | public string level { get; set; }
12 | public string tag { get; set; }
13 | public double firerating { get; set; }
14 | public uint modified { get; set; }
15 |
16 |
17 | ///
18 | /// Constructor to populate instance by
19 | /// deserialising the REST GET response.
20 | ///
21 | public DoorData()
22 | {
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/FireRating/FireRating.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {40FF48AF-E87C-45B0-88BB-ED06ECEA8E10}
8 | Library
9 | Properties
10 | FireRating
11 | FireRating
12 | v4.5.2
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 | ..\packages\RestSharp.105.2.2\lib\net452\RestSharp.dll
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
52 |
--------------------------------------------------------------------------------
/FireRating/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("FireRating")]
9 | [assembly: AssemblyDescription( "FireRating utility library defining door data and HTTP REST access" )]
10 | [assembly: AssemblyConfiguration( "" )]
11 | [assembly: AssemblyCompany( "Autodesk Inc." )]
12 | [assembly: AssemblyProduct("FireRating")]
13 | [assembly: AssemblyCopyright( "Copyright 2016-2017 © Jeremy Tammik Autodesk Inc." )]
14 | [assembly: AssemblyTrademark( "" )]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("5651a014-5ac0-49e4-b074-f543e78b9307")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("2018.0.0.0")]
36 | [assembly: AssemblyFileVersion("2018.0.0.0")]
37 |
--------------------------------------------------------------------------------
/FireRating/README.md:
--------------------------------------------------------------------------------
1 | # FireRating
2 |
3 | FireRating is a C# .NET library used both by
4 | the [FireRatingCloud](https://github.com/jeremytammik/FireRatingCloud) Revit API add-in and
5 | the [FireRatingClient](https://github.com/jeremytammik/FireRatingCloud/tree/master/FireRatingClient) stand-alone Windows REST API client.
6 |
7 | ## Author
8 |
9 | Jeremy Tammik,
10 | [The Building Coder](http://thebuildingcoder.typepad.com) and
11 | [The 3D Web Coder](http://the3dwebcoder.typepad.com),
12 | [ADN](http://www.autodesk.com/adn)
13 | [Open](http://www.autodesk.com/adnopen),
14 | [Autodesk Inc.](http://www.autodesk.com)
15 |
16 | ## License
17 |
18 | This sample is licensed under the terms of the [MIT License](http://opensource.org/licenses/MIT).
19 | Please see the [LICENSE](../LICENSE) file for full details.
20 |
--------------------------------------------------------------------------------
/FireRating/Util.cs:
--------------------------------------------------------------------------------
1 | #region Namespaces
2 | using RestSharp;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.IO;
7 | using System.Net;
8 | using System.Security.Cryptography;
9 | #endregion // Namespaces
10 |
11 | namespace FireRating
12 | {
13 | public class Util
14 | {
15 | #region HTTP Access
16 | ///
17 | /// HTTP access constant to toggle
18 | /// between local and global server.
19 | ///
20 | public static bool UseLocalServer = false;
21 |
22 | // HTTP access constants.
23 |
24 | const string _base_url_local = "http://127.0.0.1:3001";
25 | const string _base_url_global = "http://fireratingdb.herokuapp.com";
26 | const string _api_version = "api/v1";
27 |
28 | ///
29 | /// Return REST API base URL.
30 | ///
31 | public static string RestApiBaseUrl
32 | {
33 | get
34 | {
35 | return UseLocalServer
36 | ? _base_url_local
37 | : _base_url_global;
38 | }
39 | }
40 |
41 | ///
42 | /// Return REST API URI.
43 | ///
44 | public static string RestApiUri
45 | {
46 | get
47 | {
48 | return RestApiBaseUrl + "/" + _api_version;
49 | }
50 | }
51 |
52 | ///
53 | /// PUT JSON document data into
54 | /// the specified mongoDB collection.
55 | ///
56 | public static HttpStatusCode Put(
57 | out string content,
58 | out string errorMessage,
59 | string collection_name_and_id,
60 | DoorData doorData )
61 | {
62 | var client = new RestClient( RestApiBaseUrl );
63 |
64 | var request = new RestRequest( _api_version + "/"
65 | + collection_name_and_id, Method.PUT );
66 |
67 | request.RequestFormat = DataFormat.Json;
68 |
69 | request.AddBody( doorData ); // uses JsonSerializer
70 |
71 | IRestResponse response = client.Execute( request );
72 |
73 | content = response.Content; // raw content as string
74 | errorMessage = response.ErrorMessage;
75 |
76 | return response.StatusCode;
77 | }
78 |
79 | ///
80 | /// GET JSON document data from
81 | /// the specified mongoDB collection.
82 | ///
83 | public static List Get(
84 | string collection_name_and_id )
85 | {
86 | var client = new RestClient( RestApiBaseUrl );
87 |
88 | var request = new RestRequest( _api_version + "/"
89 | + collection_name_and_id, Method.GET );
90 |
91 | IRestResponse> response
92 | = client.Execute>( request );
93 |
94 | return response.Data;
95 | }
96 |
97 | ///
98 | /// Delete all door data for this project
99 | /// from the specified mongoDB collection.
100 | ///
101 | public static string Delete(
102 | string collection_name_and_id )
103 | {
104 | var client = new RestClient( RestApiBaseUrl );
105 |
106 | var request = new RestRequest( _api_version + "/"
107 | + collection_name_and_id, Method.DELETE );
108 |
109 | IRestResponse response = client.Execute( request );
110 |
111 | return response.Content;
112 | }
113 |
114 | ///
115 | /// Batch PUT JSON document data into
116 | /// the specified mongoDB collection.
117 | ///
118 | public static HttpStatusCode PostBatch(
119 | out string content,
120 | out string errorMessage,
121 | string collection_name,
122 | List doorData )
123 | {
124 | var client = new RestClient( RestApiBaseUrl );
125 |
126 | var request = new RestRequest( _api_version + "/"
127 | + collection_name, Method.POST );
128 |
129 | request.RequestFormat = DataFormat.Json;
130 |
131 | request.AddBody( doorData ); // uses JsonSerializer
132 |
133 | IRestResponse response = client.Execute( request );
134 |
135 | content = response.Content; // raw content as string
136 | errorMessage = response.ErrorMessage;
137 |
138 | return response.StatusCode;
139 | }
140 |
141 | #region Project
142 | #if NEED_PROJECT_DOCUMENT
143 | ///
144 | /// Return the project database id for the given
145 | /// Revit document.
146 | ///
147 | public static string GetProjectDbId(
148 | Document doc )
149 | {
150 | string project_id = null;
151 |
152 | // Determine project database id.
153 |
154 | // Using the ProjectInformation UniqueId is
155 | // utterly unreliable, we can stop that right
156 | // away. Use computer name and full project
157 | // path instead for the time being.
158 |
159 | //string query = "projects/uid/"
160 | // + doc.ProjectInformation.UniqueId;
161 |
162 | // Using a query string does not work either.
163 |
164 | //string query = string.Format(
165 | // "projects?computername={0}&path={1}",
166 | // System.Environment.MachineName,
167 | // doc.PathName );
168 |
169 | //string query = string.Format(
170 | // "projects/pcnamepath/{0}+{1}",
171 | // System.Environment.MachineName,
172 | // doc.PathName );
173 |
174 | string query = string.Format(
175 | "projects/path/{0}",
176 | doc.PathName.Replace( '\\', '/' ) );
177 |
178 | string jsonResponse = Util.QueryOrUpsert( query,
179 | string.Empty, "GET" );
180 |
181 | if( 2 < jsonResponse.Length )
182 | {
183 | object obj = JsonParser.JsonDecode(
184 | jsonResponse );
185 |
186 | ArrayList a = obj as ArrayList;
187 |
188 | Debug.Assert( 1 == a.Count,
189 | "expected only one project entry for a given computer name and project path" );
190 |
191 | Debug.Assert( a[0] is Hashtable,
192 | "expected hash table entry for project document" );
193 |
194 | Hashtable d = a[0] as Hashtable;
195 |
196 | project_id = d["_id"] as string;
197 | }
198 | return project_id;
199 | }
200 | #endif // NEED_PROJECT_DOCUMENT
201 | #endregion Project
202 |
203 | ///
204 | /// Convert a string to a byte array.
205 | ///
206 | public static byte[] GetBytes( string str )
207 | {
208 | byte[] bytes = new byte[str.Length
209 | * sizeof( char )];
210 |
211 | System.Buffer.BlockCopy( str.ToCharArray(),
212 | 0, bytes, 0, bytes.Length );
213 |
214 | return bytes;
215 | }
216 |
217 | ///
218 | /// Convert a byte array to a string.
219 | ///
220 | static string GetString( byte[] bytes )
221 | {
222 | char[] chars = new char[bytes.Length / sizeof( char )];
223 | System.Buffer.BlockCopy( bytes, 0, chars, 0, bytes.Length );
224 | return new string( chars );
225 | }
226 |
227 | #region Test Code
228 | #if LOTS_OF_TEST_CODE
229 | ///
230 | /// Timeout for HTTP calls.
231 | ///
232 | //public static int Timeout = 1000;
233 |
234 | ///
235 | /// GET, PUT or POST JSON document data from or to
236 | /// the specified mongoDB collection.
237 | /// Obsolete method using HttpWebRequest, later
238 | /// replaced by more succinct code using RestSharp.
239 | ///
240 | public static string QueryOrUpsert(
241 | string collection_name_id_query,
242 | string json,
243 | string method )
244 | {
245 | string uri = Util.RestApiUri + "/"
246 | + collection_name_id_query;
247 |
248 | HttpWebRequest request = HttpWebRequest.Create(
249 | uri ) as HttpWebRequest;
250 |
251 | request.ContentType = "application/json; charset=utf-8";
252 | request.Accept = "application/json, text/javascript, */*";
253 | request.Timeout = Util.Timeout;
254 | request.Method = method;
255 |
256 | if( 0 < json.Length )
257 | {
258 | Debug.Assert( !method.Equals( "GET" ),
259 | "content is not allowed with GET" );
260 |
261 | using( StreamWriter writer = new StreamWriter(
262 | request.GetRequestStream() ) )
263 | {
264 | writer.Write( json );
265 | }
266 | }
267 | WebResponse response = request.GetResponse();
268 | Stream stream = response.GetResponseStream();
269 | string jsonResponse = string.Empty;
270 |
271 | using( StreamReader reader = new StreamReader(
272 | stream ) )
273 | {
274 | while( !reader.EndOfStream )
275 | {
276 | jsonResponse += reader.ReadLine();
277 | }
278 | }
279 | return jsonResponse;
280 | }
281 |
282 | ///
283 | /// POST JSON data to the specified mongoDB collection.
284 | ///
285 | async void PostJsonDataAsyncAttempt(
286 | string collection_name,
287 | string json )
288 | {
289 | using( System.Net.Http.HttpClient httpClient
290 | = new System.Net.Http.HttpClient() )
291 | {
292 | try
293 | {
294 | string resourceAddress = Util.RestApiUri
295 | + "/" + collection_name;
296 |
297 | string postBody = json;
298 |
299 | httpClient.DefaultRequestHeaders.Accept.Add(
300 | new MediaTypeWithQualityHeaderValue(
301 | "application/json" ) );
302 |
303 | HttpResponseMessage wcfResponse
304 | = await httpClient.PostAsync(
305 | resourceAddress, new StringContent(
306 | postBody, Encoding.UTF8,
307 | "application/json" ) );
308 |
309 | //await DisplayTextResult( wcfResponse, OutputField );
310 | }
311 | catch( HttpRequestException hre )
312 | {
313 | Util.Log( "Error:" + hre.Message );
314 | }
315 | catch( TaskCanceledException )
316 | {
317 | Util.Log( "Request canceled." );
318 | }
319 | catch( Exception ex )
320 | {
321 | Util.Log( ex.Message );
322 | }
323 | }
324 | }
325 |
326 | static async void DownloadPageAsync()
327 | {
328 | // ... Target page.
329 | string page = "http://en.wikipedia.org/";
330 |
331 | // ... Use HttpClient.
332 | using( HttpClient client = new HttpClient() )
333 | using( HttpResponseMessage response = await client.GetAsync( page ) )
334 | using( HttpContent content = response.Content )
335 | {
336 | // ... Read the string.
337 | string result = await content.ReadAsStringAsync();
338 |
339 | // ... Display the result.
340 | if( result != null &&
341 | result.Length >= 50 )
342 | {
343 | Console.WriteLine( result.Substring( 0, 50 ) + "..." );
344 | }
345 | }
346 | }
347 |
348 | #if FUTURE_SAMPLE_CODE
349 | static void DownloadPageAsync2( string[] args )
350 | {
351 | string uri = Util.RestApiUri;
352 |
353 | // Create an HttpClient instance
354 | HttpClient client = new HttpClient();
355 |
356 | // Send a request asynchronously continue when complete
357 | client.GetAsync( uri ).ContinueWith(
358 | ( requestTask ) =>
359 | {
360 | // Get HTTP response from completed task.
361 | HttpResponseMessage response = requestTask.Result;
362 |
363 | // Check that response was successful or throw exception
364 | response.EnsureSuccessStatusCode();
365 |
366 | // Read response asynchronously as JsonValue and write out top facts for each country
367 | response.Content.ReadAsAsync().ContinueWith(
368 | ( readTask ) =>
369 | {
370 | Console.WriteLine( "First 50 countries listed by The World Bank..." );
371 | foreach( var country in readTask.Result[1] )
372 | {
373 | Console.WriteLine( " {0}, Country Code: {1}, Capital: {2}, Latitude: {3}, Longitude: {4}",
374 | country.Value["name"],
375 | country.Value["iso2Code"],
376 | country.Value["capitalCity"],
377 | country.Value["latitude"],
378 | country.Value["longitude"] );
379 | }
380 | } );
381 | } );
382 |
383 | Console.WriteLine( "Hit ENTER to exit..." );
384 | Console.ReadLine();
385 | }
386 | #endif // FUTURE_SAMPLE_CODE
387 |
388 | #if USE_CODE_FROM_TWGL_EXPORT
389 | ///
390 | /// HTTP POST with the given JSON data in the
391 | /// request body. Use a local or global base URL.
392 | ///
393 | static public bool PostJsonData( string json )
394 | {
395 | bool rc = false;
396 |
397 | string uri = Util.RestApiUri + "/" + projects;
398 |
399 | HttpWebRequest req = WebRequest.Create( uri ) as HttpWebRequest;
400 |
401 | req.KeepAlive = false;
402 | req.Method = WebRequestMethods.Http.Post;
403 |
404 | // Turn our request string into a byte stream.
405 |
406 | byte[] postBytes = Encoding.UTF8.GetBytes( json );
407 |
408 | req.ContentLength = postBytes.Length;
409 |
410 | // Specify content type.
411 |
412 | req.ContentType = "application/json; charset=UTF-8"; // or just "text/json"?
413 | req.Accept = "application/json";
414 | req.ContentLength = postBytes.Length;
415 |
416 | Stream requestStream = req.GetRequestStream();
417 | requestStream.Write( postBytes, 0, postBytes.Length );
418 | requestStream.Close();
419 |
420 | HttpWebResponse res = req.GetResponse() as HttpWebResponse;
421 |
422 | string result;
423 |
424 | using( StreamReader reader = new StreamReader(
425 | res.GetResponseStream() ) )
426 | {
427 | result = reader.ReadToEnd();
428 | }
429 |
430 | // Get JavaScript modules from server public folder.
431 |
432 | result = result.Replace( "