{"action":"created","comment":{"url":"https://api.github.com/repos/opencor/opencor/pulls/comments/61057030","id":61057030,"diff_hunk":"@@ -305,335 +214,34 @@ void PmrWindowWindow::on_filterValue_textChanged(const QString &pText)\n \n void PmrWindowWindow::on_refreshButton_clicked()\n {\n-    // Get the list of exposures from the PMR after making sure that our\n-    // internal data has been reset\n-\n-    mWorkspaces.clear();\n-    mExposureUrls.clear();\n-    mExposureNames.clear();\n-    mExposureFileNames.clear();\n+    // Clear current list of exposures\n \n-    sendPmrRequest(ExposuresList);\n-}\n+    mExposures = PmrWindowExposures();\n \n-//==============================================================================\n+    // Get the list of exposures from the PMR\n \n-bool sortExposureFiles(const QString &pExposureFile1,\n-                       const QString &pExposureFile2)\n-{\n-    // Determine which of the two exposure files should be first (without\n-    // worrying about casing)\n-\n-    return pExposureFile1.compare(pExposureFile2, Qt::CaseInsensitive) < 0;\n+    mPmrWebService->requestExposuresList();\n }\n \n //==============================================================================\n \n-void PmrWindowWindow::finished(QNetworkReply *pNetworkReply)\n+void PmrWindowWindow::addExposure(const QString &pUrl, const QString &pName)\n {\n-    // Check whether our PMR request was successful\n-\n-    PmrRequest pmrRequest = pNetworkReply?PmrRequest(pNetworkReply->property(PmrRequestProperty).toInt()):ExposuresList;\n-    bool internetConnectionAvailable = true;\n-    QString errorMessage = QString();\n-    QString informationMessage = QString();\n-    PmrWindowExposures exposures = PmrWindowExposures();\n-    QString workspaceUrl = QString();\n-    QStringList exposureFileUrls = QStringList();\n-    QString exposureUrl = QString();\n-\n-    if (pNetworkReply) {\n-        if (pNetworkReply->error() == QNetworkReply::NoError) {\n-            // Retrieve and uncompress our JSON data\n-\n-            QByteArray compressedData = pNetworkReply->readAll();\n-            QByteArray uncompressedData = QByteArray();\n-            z_stream stream;\n-\n-            memset(&stream, 0, sizeof(z_stream));\n-\n-            if (inflateInit2(&stream, MAX_WBITS+16) == Z_OK) {\n-                static const int BufferSize = 32768;\n-\n-                Bytef buffer[BufferSize];\n-\n-                stream.next_in = (Bytef *) compressedData.data();\n-                stream.avail_in = compressedData.size();\n-\n-                do {\n-                    stream.next_out = buffer;\n-                    stream.avail_out = BufferSize;\n-\n-                    inflate(&stream, Z_NO_FLUSH);\n-\n-                    if (!stream.msg)\n-                        uncompressedData += QByteArray::fromRawData((char *) buffer, BufferSize-stream.avail_out);\n-                    else\n-                        uncompressedData = QByteArray();\n-                } while (!stream.avail_out);\n-\n-                inflateEnd(&stream);\n-            }\n-\n-            // Parse our uncompressed JSON data\n-\n-            QJsonParseError jsonParseError;\n-            QJsonDocument jsonDocument = QJsonDocument::fromJson(uncompressedData, &jsonParseError);\n-            QString url = pNetworkReply->url().toString();\n-\n-            if (jsonParseError.error == QJsonParseError::NoError) {\n-                // Check our PMR request to determine what we should do with the\n-                // data\n-\n-                QVariantMap collectionMap = jsonDocument.object().toVariantMap()[\"collection\"].toMap();\n-\n-                switch (pmrRequest) {\n-                case ExposuresList:\n-                    // Retrieve the list of exposures\n-\n-                    foreach (const QVariant &linksVariant, collectionMap[\"links\"].toList()) {\n-                        QVariantMap linksMap = linksVariant.toMap();\n-\n-                        if (!linksMap[\"rel\"].toString().compare(\"bookmark\")) {\n-                            QString exposureUrl = linksMap[\"href\"].toString().trimmed();\n-                            QString exposureName = linksMap[\"prompt\"].toString().simplified();\n-\n-                            if (   !exposureUrl.isEmpty()\n-                                && !exposureName.isEmpty()) {\n-                                mExposureNames.insert(exposureUrl, exposureName);\n-\n-                                exposures << PmrWindowExposure(exposureUrl, exposureName);\n-                            }\n-                        }\n-                    }\n-\n-                    std::sort(exposures.begin(), exposures.end());\n-\n-                    break;\n-                case ExposureInformation:\n-                    // Retrieve the URLs that will help us to retrieve some\n-                    // information about the exposure's workspace and exposure\n-                    // files\n-\n-                    exposureUrl = url;\n-\n-                    foreach (const QVariant &linksVariant, collectionMap[\"links\"].toList()) {\n-                        QVariantMap linksMap = linksVariant.toMap();\n-                        QString relValue = linksMap[\"rel\"].toString();\n+    // Add an exposure to our list of exposures\n \n-                        if (!relValue.compare(\"via\")) {\n-                            workspaceUrl = linksMap[\"href\"].toString().trimmed();\n-                        } else if (!relValue.compare(\"bookmark\")) {\n-                            QString exposureFileUrl = linksMap[\"href\"].toString().trimmed();\n-\n-                            if (!exposureFileUrl.isEmpty()) {\n-                                exposureFileUrls << exposureFileUrl;\n-\n-                                ++mNumberOfExposureFileUrlsLeft;\n-                            }\n-                        }\n-                    }\n-\n-                    // Make sure that we at least have a workspace\n-\n-                    if (workspaceUrl.isEmpty()) {\n-                        informationMessage = tr(\"No workspace URL could be found for <a href=\\\"%1\\\">%2</a>.\");\n-\n-                        break;\n-                    }\n-\n-                    // (Pretend) to show our exposure files in case this is what\n-                    // we ultimately want to do and in case we have no exposure\n-                    // files to show\n-                    // Note: indeed, this will result in an information message\n-                    //       being shown to tell us that there are no exposure\n-                    //       files. If we were not do the below, then we would\n-                    //       never get that message the first time we try to\n-                    //       show our exposure files (since that first time, we\n-                    //       would normally show our exposure files after having\n-                    //       retrieved the last exposure file information)...\n-\n-                    if (   exposureFileUrls.isEmpty()\n-                        && (Action(pNetworkReply->property(ActionProperty).toInt()) == ShowExposureFiles)) {\n-                        doShowExposureFiles(exposureUrl);\n-                    }\n-\n-                    // Retrieve the workspace and exposure file information from\n-                    // PMR\n-\n-                    mExposureUrls.insert(workspaceUrl, url);\n-\n-                    sendPmrRequest(WorkspaceInformation, workspaceUrl,\n-                                   Action(pNetworkReply->property(ActionProperty).toInt()));\n-\n-                    foreach (const QString &exposureFileUrl, exposureFileUrls) {\n-                        mExposureUrls.insert(exposureFileUrl, url);\n-\n-                        sendPmrRequest(ExposureFileInformation, exposureFileUrl,\n-                                       Action(pNetworkReply->property(ActionProperty).toInt()));\n-                    }\n-\n-                    break;\n-                case WorkspaceInformation: {\n-                    QVariantList itemsList = collectionMap[\"items\"].toList();\n-\n-                    exposureUrl = mExposureUrls.value(url);\n-\n-                    if (itemsList.count()) {\n-                        // Retrieve the ype of workspace we are dealing with\n-\n-                        QString storageValue = QString();\n-\n-                        foreach (const QVariant &dataVariant, itemsList.first().toMap()[\"data\"].toList()) {\n-                            QVariantMap dataMap = dataVariant.toMap();\n-\n-                            if (!dataMap[\"name\"].toString().compare(\"storage\")) {\n-                                storageValue = dataMap[\"value\"].toString();\n-\n-                                break;\n-                            }\n-                        }\n-\n-                        // Make sure that our workspace is a Git repository\n-\n-                        if (!storageValue.compare(\"git\")) {\n-                            // Retrieve the workspace URL from the workspace\n-                            // information, and keep track of it\n-\n-                            QString workspace = itemsList.first().toMap()[\"href\"].toString().trimmed();\n-\n-                            if (!workspace.isEmpty())\n-                                mWorkspaces.insert(exposureUrl, workspace);\n-                        } else {\n-                            informationMessage = tr(\"The workspace for <a href=\\\"%1\\\">%2</a> is not a Git repository.\");\n-                        }\n-                    } else {\n-                        informationMessage = tr(\"No workspace information could be found for <a href=\\\"%1\\\">%2</a>.\");\n-                    }\n-\n-                    break;\n-                }\n-                case ExposureFileInformation: {\n-                    bool hasExposureFileInformation = true;\n-                    QVariantList itemsList = collectionMap[\"items\"].toList();\n-\n-                    exposureUrl = mExposureUrls.value(url);\n-\n-                    if (itemsList.count()) {\n-                        QVariantList linksList = itemsList.first().toMap()[\"links\"].toList();\n-\n-                        if (linksList.count()) {\n-                            // Retrieve the exposure file name, from the\n-                            // exposure file information, and keep track of it\n-\n-                            QString exposureFile = linksList.first().toMap()[\"href\"].toString().trimmed();\n-\n-                            if (!exposureFile.isEmpty()) {\n-                                exposureUrl = mExposureUrls.value(url);\n-\n-                                mExposureFileNames.insertMulti(exposureUrl, exposureFile);\n-\n-                                --mNumberOfExposureFileUrlsLeft;\n-\n-                                // Ask our widget to add our exposure files,\n-                                // should we have no exposure file URL left to\n-                                // handle\n-\n-                                if (!mNumberOfExposureFileUrlsLeft) {\n-                                    QStringList exposureFileNames = mExposureFileNames.values(exposureUrl);\n-\n-                                    std::sort(exposureFileNames.begin(), exposureFileNames.end(), sortExposureFiles);\n-\n-                                    mPmrWidget->addExposureFiles(exposureUrl, exposureFileNames);\n-                                }\n-                            }\n-                        } else {\n-                            hasExposureFileInformation = false;\n-                        }\n-                    } else {\n-                        hasExposureFileInformation = false;\n-                    }\n-\n-                    if (!hasExposureFileInformation)\n-                        informationMessage = tr(\"No exposure file information could be found for <a href=\\\"%1\\\">%2</a>.\");\n-\n-                    break;\n-                }\n-                }\n-\n-                // Check whether something wrong happened during the processing\n-                // of our request\n-\n-                if (!informationMessage.isEmpty()) {\n-                    QMessageBox::information( Core::mainWindow(), windowTitle(),\n-                                              informationMessage.arg(exposureUrl, mExposureNames.value(exposureUrl))\n-                                             +\"<br/><br/>\"+mInformationNoteMessage,\n-                                              QMessageBox::Ok);\n-                }\n-            } else {\n-                errorMessage = jsonParseError.errorString();\n-            }\n-        } else {\n-            errorMessage = pNetworkReply->errorString();\n-        }\n-    } else {\n-        internetConnectionAvailable = false;\n-    }\n-\n-    // Some additional processing based on our PMR request\n-\n-    switch (pmrRequest) {\n-    case ExposuresList:\n-        // Ask our PMR widget to initialise itself\n-\n-        mPmrWidget->initialize(exposures, errorMessage,\n-                               mGui->filterValue->text(),\n-                               internetConnectionAvailable);\n-\n-        break;\n-    case ExposureInformation:\n-        // No additional processing needed\n-\n-        break;\n-    case WorkspaceInformation:\n-        // Clone the workspace, if possible and requested\n-\n-        if (   mWorkspaces.contains(exposureUrl)\n-            && (Action(pNetworkReply->property(ActionProperty).toInt()) == CloneWorkspace)) {\n-            doCloneWorkspace(mWorkspaces.value(exposureUrl));\n-        }\n-\n-        break;\n-    case ExposureFileInformation:\n-        // Show the exposure files, if possible and requested\n-\n-        if (   !mNumberOfExposureFileUrlsLeft\n-            &&  (Action(pNetworkReply->property(ActionProperty).toInt()) == ShowExposureFiles)) {\n-            doShowExposureFiles(exposureUrl);\n-        }\n-\n-        break;\n-    }\n-\n-    // Show ourselves as not busy anymore\n-\n-    busy(false);\n-\n-    // Delete (later) the network reply\n-\n-    if (pNetworkReply)\n-        pNetworkReply->deleteLater();\n+    mExposures << PmrWindowExposure(pUrl, pName);","path":"src/plugins/organisation/PMRWindow/src/pmrwindowwindow.cpp","position":537,"original_position":537,"commit_id":"df66a34263a951a97a8010b3f7b89aa714f8f693","original_commit_id":"df66a34263a951a97a8010b3f7b89aa714f8f693","user":{"login":"agarny","id":602265,"avatar_url":"https://avatars.githubusercontent.com/u/602265?v=3","gravatar_id":"","url":"https://api.github.com/users/agarny","html_url":"https://github.com/agarny","followers_url":"https://api.github.com/users/agarny/followers","following_url":"https://api.github.com/users/agarny/following{/other_user}","gists_url":"https://api.github.com/users/agarny/gists{/gist_id}","starred_url":"https://api.github.com/users/agarny/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/agarny/subscriptions","organizations_url":"https://api.github.com/users/agarny/orgs","repos_url":"https://api.github.com/users/agarny/repos","events_url":"https://api.github.com/users/agarny/events{/privacy}","received_events_url":"https://api.github.com/users/agarny/received_events","type":"User","site_admin":false},"body":"Surely, this could be improved? I mean that right now, this slot is going to be called 576 times! Couldn't we retrieve all the exposures and then have them emitted? This also means that we wouldn't have to clear the list of exposures in ```PmrWindowWindow::on_refreshButton_clicked()```.\r\n\r\nIn fact, I don't understand what ```mExposures``` is doing in ```PmrWindowWindow```. If anything, it ought to be in ```PmrWindowWidget``` since this is where it is actually used. So, all ```PmrWindowWindow``` should do is pass on the list of exposures onto ```PmrWindowWidget```.","created_at":"2016-04-26T09:43:28Z","updated_at":"2016-04-26T09:43:28Z","html_url":"https://github.com/opencor/opencor/pull/950#discussion_r61057030","pull_request_url":"https://api.github.com/repos/opencor/opencor/pulls/950","_links":{"self":{"href":"https://api.github.com/repos/opencor/opencor/pulls/comments/61057030"},"html":{"href":"https://github.com/opencor/opencor/pull/950#discussion_r61057030"},"pull_request":{"href":"https://api.github.com/repos/opencor/opencor/pulls/950"}}},"pull_request":{"url":"https://api.github.com/repos/opencor/opencor/pulls/950","id":67686781,"html_url":"https://github.com/opencor/opencor/pull/950","diff_url":"https://github.com/opencor/opencor/pull/950.diff","patch_url":"https://github.com/opencor/opencor/pull/950.patch","issue_url":"https://api.github.com/repos/opencor/opencor/issues/950","number":950,"state":"open","locked":false,"title":"#931: Separate out PMR web service interface into its own plugin.","user":{"login":"dbrnz","id":239220,"avatar_url":"https://avatars.githubusercontent.com/u/239220?v=3","gravatar_id":"","url":"https://api.github.com/users/dbrnz","html_url":"https://github.com/dbrnz","followers_url":"https://api.github.com/users/dbrnz/followers","following_url":"https://api.github.com/users/dbrnz/following{/other_user}","gists_url":"https://api.github.com/users/dbrnz/gists{/gist_id}","starred_url":"https://api.github.com/users/dbrnz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dbrnz/subscriptions","organizations_url":"https://api.github.com/users/dbrnz/orgs","repos_url":"https://api.github.com/users/dbrnz/repos","events_url":"https://api.github.com/users/dbrnz/events{/privacy}","received_events_url":"https://api.github.com/users/dbrnz/received_events","type":"User","site_admin":false},"body":"This has been build and tested under OS/X -- hopefully I haven't missed anything.","created_at":"2016-04-25T09:10:41Z","updated_at":"2016-04-26T09:43:28Z","closed_at":null,"merged_at":null,"merge_commit_sha":"662c8bbf4db7028fc62d0dec92bf5749a2633879","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/opencor/opencor/pulls/950/commits","review_comments_url":"https://api.github.com/repos/opencor/opencor/pulls/950/comments","review_comment_url":"https://api.github.com/repos/opencor/opencor/pulls/comments{/number}","comments_url":"https://api.github.com/repos/opencor/opencor/issues/950/comments","statuses_url":"https://api.github.com/repos/opencor/opencor/statuses/df66a34263a951a97a8010b3f7b89aa714f8f693","head":{"label":"dbrnz:pmrsupport","ref":"pmrsupport","sha":"df66a34263a951a97a8010b3f7b89aa714f8f693","user":{"login":"dbrnz","id":239220,"avatar_url":"https://avatars.githubusercontent.com/u/239220?v=3","gravatar_id":"","url":"https://api.github.com/users/dbrnz","html_url":"https://github.com/dbrnz","followers_url":"https://api.github.com/users/dbrnz/followers","following_url":"https://api.github.com/users/dbrnz/following{/other_user}","gists_url":"https://api.github.com/users/dbrnz/gists{/gist_id}","starred_url":"https://api.github.com/users/dbrnz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dbrnz/subscriptions","organizations_url":"https://api.github.com/users/dbrnz/orgs","repos_url":"https://api.github.com/users/dbrnz/repos","events_url":"https://api.github.com/users/dbrnz/events{/privacy}","received_events_url":"https://api.github.com/users/dbrnz/received_events","type":"User","site_admin":false},"repo":{"id":9968640,"name":"opencor","full_name":"dbrnz/opencor","owner":{"login":"dbrnz","id":239220,"avatar_url":"https://avatars.githubusercontent.com/u/239220?v=3","gravatar_id":"","url":"https://api.github.com/users/dbrnz","html_url":"https://github.com/dbrnz","followers_url":"https://api.github.com/users/dbrnz/followers","following_url":"https://api.github.com/users/dbrnz/following{/other_user}","gists_url":"https://api.github.com/users/dbrnz/gists{/gist_id}","starred_url":"https://api.github.com/users/dbrnz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dbrnz/subscriptions","organizations_url":"https://api.github.com/users/dbrnz/orgs","repos_url":"https://api.github.com/users/dbrnz/repos","events_url":"https://api.github.com/users/dbrnz/events{/privacy}","received_events_url":"https://api.github.com/users/dbrnz/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/dbrnz/opencor","description":"OpenCOR is a cross-platform modelling environment which can be used to organise, edit, simulate and analyse CellML files.","fork":true,"url":"https://api.github.com/repos/dbrnz/opencor","forks_url":"https://api.github.com/repos/dbrnz/opencor/forks","keys_url":"https://api.github.com/repos/dbrnz/opencor/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dbrnz/opencor/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dbrnz/opencor/teams","hooks_url":"https://api.github.com/repos/dbrnz/opencor/hooks","issue_events_url":"https://api.github.com/repos/dbrnz/opencor/issues/events{/number}","events_url":"https://api.github.com/repos/dbrnz/opencor/events","assignees_url":"https://api.github.com/repos/dbrnz/opencor/assignees{/user}","branches_url":"https://api.github.com/repos/dbrnz/opencor/branches{/branch}","tags_url":"https://api.github.com/repos/dbrnz/opencor/tags","blobs_url":"https://api.github.com/repos/dbrnz/opencor/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dbrnz/opencor/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dbrnz/opencor/git/refs{/sha}","trees_url":"https://api.github.com/repos/dbrnz/opencor/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dbrnz/opencor/statuses/{sha}","languages_url":"https://api.github.com/repos/dbrnz/opencor/languages","stargazers_url":"https://api.github.com/repos/dbrnz/opencor/stargazers","contributors_url":"https://api.github.com/repos/dbrnz/opencor/contributors","subscribers_url":"https://api.github.com/repos/dbrnz/opencor/subscribers","subscription_url":"https://api.github.com/repos/dbrnz/opencor/subscription","commits_url":"https://api.github.com/repos/dbrnz/opencor/commits{/sha}","git_commits_url":"https://api.github.com/repos/dbrnz/opencor/git/commits{/sha}","comments_url":"https://api.github.com/repos/dbrnz/opencor/comments{/number}","issue_comment_url":"https://api.github.com/repos/dbrnz/opencor/issues/comments{/number}","contents_url":"https://api.github.com/repos/dbrnz/opencor/contents/{+path}","compare_url":"https://api.github.com/repos/dbrnz/opencor/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dbrnz/opencor/merges","archive_url":"https://api.github.com/repos/dbrnz/opencor/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dbrnz/opencor/downloads","issues_url":"https://api.github.com/repos/dbrnz/opencor/issues{/number}","pulls_url":"https://api.github.com/repos/dbrnz/opencor/pulls{/number}","milestones_url":"https://api.github.com/repos/dbrnz/opencor/milestones{/number}","notifications_url":"https://api.github.com/repos/dbrnz/opencor/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dbrnz/opencor/labels{/name}","releases_url":"https://api.github.com/repos/dbrnz/opencor/releases{/id}","deployments_url":"https://api.github.com/repos/dbrnz/opencor/deployments","created_at":"2013-05-09T21:09:22Z","updated_at":"2015-04-26T19:00:27Z","pushed_at":"2016-04-25T20:25:32Z","git_url":"git://github.com/dbrnz/opencor.git","ssh_url":"git@github.com:dbrnz/opencor.git","clone_url":"https://github.com/dbrnz/opencor.git","svn_url":"https://github.com/dbrnz/opencor","homepage":"http://www.opencor.ws/","size":115992,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"opencor:master","ref":"master","sha":"d0d4c4f7b6782c7bdb4c1ef5f997681ed138a845","user":{"login":"opencor","id":754570,"avatar_url":"https://avatars.githubusercontent.com/u/754570?v=3","gravatar_id":"","url":"https://api.github.com/users/opencor","html_url":"https://github.com/opencor","followers_url":"https://api.github.com/users/opencor/followers","following_url":"https://api.github.com/users/opencor/following{/other_user}","gists_url":"https://api.github.com/users/opencor/gists{/gist_id}","starred_url":"https://api.github.com/users/opencor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/opencor/subscriptions","organizations_url":"https://api.github.com/users/opencor/orgs","repos_url":"https://api.github.com/users/opencor/repos","events_url":"https://api.github.com/users/opencor/events{/privacy}","received_events_url":"https://api.github.com/users/opencor/received_events","type":"Organization","site_admin":false},"repo":{"id":9957667,"name":"opencor","full_name":"opencor/opencor","owner":{"login":"opencor","id":754570,"avatar_url":"https://avatars.githubusercontent.com/u/754570?v=3","gravatar_id":"","url":"https://api.github.com/users/opencor","html_url":"https://github.com/opencor","followers_url":"https://api.github.com/users/opencor/followers","following_url":"https://api.github.com/users/opencor/following{/other_user}","gists_url":"https://api.github.com/users/opencor/gists{/gist_id}","starred_url":"https://api.github.com/users/opencor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/opencor/subscriptions","organizations_url":"https://api.github.com/users/opencor/orgs","repos_url":"https://api.github.com/users/opencor/repos","events_url":"https://api.github.com/users/opencor/events{/privacy}","received_events_url":"https://api.github.com/users/opencor/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/opencor/opencor","description":"OpenCOR is a cross-platform modelling environment, which can be used to organise, edit, simulate and analyse CellML files.","fork":false,"url":"https://api.github.com/repos/opencor/opencor","forks_url":"https://api.github.com/repos/opencor/opencor/forks","keys_url":"https://api.github.com/repos/opencor/opencor/keys{/key_id}","collaborators_url":"https://api.github.com/repos/opencor/opencor/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/opencor/opencor/teams","hooks_url":"https://api.github.com/repos/opencor/opencor/hooks","issue_events_url":"https://api.github.com/repos/opencor/opencor/issues/events{/number}","events_url":"https://api.github.com/repos/opencor/opencor/events","assignees_url":"https://api.github.com/repos/opencor/opencor/assignees{/user}","branches_url":"https://api.github.com/repos/opencor/opencor/branches{/branch}","tags_url":"https://api.github.com/repos/opencor/opencor/tags","blobs_url":"https://api.github.com/repos/opencor/opencor/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/opencor/opencor/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/opencor/opencor/git/refs{/sha}","trees_url":"https://api.github.com/repos/opencor/opencor/git/trees{/sha}","statuses_url":"https://api.github.com/repos/opencor/opencor/statuses/{sha}","languages_url":"https://api.github.com/repos/opencor/opencor/languages","stargazers_url":"https://api.github.com/repos/opencor/opencor/stargazers","contributors_url":"https://api.github.com/repos/opencor/opencor/contributors","subscribers_url":"https://api.github.com/repos/opencor/opencor/subscribers","subscription_url":"https://api.github.com/repos/opencor/opencor/subscription","commits_url":"https://api.github.com/repos/opencor/opencor/commits{/sha}","git_commits_url":"https://api.github.com/repos/opencor/opencor/git/commits{/sha}","comments_url":"https://api.github.com/repos/opencor/opencor/comments{/number}","issue_comment_url":"https://api.github.com/repos/opencor/opencor/issues/comments{/number}","contents_url":"https://api.github.com/repos/opencor/opencor/contents/{+path}","compare_url":"https://api.github.com/repos/opencor/opencor/compare/{base}...{head}","merges_url":"https://api.github.com/repos/opencor/opencor/merges","archive_url":"https://api.github.com/repos/opencor/opencor/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/opencor/opencor/downloads","issues_url":"https://api.github.com/repos/opencor/opencor/issues{/number}","pulls_url":"https://api.github.com/repos/opencor/opencor/pulls{/number}","milestones_url":"https://api.github.com/repos/opencor/opencor/milestones{/number}","notifications_url":"https://api.github.com/repos/opencor/opencor/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/opencor/opencor/labels{/name}","releases_url":"https://api.github.com/repos/opencor/opencor/releases{/id}","deployments_url":"https://api.github.com/repos/opencor/opencor/deployments","created_at":"2013-05-09T11:07:58Z","updated_at":"2016-04-14T22:20:14Z","pushed_at":"2016-04-26T09:35:26Z","git_url":"git://github.com/opencor/opencor.git","ssh_url":"git@github.com:opencor/opencor.git","clone_url":"https://github.com/opencor/opencor.git","svn_url":"https://github.com/opencor/opencor","homepage":"http://www.opencor.ws/","size":116379,"stargazers_count":14,"watchers_count":14,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":8,"mirror_url":null,"open_issues_count":76,"forks":8,"open_issues":76,"watchers":14,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/opencor/opencor/pulls/950"},"html":{"href":"https://github.com/opencor/opencor/pull/950"},"issue":{"href":"https://api.github.com/repos/opencor/opencor/issues/950"},"comments":{"href":"https://api.github.com/repos/opencor/opencor/issues/950/comments"},"review_comments":{"href":"https://api.github.com/repos/opencor/opencor/pulls/950/comments"},"review_comment":{"href":"https://api.github.com/repos/opencor/opencor/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/opencor/opencor/pulls/950/commits"},"statuses":{"href":"https://api.github.com/repos/opencor/opencor/statuses/df66a34263a951a97a8010b3f7b89aa714f8f693"}}}}