private void    AsyncDeployAll()
        {
            for (int i = 0; i < ProfilesManager.Profile.projects.Count; i++)
            {
                try
                {
                    if (Directory.Exists(ProfilesManager.Profile.projects[i]) == true)
                    {
                        string unityVersion = Utility.GetUnityVersion(ProfilesManager.Profile.projects[i]);
                        if (string.IsNullOrEmpty(unityVersion) == false)
                        {
                            string unityExe = NGUnityDetectorWindow.GetUnityExecutable(this.unityInstalls, unityVersion);

                            if (File.Exists(unityExe) == true)
                            {
                                this.AsyncDeploy(ProfilesManager.Profile.projects[i]);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    InternalNGDebug.LogException("Deployment at \"" + ProfilesManager.Profile.projects[i] + "\" failed.", ex);
                }
            }
        }
        private void    CheckUnityProject(string path)
        {
            string error = null;

            if (Utility.IsUnityProject(path) == false)
            {
                error = "Path is not a valid Unity project.";
            }
            else
            {
                string unityVersion = Utility.GetUnityVersion(path);
                if (string.IsNullOrEmpty(unityVersion) == true)
                {
                    error = "Can't extract Unity version from \"" + path + "\".";
                }
                else
                {
                    string unityExe = NGUnityDetectorWindow.GetUnityExecutable(this.unityInstalls, unityVersion);

                    if (File.Exists(unityExe) == false)
                    {
                        error = "Can't find Unity Editor for version \"" + unityVersion + "\".";
                    }
                }
            }

            if (error == null)
            {
                if (this.errors.ContainsKey(path) == true)
                {
                    this.errors.Remove(path);
                }
            }
            else
            {
                if (this.errors.ContainsKey(path) == true)
                {
                    this.errors[path] = error;
                }
                else
                {
                    this.errors.Add(path, error);
                }
            }
        }
        private void    Draw(Rect rect, int index, bool isActive, bool isFocused)
        {
            string unityVersion = Utility.GetUnityVersion(ProfilesManager.Profile.projects[index]);
            float  width        = rect.width;

            rect.width = 55F;
            if (GUI.Button(rect, "Browse", "ButtonLeft") == true)
            {
                string projectPath = EditorUtility.OpenFolderPanel("Open Unity Project", ProfilesManager.Profile.projects[index], string.Empty);

                if (string.IsNullOrEmpty(projectPath) == false)
                {
                    ProfilesManager.Profile.projects[index] = projectPath;
                    this.CheckUnityProject(ProfilesManager.Profile.projects[index]);
                    GUI.FocusControl(null);
                }
            }

            rect.x    += rect.width;
            rect.width = 40F;
            if (GUI.Button(rect, "Open", "ButtonMid") == true)
            {
                Utility.ShowExplorer(ProfilesManager.Profile.projects[index]);
            }

            string error = null;

            if (this.packageFolderError != string.Empty)
            {
                error = this.packageFolderError;
                Utility.content.tooltip = this.packageFolderError;
            }
            else if (this.errors.TryGetValue(ProfilesManager.Profile.projects[index], out error) == true)
            {
                Utility.content.tooltip = error;
            }

            rect.x    += rect.width;
            rect.width = 40F;
            EditorGUI.BeginDisabledGroup(error != null);
            Utility.content.text = "Unity";
            if (GUI.Button(rect, Utility.content, "ButtonRight") == true)
            {
                if (Utility.IsUnityProject(ProfilesManager.Profile.projects[index]) == true)
                {
                    if (string.IsNullOrEmpty(unityVersion) == false)
                    {
                        string unityExe = NGUnityDetectorWindow.GetUnityExecutable(this.unityInstalls, unityVersion);

                        if (File.Exists(unityExe) == true)
                        {
                            Process.Start(unityExe, "-projectPath \"" + ProfilesManager.Profile.projects[index] + "\"");
                        }
                    }
                }
            }
            EditorGUI.EndDisabledGroup();

            Utility.content.text = unityVersion;

            rect.x    += rect.width;
            rect.width = width - 195F - GUI.skin.label.CalcSize(Utility.content).x;
            EditorGUI.BeginChangeCheck();
            ProfilesManager.Profile.projects[index] = EditorGUI.TextField(rect, ProfilesManager.Profile.projects[index], this.textStyle);
            if (EditorGUI.EndChangeCheck() == true)
            {
                this.CheckUnityProject(ProfilesManager.Profile.projects[index]);
                ProfilesManager.Save();
            }

            rect.x    += rect.width;
            rect.width = GUI.skin.label.CalcSize(Utility.content).x;

            GUI.Label(rect, unityVersion, this.labelStyle);

            rect.x    += rect.width;
            rect.width = 60F;

            int v = -1;

            lock (this.deployingProjects)
            {
                if (this.deployingProjects.TryGetValue(ProfilesManager.Profile.projects[index], out v) == true)
                {
                    if (v == 101)
                    {
                        Utility.content.text = "Pending";
                    }
                    else if (v == 102)
                    {
                        Utility.content.text = "Compiling";
                    }
                    else
                    {
                        Utility.content.text = v + "%";
                    }

                    this.Repaint();
                }
                else
                {
                    Utility.content.text = "Deploy";
                }
            }

            EditorGUI.BeginDisabledGroup(error != null || Utility.content.text != "Deploy");
            if (GUI.Button(rect, Utility.content) == true)
            {
                this.AsyncDeploy(ProfilesManager.Profile.projects[index]);
            }
            EditorGUI.EndDisabledGroup();

            if (error != null)
            {
                Utility.content.tooltip = string.Empty;
            }
        }
        private bool    CheckProjectCompile(string projectPath)
        {
            lock (this.deployingProjects)
            {
                this.deployingProjects.Add(projectPath, 101);
            }

            try
            {
                string unityVersion = Utility.GetUnityVersion(projectPath);
                if (string.IsNullOrEmpty(unityVersion) == true)
                {
                    return(false);
                }

                string unityExe = NGUnityDetectorWindow.GetUnityExecutable(this.unityInstalls, unityVersion);
                if (File.Exists(unityExe) == false)
                {
                    return(false);
                }

                string token = Guid.NewGuid().ToString();
                int    time;
                string tempLogPath = Path.GetTempPath() + token + ".log";

                lock (this.compileLock)
                {
                    time = Environment.TickCount;
                    lock (this.deployingProjects)
                    {
                        this.deployingProjects[projectPath] = 102;
                    }

                    InternalNGDebug.Log("Compiler Token " + token + " for \"" + projectPath + '"');

                    Process unityProcess = new Process();
                    unityProcess.StartInfo.WindowStyle     = ProcessWindowStyle.Hidden;
                    unityProcess.StartInfo.CreateNoWindow  = true;
                    unityProcess.StartInfo.UseShellExecute = false;
                    unityProcess.StartInfo.FileName        = unityExe;
                    unityProcess.StartInfo.Arguments       = "-nographics -batchmode -logFile \"" + tempLogPath + "\" -quit -projectPath \"" + projectPath + '"';

                    if (unityProcess.Start() == false)
                    {
                        InternalNGDebug.Log("Process Unity stopped with code " + unityProcess.ExitCode + ".");
                        return(false);
                    }

                    unityProcess.WaitForExit();

                    if (unityProcess.ExitCode == 1)
                    {
                        for (int j = 0; j < this.unityProcessesDetected.Count; j++)
                        {
                            if (this.unityProcessesDetected[j].Contains(unityVersion) == true)
                            {
                                InternalNGDebug.LogWarning("Unity " + unityVersion + " is running, deployment can not compile the project.");
                                return(false);
                            }
                        }

                        InternalNGDebug.LogError("Unity " + unityVersion + " has aborted.");
                        return(false);
                    }
                }

                using (FileStream fs = File.Open(tempLogPath, FileMode.Open, FileAccess.Read, FileShare.Read))
                    using (BufferedStream bs = new BufferedStream(fs))
                        using (StreamReader sr = new StreamReader(bs))
                        {
                            string line;

                            while ((line = sr.ReadLine()) != null)
                            {
                                // Token spotted.
                                if (line.Contains(token) == true)
                                {
                                    bool hasCompiled = false;

                                    while ((line = sr.ReadLine()) != null)
                                    {
                                        if (line.Contains("- starting compile") == true)
                                        {
                                            hasCompiled = true;
                                        }

                                        // Check compilation result.
                                        if (line.Contains("compilationhadfailure") == true)
                                        {
                                            if (line.Contains("True") == true)
                                            {
                                                InternalNGDebug.LogWarning("Project \"" + projectPath + "\" did not compile correctly. (" + ((Environment.TickCount - time) / 1000F).ToString("#.##") + "s)");
                                            }
                                            else
                                            {
                                                InternalNGDebug.LogWarning("Project \"" + projectPath + "\" compiled but have warnings. (" + ((Environment.TickCount - time) / 1000F).ToString("#.##") + "s)");
                                            }

                                            // Stop at errors.
                                            while ((line = sr.ReadLine()) != null)
                                            {
                                                if (line.Contains("CompilerOutput:-stderr") == true)
                                                {
                                                    break;
                                                }
                                            }

                                            while ((line = sr.ReadLine()) != null)
                                            {
                                                if (line.Length == 0)
                                                {
                                                    continue;
                                                }

                                                if (line.Contains("EndCompilerOutput") == true)
                                                {
                                                    break;
                                                }

                                                if (line[0] == '-')
                                                {
                                                    continue;
                                                }

                                                if (line.Contains("): warning CS"))
                                                {
                                                    Debug.LogWarning(line);
                                                }
                                                else
                                                {
                                                    Debug.LogError(line);
                                                }
                                            }

                                            return(true);
                                        }
                                    }

                                    if (hasCompiled == true)
                                    {
                                        InternalNGDebug.Log("Project \"" + projectPath + "\" compiled. (" + ((Environment.TickCount - time) / 1000F).ToString("#.##") + "s)");
                                    }
                                    else
                                    {
                                        InternalNGDebug.Log("Project \"" + projectPath + "\" has not changed. (" + ((Environment.TickCount - time) / 1000F).ToString("#.##") + "s)");
                                    }
                                    return(true);
                                }
                            }
                        }

                InternalNGDebug.LogWarning("Project \"" + projectPath + "\" did not found the token. (" + ((Environment.TickCount - time) / 1000F).ToString("#.##") + "s)");
                return(true);
            }
            catch (Exception ex)
            {
                InternalNGDebug.LogException(ex);
            }
            finally
            {
                lock (this.deployingProjects)
                {
                    this.deployingProjects.Remove(projectPath);
                }
            }

            return(false);
        }