From 2de26b80e661a3e6a73c90eca6d4d0a0c8449eaa Mon Sep 17 00:00:00 2001 From: Steven Janzou Date: Mon, 6 Feb 2023 03:52:13 -0700 Subject: [PATCH 1/5] JSON UI forms for develop per GitHub issue SAM 504 --- .github/workflows/ci.yml | 40 ++++++++ CMakeLists.txt | 3 + include/wex/uiform.h | 15 ++- include/wex/utils.h | 14 +++ src/uiform.cpp | 201 ++++++++++++++++++++++++++++++++++++++- src/utils.cpp | 70 ++++++++++++-- 6 files changed, 334 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7275257f..8019630f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,6 +68,26 @@ jobs: run: | echo "LKDIR=$GITHUB_WORKSPACE/lk" >>$GITHUB_ENV echo "LKD_LIB=$GITHUB_WORKSPACE/lk/build_linux" >>$GITHUB_ENV # iff CMAKE_BUILD_TYPE=Debug + - name: Set RAPIDJSONDIR + run: | + echo "RAPIDJSONDIR=$GITHUB_WORKSPACE/ssc" >>$GITHUB_ENV + - name: Get git ref of sibling dependency SSC + run: | + ref=$(git ls-remote --exit-code git://github.com/NREL/ssc.git refs/heads/develop | awk '{print $1}') + echo "ref_of_ssc=$ref" | tee --append $GITHUB_ENV + - name: Get cached build data of sibling dependency SSC + uses: actions/cache@v2 + id: cachedssc + with: + path: ${{ env.GH_WORKSPACE }}/ssc + key: ${{ env.RUNS_ON }}-${{ env.ref_of_ssc }}-SSC + - name: Clone sibling dependency SSC + if: steps.cachedssc.outputs.cache-hit != 'true' + uses: actions/checkout@v2 + with: + ref: ${{ env.ref_of_ssc }} + path: ssc + repository: NREL/ssc - name: Checkout uses: actions/checkout@v2 @@ -150,6 +170,26 @@ jobs: run: | echo "LKDIR=$GITHUB_WORKSPACE/lk" >>$GITHUB_ENV echo "LKD_LIB=$GITHUB_WORKSPACE/lk/build_linux" >>$GITHUB_ENV # iff CMAKE_BUILD_TYPE=Debug + - name: Set RAPIDJSONDIR + run: | + echo "RAPIDJSONDIR=$GITHUB_WORKSPACE/ssc" >>$GITHUB_ENV + - name: Get git ref of sibling dependency SSC + run: | + ref=$(git ls-remote --exit-code git://github.com/NREL/ssc.git refs/heads/develop | awk '{print $1}') + echo "ref_of_ssc=$ref" | tee --append $GITHUB_ENV + - name: Get cached build data of sibling dependency SSC + uses: actions/cache@v2 + id: cachedssc + with: + path: ${{ env.GH_WORKSPACE }}/ssc + key: ${{ env.RUNS_ON }}-${{ env.ref_of_ssc }}-SSC + - name: Clone sibling dependency SSC + if: steps.cachedssc.outputs.cache-hit != 'true' + uses: actions/checkout@v2 + with: + ref: ${{ env.ref_of_ssc }} + path: ssc + repository: NREL/ssc - name: Checkout uses: actions/checkout@v2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a710400..35e126a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,9 @@ endif () # ##################################################################################################################### +# for rapidjson folder +include_directories($ENV{RAPIDJSONDIR}) + add_subdirectory(src) if (NOT SAM_SKIP_TOOLS) add_subdirectory(tools) diff --git a/include/wex/uiform.h b/include/wex/uiform.h index dfc17fe3..e127367a 100644 --- a/include/wex/uiform.h +++ b/include/wex/uiform.h @@ -37,6 +37,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include class wxUIProperty; @@ -120,6 +121,10 @@ class wxUIProperty { void Write_text(wxOutputStream &, wxString &); bool Read_text(wxInputStream &, wxString &); + + void Write_JSON(rapidjson::Document&, wxString &); + + bool Read_JSON(const rapidjson::Value&, wxString&); void AddUpdateInterface(const wxString &name, wxUIPropertyUpdateInterface *pui); @@ -220,6 +225,11 @@ class wxUIObject : public wxUIPropertyUpdateInterface { virtual void Write_text(wxOutputStream &, wxString &); virtual bool Read_text(wxInputStream &, wxString &); + + virtual void Write_JSON(rapidjson::Document&, wxString &); + + virtual bool Read_JSON(const rapidjson::Value&, wxString&); + protected: void AddProperty(const wxString &name, wxUIProperty *prop); @@ -314,13 +324,14 @@ class wxUIFormData { // load/save form definition virtual void Write(wxOutputStream &); - virtual bool Read(wxInputStream &); virtual void Write_text(wxOutputStream &, wxString &); - virtual bool Read_text(wxInputStream &, wxString &); + virtual void Write_JSON(rapidjson::Document&, wxString &); + virtual bool Read_JSON(const rapidjson::Document&, wxString&); + // methods to create/edit UI objects wxUIObject *Create(const wxString &type, const wxRect &geom, const wxString &name = wxEmptyString); diff --git a/include/wex/utils.h b/include/wex/utils.h index 6c102d97..615acfcd 100644 --- a/include/wex/utils.h +++ b/include/wex/utils.h @@ -37,9 +37,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include std::vector wxCommaDashListToIndices(const wxString &value); +void Write_JSON_value(rapidjson::Document& doc, wxString name, double value); + +void Write_JSON_value(rapidjson::Document& doc, wxString name, wxString value); + +void Write_JSON_multiline_value(rapidjson::Document& doc, wxString name, wxString value); + +wxString Read_JSON_multiline_value(const rapidjson::Value& doc, wxString name); + + +void Write_JSON_value(rapidjson::Document& doc, wxString name, wxArrayString value); + +wxString Read_JSON_value(const rapidjson::Value& doc, wxString name); + wxString wxLimitTextColumns(const wxString &str, size_t numcols); wxString wxConvertToBase26(unsigned int val); diff --git a/src/uiform.cpp b/src/uiform.cpp index ff8097d8..5ee1150f 100644 --- a/src/uiform.cpp +++ b/src/uiform.cpp @@ -1293,7 +1293,6 @@ bool wxUIProperty::Read(wxInputStream &_i) { return (code == in.Read8()); } - void wxUIProperty::Write_text(wxOutputStream &_o, wxString &ui_path) { wxExtTextOutputStream out(_o, wxEOL_UNIX); wxString s = wxEmptyString; @@ -1364,6 +1363,122 @@ void wxUIProperty::Write_text(wxOutputStream &_o, wxString &ui_path) { } } + +void wxUIProperty::Write_JSON(rapidjson::Document& doc, wxString &ui_path) +{ + wxString s = wxEmptyString; + wxString name; + rapidjson::Document json_table(&doc.GetAllocator()); // for table inside of json document. + json_table.SetObject(); + int type = GetType(); + Write_JSON_value(doc, "Type", type); + switch (type) { + case DOUBLE: { + Write_JSON_value(doc, "Double", GetDouble()); + } + break; + case BOOLEAN: { + if (GetBoolean()) + Write_JSON_value(doc, "Boolean", 1.0); + else + Write_JSON_value(doc, "Boolean", 0.0); + } + break; + case INTEGER: { + Write_JSON_value(doc, "Integer", GetInteger()); + } + break; + case STRING: { + Write_JSON_value(doc, "String", GetString()); + + } + break; + case COLOUR: { + wxColour c = GetColour(); + Write_JSON_value(json_table, "Red", c.Red()); + Write_JSON_value(json_table, "Green", c.Green()); + Write_JSON_value(json_table, "Blue", c.Blue()); + Write_JSON_value(json_table, "Alpha", c.Alpha()); + name = "Color"; + doc.AddMember(rapidjson::Value(name.c_str(), (unsigned int)name.size(), doc.GetAllocator()).Move(), json_table.Move(), doc.GetAllocator()); + } + break; + case STRINGLIST: { + Write_JSON_value(doc, "StringList", GetStringList()); + } + break; + case IMAGE: { + wxImage img = GetImage(); + img.SaveFile(ui_path + ".png", wxBITMAP_TYPE_PNG); + wxString fn = wxFileName(ui_path + ".png").GetName(); + Write_JSON_value(doc, "Image", fn + ".png"); + } + break; + } + +} + +bool wxUIProperty::Read_JSON(const rapidjson::Value& doc, wxString& ui_path) +{ + wxUint8 r, g, b, a; + bool ok = true; + int type = (int)doc["Type"].GetDouble(); + if (m_pReference) + m_pReference->m_type = type; + else + m_type = type; + + switch (type) { + case DOUBLE: + Set(doc["Double"].GetDouble()); + break; + case BOOLEAN: { + if ((int)doc["Boolean"].GetDouble() == 1) + Set(true); + else + Set(false); + } + break; + case INTEGER: + Set((int)doc["Integer"].GetDouble()); + break; + case STRING: + Set(Read_JSON_value(doc, "String")); + break; + case COLOUR: + for (rapidjson::Value::ConstMemberIterator itr = doc["Color"].GetObject().MemberBegin(); itr != doc["Color"].GetObject().MemberEnd(); ++itr) { + wxString name = wxString(itr->name.GetString()); + if (name == "Red") + r = (int)itr->value.GetDouble(); + else if (name == "Green") + g = (int)itr->value.GetDouble(); + else if (name == "Blue") + b = (int)itr->value.GetDouble(); + else if (name == "Alpha") + a = (int)itr->value.GetDouble(); + } + Set(wxColour(r, g, b, a)); + break; + case STRINGLIST: { + wxArrayString list = wxSplit(Read_JSON_value(doc, "StringList"), '|'); + Set(list); + } + break; + case IMAGE: { + wxImage img; + wxString img_filename = doc["Image"].GetString(); + img_filename = ui_path + img_filename; + img.LoadFile(img_filename, wxBITMAP_TYPE_PNG); + Set(img); + } + break; + } + + return ok; +} + + + bool wxUIProperty::Read_text(wxInputStream &_i, wxString &ui_path) { wxExtTextInputStream in(_i, "\n", wxConvAuto(wxFONTENCODING_UTF8)); wxUint16 type = in.Read16(); @@ -1680,6 +1795,44 @@ void wxUIObject::Write_text(wxOutputStream &_o, wxString &ui_path) { } + +void wxUIObject::Write_JSON(rapidjson::Document &doc, wxString &ui_path) +{ + if (m_visible) + Write_JSON_value(doc, "Visible", 1); + else + Write_JSON_value(doc, "Visible", 0); + rapidjson::Document json_objectproperties(&doc.GetAllocator()); // for table inside of json document. + json_objectproperties.SetObject(); + for (size_t i = 0; i < m_properties.size(); i++) { + rapidjson::Document json_uiproperty(&json_objectproperties.GetAllocator()); // for table inside of json document. + json_uiproperty.SetObject(); + m_properties[i].prop->Write_JSON(json_uiproperty, ui_path); + json_objectproperties.AddMember(rapidjson::Value(m_properties[i].name.c_str(), (unsigned int)m_properties[i].name.size(), json_objectproperties.GetAllocator()).Move(), json_uiproperty.Move(), json_objectproperties.GetAllocator()); + } + wxString name="ObjectProperties"; + doc.AddMember(rapidjson::Value(name.c_str(), (unsigned int)name.size(), doc.GetAllocator()).Move(), json_objectproperties.Move(), doc.GetAllocator()); +} + + +bool wxUIObject::Read_JSON(const rapidjson::Value &doc, wxString &ui_path) +{ + bool ok = true; + if ((int)doc["Visible"].GetDouble() == 1) + m_visible = true; + else + m_visible = false; + + auto json_objectproperties = doc["ObjectProperties"].GetObject(); + for (rapidjson::Value::ConstMemberIterator itr = json_objectproperties.MemberBegin(); itr != json_objectproperties.MemberEnd() && ok; ++itr) { + wxString name = itr->name.GetString(); + ok = ok && Property(name).Read_JSON(itr->value, ui_path); + } + return ok; + +} + + bool wxUIObject::Read_text(wxInputStream &_i, wxString &ui_path) { wxExtTextInputStream in(_i, "\n"); @@ -2213,9 +2366,55 @@ void wxUIFormData::Write_text(wxOutputStream &_O, wxString &ui_path) { o->Write_text(_O, ui_path); } } +} + +void wxUIFormData::Write_JSON(rapidjson::Document& doc, wxString &ui_path) +{ + Write_JSON_value(doc, "Name", m_name); + Write_JSON_value(doc, "Width", m_width); + Write_JSON_value(doc, "Height", m_height); + rapidjson::Document json_formobjects(&doc.GetAllocator()); // for table inside of json document. + json_formobjects.SetObject(); + wxUIObject *o; + wxArrayString as = ListAll(); + as.Sort(); + for (size_t i = 0; i < as.Count(); i++) { + o = Find(as[i]); + if (o != NULL) { + rapidjson::Document json_uiobject(&json_formobjects.GetAllocator()); // for table inside of json document. + json_uiobject.SetObject(); + o->Write_JSON(json_uiobject, ui_path); + json_formobjects.AddMember(rapidjson::Value(o->GetTypeName().c_str(), (unsigned int)o->GetTypeName().size(), json_formobjects.GetAllocator()).Move(), json_uiobject.Move(), json_formobjects.GetAllocator()); + } + } + wxString name="FormObjects"; + doc.AddMember(rapidjson::Value(name.c_str(), (unsigned int)name.size(), doc.GetAllocator()).Move(), json_formobjects.Move(), doc.GetAllocator()); +} +bool wxUIFormData::Read_JSON(const rapidjson::Document& doc, wxString& ui_path) +{ + bool ok = true; + DeleteAll(); + + m_name = doc["Name"].GetString(); + m_width = (int)doc["Width"].GetDouble(); + m_height = (int)doc["Height"].GetDouble(); + + + auto json_formobjects = doc["FormObjects"].GetObject(); + + for (rapidjson::Value::ConstMemberIterator itr = json_formobjects.MemberBegin(); itr != json_formobjects.MemberEnd() && ok; ++itr) { + wxString type = itr->name.GetString(); + if (wxUIObject *obj = Create(type)) + ok = ok && obj->Read_JSON(itr->value, ui_path); + else + ok = false; + } + return ok; } + + bool wxUIFormData::Read_text(wxInputStream &_I, wxString &ui_path) { DeleteAll(); diff --git a/src/utils.cpp b/src/utils.cpp index 434bd91f..dd913d28 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -64,6 +64,64 @@ return !(buf.Len() == 0 && c == EOF); } */ + +void Write_JSON_value(rapidjson::Document& doc, wxString name, double value) +{ + rapidjson::Value json_val; + json_val = value; + doc.AddMember(rapidjson::Value(name.c_str(), (unsigned int)name.size(), doc.GetAllocator()).Move(), json_val.Move(), doc.GetAllocator()); +} + +void Write_JSON_value(rapidjson::Document& doc, wxString name, wxString value) +{ + rapidjson::Value json_val; + json_val.SetString(value.utf8_str(), doc.GetAllocator()); // normal and any string with Unicode + doc.AddMember(rapidjson::Value(name.c_str(), (unsigned int)name.size(), doc.GetAllocator()).Move(), json_val.Move(), doc.GetAllocator()); +} + +wxString Read_JSON_value(const rapidjson::Value& doc, wxString name) +{ + return wxString::FromUTF8(doc[(const char*)name.mb_str()].GetString()); +} + +void Write_JSON_multiline_value(rapidjson::Document& doc, wxString name, wxString value) // json array fails in arraystring writing "\\" does not go to "\\\\" +{ + rapidjson::Document json_multiline(&doc.GetAllocator()); // for table inside of json document. + json_multiline.SetArray(); + wxArrayString as = wxSplit(value, '\n'); + for (size_t i = 0; i < as.Count(); i++) { + wxString linename = wxString::Format("%d",(int)i+1); + // these two replace statements were not necessary when the JSON was stored as a single string + as[i].Replace("'\\'", "'\\\\'"); // file = replace(file, '\\', '/'); + as[i].Replace("^\\", "^\\\\"); // plotopt({"title"=sprintf('IV curves at %g ^\\deg C',Tc),"popup"=true,"backcolor"=[255,255,255],"legend"=true, 'legendpos'='bottom'}); + json_multiline.PushBack(rapidjson::Value(as[i].utf8_str(), doc.GetAllocator()).Move(), doc.GetAllocator()); + } + doc.AddMember(rapidjson::Value(name.c_str(), (unsigned int)name.size(), doc.GetAllocator()).Move(), json_multiline.Move(), doc.GetAllocator()); +} + +wxString Read_JSON_multiline_value(const rapidjson::Value& doc, wxString name) +{ + wxArrayString as; + auto& json_multiline = doc[(const char*)name.mb_str()]; + for (rapidjson::SizeType i = 0; i < json_multiline.Size(); i++) { + as.push_back(wxString::FromUTF8(json_multiline[i].GetString())); + } + + wxString str = wxJoin(as,'\n'); + return str; +} + +void Write_JSON_value(rapidjson::Document& doc, wxString name, wxArrayString value) +{ + rapidjson::Value json_val; + wxString x = ""; + if (value.Count() > 0) + x = wxJoin(value, '|'); + json_val.SetString(x.utf8_str(), doc.GetAllocator()); + doc.AddMember(rapidjson::Value(name.c_str(), (unsigned int)name.size(), doc.GetAllocator()).Move(), json_val.Move(), doc.GetAllocator()); +} + + wxString wxLimitTextColumns(const wxString &str, size_t numcols) { wxString buf; size_t len = (int) str.Len(); @@ -413,7 +471,7 @@ bool wxWebHttpDownload(const wxString &url, const wxString &local_file, wxInputStream *httpStream = get.GetInputStream(file); bool ok = false; if (get.GetError() == wxPROTO_NOERR) { - int ntotal = httpStream->GetSize(); + int ntotal = (int)httpStream->GetSize(); if (ntotal < 1) ntotal = -1000; @@ -434,7 +492,7 @@ bool wxWebHttpDownload(const wxString &url, const wxString &local_file, while (!httpStream->Eof()) { int nread; httpStream->Read(rwbuf, NRWBUFBYTES); - nread = httpStream->LastRead(); + nread = (int)httpStream->LastRead(); fout.Write(rwbuf, nread); if (nread > 0) ndown += nread; @@ -579,13 +637,13 @@ std::vector wxCommaDashListToIndices(const wxString &value) { if (hpos < 0) { long num = 0; if (s.ToLong(&num)) - list.push_back(num); + list.push_back((int)num); } else { long start = 0, end = 0; if (s.Mid(0, hpos).ToLong(&start) && s.Mid(hpos + 1).ToLong(&end) && end >= start) { - for (int j = start; j <= end; j++) + for (int j = (int)start; j <= end; j++) list.push_back(j); } } @@ -1353,7 +1411,7 @@ wxString wxGetMD5(const wxString &string) { char *buf = strdup((const char *) string.c_str()); MD5Init(&ctx); - MD5Update(&ctx, (unsigned char *) buf, strlen(buf)); + MD5Update(&ctx, (unsigned char *) buf, (unsigned int)strlen(buf)); MD5End(&ctx, tmp); free(buf); @@ -1375,7 +1433,7 @@ wxString wxGetFileMD5(wxInputStream &stream) { if (stream.Read(buffer, sizeof(buffer)).LastRead() <= 0) return wxEmptyString; - MD5Update(&ctx, buffer, stream.LastRead()); + MD5Update(&ctx, buffer, (unsigned int)stream.LastRead()); } while (!stream.Eof()); MD5End(&ctx, tmp); From 48379fff8ef3437fda81df0fbd1775d4453fc36e Mon Sep 17 00:00:00 2001 From: Steven Janzou Date: Mon, 6 Feb 2023 04:11:20 -0700 Subject: [PATCH 2/5] Change to Node.js 16 instead of 12 per GitHub Actions --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8019630f..88a994ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: GH_WORKSPACE: /home/runner/work/wex/wex #= $GITHUB_WORKSPACE steps: - name: Setup cmake - uses: jwlawson/actions-setup-cmake@v1.12 + uses: jwlawson/actions-setup-cmake@v1.16 with: cmake-version: '3.24.x' - name: Test cmake version @@ -114,7 +114,7 @@ jobs: GH_WORKSPACE: /home/runner/work/wex/wex #= $GITHUB_WORKSPACE steps: - name: Setup cmake - uses: jwlawson/actions-setup-cmake@v1.12 + uses: jwlawson/actions-setup-cmake@v1.16 with: cmake-version: '3.24.x' - name: Test cmake version From 30db577e7d66fbad6ad16cae384fe48dce469ee4 Mon Sep 17 00:00:00 2001 From: Steven Janzou Date: Mon, 6 Feb 2023 04:36:16 -0700 Subject: [PATCH 3/5] reset again for failing Ubuntu GitHub Actions --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88a994ff..8019630f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: GH_WORKSPACE: /home/runner/work/wex/wex #= $GITHUB_WORKSPACE steps: - name: Setup cmake - uses: jwlawson/actions-setup-cmake@v1.16 + uses: jwlawson/actions-setup-cmake@v1.12 with: cmake-version: '3.24.x' - name: Test cmake version @@ -114,7 +114,7 @@ jobs: GH_WORKSPACE: /home/runner/work/wex/wex #= $GITHUB_WORKSPACE steps: - name: Setup cmake - uses: jwlawson/actions-setup-cmake@v1.16 + uses: jwlawson/actions-setup-cmake@v1.12 with: cmake-version: '3.24.x' - name: Test cmake version From 020957b4fbed552cbf7e99db26f8fb533ff07f2d Mon Sep 17 00:00:00 2001 From: Steven Janzou Date: Mon, 6 Feb 2023 05:00:13 -0700 Subject: [PATCH 4/5] Test fixing GiHub Actions OS dependencies with --fix-missing --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8019630f..f7244103 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: run: cmake --version - name: Install OS dependencies run: | - sudo apt-get update + sudo apt-get --fix-missing update sudo apt-get install -y \ build-essential \ freeglut3-dev \ @@ -121,7 +121,7 @@ jobs: run: cmake --version - name: Install OS dependencies run: | - sudo apt-get update + sudo apt-get --fix-missing update sudo apt-get install -y \ build-essential \ freeglut3-dev \ From 4cb1f47c573c51b3a378b8417a1099269fb58057 Mon Sep 17 00:00:00 2001 From: Steven Janzou Date: Mon, 6 Feb 2023 05:18:27 -0700 Subject: [PATCH 5/5] try different OS dependencies order --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f7244103..def77a44 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: run: cmake --version - name: Install OS dependencies run: | - sudo apt-get --fix-missing update + sudo apt-get update --fix-missing sudo apt-get install -y \ build-essential \ freeglut3-dev \ @@ -121,7 +121,7 @@ jobs: run: cmake --version - name: Install OS dependencies run: | - sudo apt-get --fix-missing update + sudo apt-get update --fix-missing sudo apt-get install -y \ build-essential \ freeglut3-dev \