AspNetParser.cs :  » Development » devAdvantage » AnticipatingMinds » Genesis » CodeParser » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Development » devAdvantage 
devAdvantage » AnticipatingMinds » Genesis » CodeParser » AspNetParser.cs
using System;
using System.Text;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using System.Web.RegularExpressions;
using AnticipatingMinds.Genesis.CodeDOM;
using AnticipatingMinds.Genesis.AspNetDom;
using AnticipatingMinds.Genesis.CodeDOM.Utilities;

namespace AnticipatingMinds.Genesis.CodeParser{
  /// <summary>
  /// Summary description for AspNetParser.
  /// </summary>
  [System.Security.Permissions.StrongNameIdentityPermissionAttribute(System.Security.Permissions.SecurityAction.LinkDemand,
     PublicKey=
     "00240000048000009400000006020000002400005253413100040000010001009D309779C258129573FC313836474C75C4CE9F4" +
     "107524FA0B9A6DB2E52754459C5A8946E4CBD5B98ACDB2413C5AFD38C1DF00C9A946713E867237B47F9D9CC473D4A853EACBEAB" + 
     "799EC0A271B468D4B6D52301A414A7772F05FEBD2BA7D0A2835F0D45E401C3C37F9E7B991D29F07DA88E20BB3839A34A2739AB6" + 
     "56B5204C8BC")]
  public class AspNetParser : CodeParser
  {
    private class TagAttribute
    {
      public string Name;
      public string Value;
      public int NamePosition;
      public int ValuePoisition;
    }

    public AspNetParser(string sourceCode,string fileName,CodeAssembly codeAssembly):base(sourceCode,fileName,codeAssembly)
    {
      this.sourceCode = sourceCode;
    }

    
    public override AnticipatingMinds.Genesis.CodeDOM.CodeAssemblyFile Parse(System.Threading.ManualResetEvent cancelEvent)
    {
      aspNetAssemblyFile = new AspNetAssemblyFile();
      aspNetAssemblyFile.Assembly = CodeAssembly;
      aspNetAssemblyFile.Language = CodeLanguage.AspNet;
      aspNetAssemblyFile.SourceFileName = FileName;
      aspNetAssemblyFile.Namespace.DeclaredTypes.Add(aspNetClassDeclaration);
      aspNetClassDeclaration.Name = GetAspClassNameFromFileName(FileName);
      aspNetClassDeclaration.SourcePosition = new CodeElementPosition(FileName,0,0,0);
      registeredNamespacePrefixes.Add("asp","System.Web.UI.WebControls");
      ParseAspNetElement();
      ParseRenderCodeBlocks(cancelEvent);
      ParseExpressions(cancelEvent);
      ParseScriptBlocks(cancelEvent);
      CodeCompileUnitUtils.RefreshCompileUnitElementsReferences(aspNetAssemblyFile);
      return aspNetAssemblyFile;
    }


    private void ParseRenderCodeBlocks(System.Threading.ManualResetEvent cancelEvent)
    {
      //Now lets parse snippets of code.
      StringBuilder renderingCode = new StringBuilder();
      renderingCode.Append('{');
      int lastPosition = 1;
      int lastLine = 1;
      int lastColumn = 1;
      foreach(CodeStatementSnippet codeSnippet in renderingSnippets)
      {
        int snippetPosition = (int) snippetPositions[codeSnippet];
        
        int line = 1;
        int column = 1;
        GetPositionLineAndColumn(snippetPosition,out line,out column);
        //append line symbols
        
        //reset last column if lines are different.
        if(line != lastLine)
        {
          //pad first:
          renderingCode.Append(' ',snippetPosition-lastPosition - (line - lastLine) - (column-1));
          if(line - lastLine > 0)
            renderingCode.Append('\r',line - lastLine);
          if(column-1 > 0)
            renderingCode.Append(' ',column-1);
        }
        else
        {
          renderingCode.Append(' ',snippetPosition-lastPosition);
        }

        lastLine = line;
        lastColumn = column;

        lastPosition = snippetPosition + codeSnippet.Text.Length;
        renderingCode.Append(codeSnippet.Text);
        renderingCode.Append(';'); // append empty statement in between every snippet
        lastPosition++;
      }
      renderingCode.Append('}');
      
      CSharpParser parser = new CSharpParser(renderingCode.ToString(),FileName,CodeAssembly);
      CodeStatementBlock statmentsBlock = new CodeStatementBlock();
      try
      {
        statmentsBlock = parser.ParseStatements(cancelEvent);
      }
      catch
      {
        //Ignore parse exceptions - they are not that important in Aspx code.
      }

      aspNetClassDeclaration.RenderStatements.AddRange(statmentsBlock.Statements);
    }

    private void ParseExpressions(System.Threading.ManualResetEvent cancelEvent)
    {
      foreach(CodeStatementSnippet expressionCode in expressionSnippets)
      {
        //Now lets parse snippets of code.
        StringBuilder renderingCode = new StringBuilder();

        int snippetPosition = (int) snippetPositions[expressionCode];
        int line = 1;
        int column = 1;
        GetPositionLineAndColumn(snippetPosition,out line,out column);
        //append line symbols

        //pad first:
        renderingCode.Append(' ',snippetPosition - (line-1) - (column-1));
        if(line > 1)
          renderingCode.Append('\r',line - 1);
        if(column > 1)
          renderingCode.Append(' ',column -1);

        renderingCode.Append(expressionCode.Text);
      
        CSharpParser parser = new CSharpParser(renderingCode.ToString(),FileName,CodeAssembly);
        CodeExpression expression = null;
        try
        {
          expression = parser.ParseExpression(cancelEvent);
        }
        catch
        {
          //Ignore parse exceptions - they are not that important in Aspx code.
        }

        aspNetClassDeclaration.EvaluatedExpressions.Add(expression);
      }
    }

    private void ParseScriptBlocks(System.Threading.ManualResetEvent cancelEvent)
    {
      foreach(CodeStatementSnippet scriptCode in scriptSnippets)
      {
        //Now lets parse snippets of code.
        StringBuilder renderingCode = new StringBuilder();
        renderingCode.Append("class A{");

        int snippetPosition = (int) snippetPositions[scriptCode] - 8;
        int line = 1;
        int column = 1;
        GetPositionLineAndColumn(snippetPosition,out line,out column);
        //append line symbols

        //pad first:
        renderingCode.Append(' ',snippetPosition - (line-1) - (column-1));
        if(line > 1)
          renderingCode.Append('\r',line - 1);
        if(column > 1)
          renderingCode.Append(' ',column -1);

        renderingCode.Append(scriptCode.Text);
        renderingCode.Append(" }");
        
      
        CSharpParser parser = new CSharpParser(renderingCode.ToString(),FileName,CodeAssembly);
        try
        {
          aspNetClassDeclaration.Members.AddRange( ((parser.Parse(cancelEvent) as CodeCompileUnit).Namespace.DeclaredTypes[0] as CodeClassDeclaration).Members);
        }
        catch
        {
          //Ignore parse exceptions - they are not that important in Aspx code.
        }
      }
    }

    public override System.CodeDom.Compiler.CompilerErrorCollection Errors
    {
      get
      {
        return errors;
      }
    }


    #region ASP Parsing

    private static Regex tagRegex = new TagRegex();
    private static Regex endtagRegex = new EndTagRegex();
    private static Regex textRegex = new TextRegex();
    private static Regex directiveRegex = new DirectiveRegex();
    private static Regex aspCodeRegex = new AspCodeRegex();
    private static Regex aspExprRegex = new AspExprRegex();
    private static Regex databindExprRegex = new DatabindExprRegex();
    private static Regex attributeDatabindExprRegex = new DataBindRegex();
    private static Regex serverCommentRegex = new CommentRegex();
    private static Regex xmlCommentRegex = new Regex(@"\G<!--(([^-]*)-)*?->", RegexOptions.Multiline | RegexOptions.Compiled);
    private static Regex includeRegex =  new IncludeRegex();
    private static Regex gtRegex = new GTRegex();
    private static Regex ltRegex = new LTRegex();
    private static Regex serverTagsRegex = new ServerTagsRegex();
    private static Regex runatServerRegex = new RunatServerRegex();

    bool inScriptTag = false;
    bool closeTagDoesNotCloseScript;

    private void ParseAspNetElement()
    {
      string text = SourceCode;
      int offset = 0;
      Match match;
      int scriptStartPosition = -1;
      do
      {
        //Skip text - we are not intrested in text.
        match = textRegex.Match(text, offset);
        if( match.Success )
        {
          offset = (match.Index + match.Length);
        }
        if( offset == text.Length )
        {
          break;
        }

        this.closeTagDoesNotCloseScript = false;
        if( ! this.inScriptTag )
        {
          match = directiveRegex.Match(text, offset);
          if( match.Success )
          {
            this.ProcessDirective(match);
            goto MOVE_OFFSET;
          }
        }

        //        match = includeRegex.Match(text, offset);
        //        if( match.Success )
        //        {
        //          //this.ProcessServerInclude(match);
        //        }
        //        else
      {
        match = serverCommentRegex.Match(text, offset);
        if( match.Success )
        {
          goto MOVE_OFFSET;
        }

        match = xmlCommentRegex.Match(text, offset);
        if( match.Success )
        {
          goto MOVE_OFFSET;
        }

        if( this.inScriptTag == false )
        {
          match = aspExprRegex.Match(text, offset);
          if( match.Success )
          {
            string code = SourceCode.Substring(match.Index,match.Length);
            int codeStartedPosition = code.IndexOf("=");
            if(codeStartedPosition != -1)
            {
              code = code.Substring(codeStartedPosition+1,code.LastIndexOf('%')-(codeStartedPosition+1));
              CodeStatementSnippet snippet = new CodeStatementSnippet(code);  
              expressionSnippets.Add(snippet);
              snippetPositions[snippet] = match.Index;
            }
            goto MOVE_OFFSET;
          }

          match = databindExprRegex.Match(text, offset);
          if( match.Success )
          {
            string code = SourceCode.Substring(match.Index,match.Length);
            int codeStartedPosition = code.IndexOf("#");
            if(codeStartedPosition != -1)
            {
              code = code.Substring(codeStartedPosition+1,code.LastIndexOf('%') - (codeStartedPosition+1));
              CodeStatementSnippet snippet = new CodeStatementSnippet(code);
              expressionSnippets.Add(snippet);
              snippetPositions[snippet] = match.Index;
            }
            goto MOVE_OFFSET;
          }

          match = aspCodeRegex.Match(text, offset);
          if( match.Success )
          {
            
            string code = SourceCode.Substring(match.Index,match.Length);
            int codeStartedPosition = code.IndexOf("%");
            if(codeStartedPosition != -1)
            {
              code = code.Substring(codeStartedPosition+1,code.LastIndexOf('%') - (codeStartedPosition+1));
              CodeStatementSnippet snippet = new CodeStatementSnippet(code);
              renderingSnippets.Add(snippet);
              snippetPositions[snippet] = match.Index + codeStartedPosition+1;
            }
            
            goto MOVE_OFFSET;
          }

          match = tagRegex.Match(text, offset);
          if( match.Success )
          {
            string tagName = match.Groups["tagname"].Value;
            IDictionary attributes = ProcessAttributes(match);
            //Process script block
            if(String.Compare(tagName,"script",true) == 0 && 
              attributes.Contains("runat") && 
              String.Compare("server",(attributes["runat"] as TagAttribute).Value,true) == 0)
            {
              scriptStartPosition = match.Index + match.Value.Length;
              inScriptTag = true;
              goto MOVE_OFFSET;
            }

            //Process server controls
            if((tagName.IndexOf(":") != -1) || (attributes.Contains("runat") && 
              String.Compare("server",(attributes["runat"] as TagAttribute).Value,true) == 0))
            {
              AspNetServerControl serverControl = new AspNetServerControl();
              RecordElementPosition(serverControl,match.Index);
              serverControl.Name = tagName;
              //Is it user control?
              if(userControlTagNames.Contains(serverControl.Name))
              {
                serverControl.ControlType = new CodeTypeReference(userControlTagNames[serverControl.Name] as string);
              }
              else
              {
                //Server control or HTML control?
                if(tagName.IndexOf(":") != -1)
                {
                  string namespacePrefix = tagName.Substring(0,tagName.IndexOf(":"));
                  string typeName = tagName.Substring(tagName.IndexOf(":")+1);
                  string controlTypeName = "";
                
                  if(registeredNamespacePrefixes.Contains(namespacePrefix))
                    controlTypeName = registeredNamespacePrefixes[namespacePrefix] + ".";

                  controlTypeName += typeName;
                  serverControl.ControlType = new CodeTypeReference(controlTypeName);
                }
                else
                {
                  switch(tagName.ToLower())
                  {
                    case "a":
                    {
                      serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlAnchor");
                      break;
                    }
                    case "button":
                    {
                      serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlButton");
                      break;
                    }
                    case "form":
                    {
                      serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlForm");
                      break;
                    }
                    case "img":
                    {
                      serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlImage");
                      break;
                    }
                    case "input":
                    {
                      string type = "";
                      if(attributes.Contains("type"))
                        type = attributes["type"] as String;

                      switch(type)
                      {
                        case "button":
                        case "submit":
                        case "reset":
                        {
                          serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlInputButton");
                          break;
                        }

                        case "checkbox":
                        {
                          serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlInputCheckBox");
                          break;
                        }
                        case "file":
                        {
                          serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlInputFile");
                          break;
                        }
                        case "hidden":
                        {
                          serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlInputHidden");
                          break;
                        }
                        case "image":
                        {
                          serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlInputImage");
                          break;
                        }
                        case "radio":
                        {
                          serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlInputRadioButton");
                          break;
                        }
                        case "password":
                        {
                          serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlInputText");
                          break;
                        }
                        default:
                        {
                          serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlInputControl");
                          break;
                        }
                      }
                      break;
                    }
                    case "select":
                    {
                      serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlSelect");
                      break;
                    }
                    case "table":
                    {
                      serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlTable");
                      break;
                    }
                    case "td":
                    case "th":
                    {
                      serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlTableCell");
                      break;
                    }
                    case "tr":
                    {
                      serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlTableRow");
                      break;
                    }
                    case "textarea":
                    {
                      serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlTextArea");
                      break;
                    }
                    default:
                    {
                      serverControl.ControlType = new CodeTypeReference("System.Web.UI.HtmlControls.HtmlGenericControl");
                      break;
                    }
                  }

                }
              }

              foreach(TagAttribute a in attributes.Values)
              {
                AspNetTagAttribute tagAttribute = new AspNetTagAttribute();
                RecordElementPosition(tagAttribute,a.NamePosition);
                tagAttribute.Name = new CodeUnresolvedReferenceExpression(a.Name);
                RecordElementPosition(tagAttribute.Name,a.NamePosition);
                
                tagAttribute.Value = new CodeUnresolvedReferenceExpression(a.Value);
                RecordElementPosition(tagAttribute.Value,a.ValuePoisition);

                serverControl.Attributes.Add(tagAttribute);
              }

              if(webControlsStack.Count != 0)
                (webControlsStack.Peek() as AspNetServerControl).NestedTags.Add(serverControl);
              else
                aspNetClassDeclaration.ServerControls.Add(serverControl);

              Group emptyTag = match.Groups["empty"];
              if( !emptyTag.Success )
              {
                webControlsStack.Push(serverControl);
              }
            }

            goto MOVE_OFFSET;
          }
        }

        match = endtagRegex.Match(text, offset);
        if( match.Success )
        {
          IDictionary attributes = ProcessAttributes(match);
          string tagName = match.Groups["tagname"].Value;
          if( IsScriptTagName(tagName) && inScriptTag)
          {
            string code = SourceCode.Substring(scriptStartPosition,match.Index - scriptStartPosition);
            CodeStatementSnippet snippet = new CodeStatementSnippet(code);
            scriptSnippets.Add(snippet);
            snippetPositions[snippet] = scriptStartPosition;
            scriptStartPosition = -1;
            inScriptTag = false;
          }

          //Process server controls closing tag
          if(tagName.IndexOf(":") != -1 && webControlsStack.Count != 0)
          {
            bool openTagFound = false;
            foreach(AspNetServerControl control in webControlsStack)
              if(String.Compare(control.Name,tagName,true) == 0)
              {
                openTagFound = true;
                break;
              }

            if(openTagFound)
              while(String.Compare((webControlsStack.Pop() as AspNetServerControl).Name,tagName,true) != 0)
              {
                ;
              }
          }
        }
      }
 
      MOVE_OFFSET:
        if( (match == null) || (!match.Success || this.closeTagDoesNotCloseScript) )
        {  
          offset = (offset + 1);
        }
        else
        {
          offset = (match.Index + match.Length);
        }
      }
      while (offset != text.Length);
    }


    private bool IsScriptTagName(string name)
    {
      return (CaseInsensitiveComparer.Default.Compare("SCRIPT", name) == 0);
    }

    private void ProcessDirective(Match directiveMatch)
    {
      IDictionary directives = ProcessAttributes(directiveMatch);
      if(directives.Contains("language"))
      {
        if(String.Compare((directives["language"] as TagAttribute).Value,"C#",true) == 0)
          aspNetAssemblyFile.InlineCodeLanguage = CodeLanguage.CSharp;
      }

      if(directives.Contains("Inherits"))
      {
        CodeTypeReference typeReference = new CodeTypeReference((directives["Inherits"] as TagAttribute).Value);
        RecordElementPosition(typeReference,(directives["Inherits"] as TagAttribute).ValuePoisition);
        aspNetClassDeclaration.BaseTypes.Insert(0,typeReference);
      }

      if(directives.Contains("Register"))
      {
        String tagPrefix = (directives["TagPrefix"] as TagAttribute).Value;
        if(directives.Contains("Namespace"))
        {
          //Namespace import
          //Associate prefix with manespace.
          string importedNamespace = (directives["Namespace"] as TagAttribute).Value;
          if(!registeredNamespacePrefixes.Contains(tagPrefix))
            registeredNamespacePrefixes.Add(tagPrefix,importedNamespace);
        }
        else
        {
          //User control import
          //associate full control name (prefix:name) with type
          string tagName = (directives["Tagname"] as TagAttribute).Value;
          string src = (directives["src"] as TagAttribute).Value;

          //Build the name of the file
          String currentFileFolder = Path.GetDirectoryName(FileName);
          if(src.Length > 0 && src[0] == '~')
          {
            currentFileFolder = Path.GetDirectoryName(CodeAssembly.ApplicationData["ProjectFileName"] as string);
            src = src.Substring(1);
            if(src[0] == '\\' || src[0] == '/')
              src = src.Substring(1);
          }
          if(Directory.Exists(currentFileFolder))
          {
            Directory.SetCurrentDirectory(currentFileFolder);
            string fullControlPath = Path.GetFullPath(src);
            string controlTypeName = GetAspClassNameFromFileName(fullControlPath);
            userControlTagNames[tagPrefix + ":" + tagName] = controlTypeName;
          }
        }
      }
      if(directives.Contains("Import"))
      {
        aspNetAssemblyFile.Namespace.Imports.Add(new CodeNamespaceImport((directives["namespace"] as TagAttribute).Value));
      }

      if(directives.Contains("Implements"))
      {
        CodeTypeReference typeReference = new CodeTypeReference((directives["interface"] as TagAttribute).Value);
        RecordElementPosition(typeReference,(directives["interface"] as TagAttribute).ValuePoisition);
        aspNetClassDeclaration.BaseTypes.Add(typeReference);
      }

    }


    private IDictionary ProcessAttributes(Match match)
    {
      Hashtable attributes = new Hashtable(CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
      CaptureCollection names = match.Groups["attrname"].Captures;
      CaptureCollection values = match.Groups["attrval"].Captures;
      for(int i = 0; i < names.Count; i ++)
      {
        Capture name = names[i];
        Capture value = values[i];
        TagAttribute attribute = new TagAttribute();
        attribute.Name = name.Value;
        attribute.Value = value.Value;
        attribute.NamePosition = name.Index;
        attribute.ValuePoisition = value.Index;

        if(attributes.Contains(name.Value))
          attributes[name.Value] = attribute;
        else
          attributes.Add(name.Value,attribute);
      }

      return attributes as IDictionary;
    }

    private void RecordElementPosition(CodeElement codeElment,int position)
    {
      codeElment.SourcePosition.Position = position;
      codeElment.CompileUnit = aspNetAssemblyFile;
      codeElment.SourcePosition.FileName = aspNetAssemblyFile.SourceFileName;
    }

    private void GetPositionLineAndColumn(int position,out int line, out int column)
    {
      line = 1;
      column = 1;
      int lastPosition = Math.Min(position,SourceCode.Length);
      for(int i = 0; i < lastPosition; i++)
      {
        column++;
        if(SourceCode[i] == 0x0A || SourceCode[i] == 0x2028 || SourceCode[i] == 0x2029)
        {
          line++;
          column = 1;
        }
      }
    }

    private string GetAspClassNameFromFileName(string fileName)
    {
      return fileName.Replace('.','_').Replace('\\','_').Replace('/','_').Replace(':','_');
    }
    #endregion

    private AspNetAssemblyFile aspNetAssemblyFile;
    private AspNetClassDeclaration aspNetClassDeclaration = new AspNetClassDeclaration();
    private System.CodeDom.Compiler.CompilerErrorCollection errors = new System.CodeDom.Compiler.CompilerErrorCollection();
    
    private CodeStatementCollection scriptSnippets = new CodeStatementCollection();
    private Hashtable registeredNamespacePrefixes = new Hashtable(CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
    private Hashtable userControlTagNames = new Hashtable(CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);

    private CodeStatementCollection expressionSnippets = new CodeStatementCollection();
    private CodeStatementCollection renderingSnippets = new CodeStatementCollection();
    private Hashtable snippetPositions = new Hashtable();

    private Stack webControlsStack = new Stack();
    private string sourceCode;
  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.