|
|
(53 intermediate revisions by the same user not shown) |
Line 16: |
Line 16: |
| {| class="wikitable" | | {| class="wikitable" |
| ! [http://www.aosabook.org/en/index.html Architecture of major open source apps] | | ! [http://www.aosabook.org/en/index.html Architecture of major open source apps] |
| | |} |
| | {| class="wikitable" |
| | ! [[Security]] |
| |} | | |} |
| {| class="wikitable" | | {| class="wikitable" |
Line 21: |
Line 24: |
| |} | | |} |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! String escape formatting across different languages and systems | | ! nosql enhances, not replaces, SQL |
| |- | | |- |
| | | | | Not all data should be denormalized, and not all data should be normalized. The optimal mix considers the extent of the data. |
| * c++ to JSON: always use nlohmann::json j.dump() to encode, to ensure strings are properly escaped | | |
| * JSON to c++: always use nlohmann::json j.parse() " | | * Precise schemas are good when not overdone |
| * c++ to Javascript: use raw_to_Javascript() to properly escape | | * When a container has an array with a large number of elements, it should be normalized |
| * c++ to sqlite: use SqliteLocalModel::safestr(), which uses double_doublequotes(str)
| | * Sparse data and heterogeneous data are the best candidates for denormalization |
| | |
| | Postgres with JSON allows an elegant combination of nosql and SQL. |
| |} | | |} |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
Line 113: |
Line 118: |
| Now you should have build+run debug+release configurations, selectable in the weird project icon in bottom of left-side toolbar ("mode selector") | | Now you should have build+run debug+release configurations, selectable in the weird project icon in bottom of left-side toolbar ("mode selector") |
| |} | | |} |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! boost release and debug build for linux
| |
| |-
| |
| |
| |
| # download latest boost, eg: boost_1_59_0
| |
| m@wallee:~/development$ 7z x boost_1_59_0.7z
| |
| cd boost_1_##_0
| |
| build_boost_release_and_debug.sh
| |
| # then patch .bashrc as instructed
| |
| # eclipse and server/nix/bootstrap.sh are customized to match
| |
| To upgrade a project:
| |
| cd nix
| |
| make distclean # removes nasty .deps folders that link to old boost if you let them
| |
| make clean # removes .o files etc
| |
| cd ../build-Release && make distclean && make clean
| |
| cd ../build-Debug && make distclean && make clean
| |
| cd ..
| |
| ./bootstrap force release
| |
| ./bootstrap force debug
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! boost release and debug build for Windows
| |
| |-
| |
| | Open a VS2015 x64 Native Tools Command Prompt.
| |
| EITHER: for new installs, you have to run bootstrap.bat first, it will build b2;
| |
| OR: for reruns, remove boost dirs: [bin.v2, stage].
| |
| Then build 64-bit:
| |
| cd "....\boost_1_59_0"
| |
| b2 toolset=msvc variant=release,debug link=static address-model=64
| |
| rem trying to avoid excessive options, assuming I don't need these: threading=multi
| |
| (old stuff)
| |
| --toolset=msvc-14.0 address-model=64 --build-type=complete --stagedir=windows_lib\x64 stage
| |
| Now open VS2013 x86 Native Tools Command Prompt and build 32-bit:
| |
| cd "C:\Michael's Data\development\sixth_column\boost_1_55_0"
| |
| bjam --toolset=msvc-12.0 address-model=32 --build-type=complete --stagedir=windows_lib\x86 stage
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 include base constructor (etc) in derived class
| |
| |-
| |
| | The awesome C++11 way to steal the constructor from the base class, oh man I've been waiting for this one...
| |
| class HttpsServer : public Server<HTTPS>
| |
| {
| |
| // DOES THIS FOR YOU!
| |
| /*
| |
| HttpsServer(unsigned short port, size_t num_threads, const std::string& cert_file, const std::string& private_key_file)
| |
| :
| |
| // Call base class
| |
| Server<HTTPS>::Server(port, num_threads, cert_file, private_key_file)
| |
| {}
| |
| */
| |
| using Server<HTTPS>::Server;
| |
| ....
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 containers
| |
| |-
| |
| | sorted_vector || use when doing lots of unsorted insertions and maintaining constant sort would be expensive; vector is good for a big pile of things that only occasionally needs a sorted lookup
| |
| |-
| |
| | map || sorted binary search tree; always sorted by key; you can walk through in sorted order (choose unordered if not needed!)
| |
| |-
| |
| | multimap || same as map but allows dupe keys (not as common)
| |
| |-
| |
| | unordered_map || hashmap; always sorted by key; additional bucket required for hash collisions; no defined order when walking through
| |
| |-
| |
| | unordered_multimap || same as map but allows dupe keys; dupes are obviously in the same bucket, and you can walk just the dupes if needed
| |
| |-
| |
| | set<br>multiset<br>unordered_set<br>unordered_multiset || sets are just like maps, except the key is embedded in the object, nice for encapsulation.<br />
| |
| Items must be const (!) since they are the key - sounds bad, but this is mitigated by the mutable keyword.<br />
| |
| You can use mutable on the variables that are not part of the key to remove the const.<br />
| |
| This changes the constness of the object from binary (completely const) to logical (constness is defined by the developer).<br />
| |
| So... set is a good way to achieve both encapsulation and logical const - make const work for you, not against! :-)<br />
| |
| |-
| |
| | set (etc.) of pointers || sets of pointers are the pinnacle of object stores<br />
| |
| The entire object can be dereferenced and accessed then without const issues.<br />
| |
| A pointer functor can be provided that does a sort by dereferencing the pointer to the object.<br />
| |
| Two requirements: you must make sure yourself that you do not change the key values - you can mark them const, provided in constructor;<br />
| |
| you must create sort/equal/hash functors that dereference the pointers to use object contents<br />
| |
| (the default will be by pointer address).<br />
| |
| The arguably biggest advantage, as a result, is that you can create multiple sets<br />
| |
| to reference the same group of objects with different sort funtors to create multiple indices.<br />
| |
| You just have to manage the keys carefully, so that they don't change (which would invalidate the sorting).<br />
| |
| The primary container can manage object allocation; using a heap-based unique_ptr allocation<br />
| |
| map vs key redux
| |
|
| |
| use a key in the set, derive a class from it with the contents
| |
| + small key
| |
| + encapsulation
| |
| - requires mutable to solve the const problem
| |
| use a key in the set, key includes a mutable object
| |
| + encapsulation
| |
| - weird bc everything uses a const object but we have const functions like save() that change the mutable subobject
| |
| use a map
| |
| + small key
| |
| - no encapsulation, have to deal with a pair instead of an object
| |
| can we just put a ref to key in the value? sure why not - err, bc we don't have access to it
| |
| + solves const problem bc value is totally mutable by design
| |
| + we can have multiple keys - and the value can have multiple refs to them
| |
| + simpler equal and hash functions
| |
| map:
| |
| create an object with internal key(s)
| |
| create map index(es) with duplicate key values outside the object - dupe data is the downside
| |
| use set(s) with one static key for find():
| |
| create an object with internal key(s)
| |
| create set index(es) with specific hash/equals functor(s)
| |
| when finding, use one static key object (even across indexes!) so there isn't a big construction each time; just set the necessary key values
| |
| that proves difficult when dealing with member vars that are references
| |
| but to solve it, just set up a structure of dummy static key objects that use each other; then provide a function to setKey(Object& keyref) { keyref_ = keyref; }
| |
| nope, can't reassign refs
| |
| the solution: use pointers not references
| |
| yes that's right
| |
| just do it
| |
| apparently there was a reason i was anti-reference for all those years
| |
| two reasons to use pointers:
| |
| dynamically allocated
| |
| reassignment required
| |
| there ya go. simple. get it done.
| |
| when accessing find results from the set, use a const_cast on the object!
| |
| WARNING: a separate base class with the key sounds good... but fails when you have more than one index on the object. just use a static key object for them all!
| |
|
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 example for large groups of objects with frequent crud AND search
| |
| |-
| |
| | Best solution is an unordered set of pointers:
| |
| typedef boost::unordered_set<MajorObject*> MajorObjects;
| |
|
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 example for large groups of objects with infrequent crud and frequent search
| |
| |-
| |
| | Best solution is a vector of pointers sorted on demand (sorted_vector):
| |
| TODO
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 example to associate two complex objects (one the map key, one the map value)
| |
| |-
| |
| | Use unordered_map with a custom object as key. You must add hash and equals functions. Boost makes it easy:
| |
| static bool operator==(MyKeyObject const& m1, MyKeyObject const& m2)
| |
| {
| |
| return
| |
| m1.id_0 == m2.id_0
| |
| && m1.id_1 == m2.id_1;
| |
| }
| |
| static std::size_t hash_value(MyKeyObject const& mko)
| |
| {
| |
| std::size_t seed = 0;
| |
| boost::hash_combine(seed, mko.id_0);
| |
| boost::hash_combine(seed, mko.id_1);
| |
| return seed;
| |
| }
| |
| typedef boost::unordered_map<MyKeyObject, MyValueObject*> MyMap;
| |
| Note that you can extend this to use a pointer to a key object, whoop.
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 example for multiple unordered_set indexes into one group of objects
| |
| |-
| |
| | Objects will be dynamically created. One set should include them all and be responsible for memory allocation cleanup:
| |
| TODO
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 example for set with specific sorting
| |
| |-
| |
| | Use set with a specific sort functor. You can create as many of these indexes as you want!
| |
| struct customers_set_sort_functor
| |
| {
| |
| bool operator()(const MyObject* l, const MyObject* r) const
| |
| {
| |
| // the id is the key
| |
| return l->id_ < r->id_;
| |
| }
| |
| };
| |
| typedef set<MyObject*,myobject_sort_by_id_functor> MyObjectsById;
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 loop through vector to erase some items
| |
| |-
| |
| | Note that other containers' iterators may not be invalidated so you can just erase() as needed...
| |
| For vectors, you have to play with iterators to get it right - watch for proper ++ pre/postfix!
| |
| for (it = numbers.begin(); it != numbers.end(); ) // NOTE we increment below, only if we don't erase
| |
| {
| |
| if (*it.no_good())
| |
| {
| |
| numbers.erase(it++); // NOTE that we ERASE THEN INCREMENT here.
| |
| }
| |
| else
| |
| {
| |
| ++it;
| |
| }
| |
| }
| |
| I thought I had always looped backwards to do this, I *think* that's ok too, but I don't see it used in my code, I think I'll avoid. :-)
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 range based for loop, jacked with boost index if needed
| |
| |-
| |
| | No iterator usage at all. Nice at times, not enough at others. Make SURE to always use a reference or you will be working on a COPY. Make it const if you aren't changing the object.
| |
| for (auto& mc : my_container)
| |
| mc.setString("default");
| |
| for (const auto& cmc : my_container)
| |
| cout << cmc.asString();
| |
| boost index can give you the index if you need it, sweet:
| |
| #include <boost/range/adaptor/indexed.hpp>
| |
| ...
| |
| for (const auto &element: boost::adaptors::index(mah_container))
| |
| cout << element.value() << element.index();
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 for loop using lambda
| |
| |-
| |
| | This C++11 for loop is clean and elegant and a perfect way to check if your compiler is ready for c++11:
| |
| vector<int> v;
| |
| for_each( v.begin(), v.end(), [] (int val)
| |
| {
| |
| cout << val;
| |
| } );
| |
| This is using a lambda function, we should switch from iterators and functors to those - but not quite yet, since we're writing cross-platform code. Do not touch this until we can be sure that all platforms provide compatible C++11 handling.
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 integer types
| |
| |-
| |
| | I really like the "fast" C++11 types, that give best performance for a guaranteed minimum bit width.
| |
| Use them when you know a variable will not exceed the maximum value of that bit width, but does not have to be a precise bit width in memory or elsewhere.
| |
|
| |
| Pick specific-width fields whenever data is shared with other processes and components and you want a guarantee of its bit width.
| |
|
| |
| And when using pointer size and array indices you should use types defined for those specific situations.
| |
|
| |
| FAST types:
| |
| int_fast8_t
| |
| int_fast16_t fastest signed integer type with width of
| |
| int_fast32_t at least 8, 16, 32 and 64 bits respectively
| |
| int_fast64_t
| |
|
| |
| uint_fast8_t
| |
| uint_fast16_t fastest unsigned integer type with width of
| |
| uint_fast32_t at least 8, 16, 32 and 64 bits respectively
| |
| uint_fast64_t
| |
| SMALL types:
| |
| int_least8_t
| |
| int_least16_t smallest signed integer type with width of
| |
| int_least32_t at least 8, 16, 32 and 64 bits respectively
| |
| int_least64_t
| |
|
| |
| uint_least8_t
| |
| uint_least16_t smallest unsigned integer type with width of
| |
| uint_least32_t at least 8, 16, 32 and 64 bits respectively
| |
| uint_least64_t
| |
| EXACT types:
| |
| int8_t signed integer type with width of
| |
| int16_t exactly 8, 16, 32 and 64 bits respectively
| |
| int32_t with no padding bits and using 2's complement for negative values
| |
| int64_t (provided only if the implementation directly supports the type)
| |
|
| |
| uint8_t unsigned integer type with width of
| |
| uint16_t exactly 8, 16, 32 and 64 bits respectively
| |
| uint32_t (provided only if the implementation directly supports the type)
| |
| uint64_t
| |
| SPECIFIC-USE types:
| |
| intptr_t integer type capable of holding a pointer
| |
| uintptr_t unsigned integer type capable of holding a pointer
| |
| size_t unsigned integer type capable of holding an array index (same size as uintptr_t)
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! C++11 scoped enumeration
| |
| |-
| |
| | C++11 has scoped enumeration, which lets you specify the SPECIFIC VARIABLE TYPE for the enum. Perfect, let's use uint_fast32_t.
| |
| enum class STRING_PREF_INDEX int_fast32_t: { ... };
| |
| Unfortunately, gcc gives me a scary warning, and stuff fails. For some reason, it does not know about the provided type, although it is definitely defined. Revisit this later if you have time.
| |
| warning: elaborated-type-specifier for a scoped enum must not use the ‘class’ keyword
| |
| Old skool is still cool:
| |
| typedef enum
| |
| {
| |
| // assert( SP_COUNT == 2 );
| |
| SP_FIRST = 0 ,
| |
| SP_SOME_PREF = SP_FIRST ,
| |
| SP_ANOTHA ,
| |
|
| |
| SP_COUNT
| |
| } STRING_PREF_INDEX;
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! c++ in-memory storage of "major" objects | | ! c++ in-memory storage of "major" objects |
Line 508: |
Line 223: |
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! C++ | | ! c++11 |
| |- | | |- |
| | | | | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Deleting multiple elements in a collection
| |
| |-
| |
| |
| |
| * For sequences (vector, list...), best practice is to use the [https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom erase-remove] STL pattern
| |
| * For associative containers (set, map...): just recurse and remove iterators, they won't muck up the sequence. [http://stackoverflow.com/questions/800955/remove-if-equivalent-for-stdmap example]
| |
| See MemoryModel::saveDirtyObjectsAsNeeded() for example code.
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++ Create a portable C/C++ project
| |
| |-
| |
| | Use QtCreator + CMake, both available everywhere!
| |
| set up:
| |
| create a Qt project as: New Project-> Non-Qt/Plain C Project (CMake Build)
| |
| pick the PARENT and use the name of the existing folder
| |
| set up a build folder in the existing folder, called (base)/qtcreator-release-build
| |
| it creates CMakeLists.txt (THIS IS BASICALLY THE PROJECT FILE!)
| |
| also creates main.c or something
| |
| build it! make sure it works
| |
| NOW we can edit CMakeLists.txt - change . to ./src to get it to scan the src folder for code!
| |
| and easily add "known" libs! this was all i needed:
| |
| TARGET_LINK_LIBRARIES(${PROJECT_NAME} pthread websockets)
| |
| make sure it builds
| |
| now we want a DEBUG build as well!
| |
| Projects->Build&Run->pick Build in weird Build/Run pillbox->Edit build configs:
| |
| Rename: release
| |
| CMake build dir: Make sure build dir is set to release ie qtcreator-debug-build
| |
| Add: Clone: release, name: debug
| |
| for debug, add a custom build step BEFORE make step:
| |
| command: /usr/bin/cmake
| |
| args: -DCMAKE_BUILD_TYPE=Debug .
| |
| working dir: %{buildDir}
| |
| (add it, and move it up above make)
| |
| (build em both)
| |
| Projects->Build&Run->pick Run in weird Build/Run pillbox
| |
| Run Configuration: rename to "{...} release"
| |
| clone it into "{...} debug"
| |
| change working dir to match Build path
| |
| change any needed params
| |
| Now you should have build+run debug+release configurations, selectable in the weird project icon in bottom of left-side toolbar ("mode selector")
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! boost release and debug build for linux
| |
| |-
| |
| |
| |
| # download latest boost, eg: boost_1_59_0
| |
| m@wallee:~/development$ 7z x boost_1_59_0.7z
| |
| cd boost_1_##_0
| |
| build_boost_release_and_debug.sh
| |
| # then patch .bashrc as instructed
| |
| # eclipse and server/nix/bootstrap.sh are customized to match
| |
| To upgrade a project:
| |
| cd nix
| |
| make distclean # removes nasty .deps folders that link to old boost if you let them
| |
| make clean # removes .o files etc
| |
| cd ../build-Release && make distclean && make clean
| |
| cd ../build-Debug && make distclean && make clean
| |
| cd ..
| |
| ./bootstrap force release
| |
| ./bootstrap force debug
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! boost release and debug build for Windows
| |
| |-
| |
| | Open a VS2015 x64 Native Tools Command Prompt.
| |
| EITHER: for new installs, you have to run bootstrap.bat first, it will build b2;
| |
| OR: for reruns, remove boost dirs: [bin.v2, stage].
| |
| Then build 64-bit:
| |
| cd "....\boost_1_59_0"
| |
| b2 toolset=msvc variant=release,debug link=static address-model=64
| |
| rem trying to avoid excessive options, assuming I don't need these: threading=multi
| |
| (old stuff)
| |
| --toolset=msvc-14.0 address-model=64 --build-type=complete --stagedir=windows_lib\x64 stage
| |
| Now open VS2013 x86 Native Tools Command Prompt and build 32-bit:
| |
| cd "C:\Michael's Data\development\sixth_column\boost_1_55_0"
| |
| bjam --toolset=msvc-12.0 address-model=32 --build-type=complete --stagedir=windows_lib\x86 stage
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! c++11 include base constructor (etc) in derived class | | ! c++11 include base constructor (etc) in derived class |
Line 840: |
Line 478: |
| SP_COUNT | | SP_COUNT |
| } STRING_PREF_INDEX; | | } STRING_PREF_INDEX; |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++ in-memory storage of "major" objects
| |
| |-
| |
| |
| |
| OBSERVATION ONE
| |
|
| |
| Consider An Important Qt Design: QObjects cannot normally be copied
| |
| their copy constructors and assignment operators are private
| |
| why? A Qt Object...
| |
| might have a unique QObject::objectName(). If we copy a Qt Object, what name should we give the copy?
| |
| has a location in an object hierarchy. If we copy a Qt Object, where should the copy be located?
| |
| can be connected to other Qt Objects to emit signals to them or to receive signals emitted by them. If we copy a Qt Object, how should we transfer these connections to the copy?
| |
| can have new properties added to it at runtime that are not declared in the C++ class. If we copy a Qt Object, should the copy include the properties that were added to the original?
| |
| in other words, a QObject is a pretty serious object that has the ability to be tied to other objects and resources in ways that make copying dangerous
| |
| isn't this true of all serious objects? pretty much
| |
|
| |
| OBSERVATION TWO
| |
|
| |
| if you have a vector of objects, you often want to track them individually outside the vector
| |
| if you use a vector of pointers, you can move the object around much more cheaply, and not worry about costly large vector reallocations
| |
| a vector of objects (not pointers) only makes sense if the number of objects is initially known and does not change over time
| |
|
| |
| OBSERVATION THREE
| |
|
| |
| STL vectors can store your pointers, iterate thru them, etc.
| |
| for a vector of any substantial size, you want to keep objects sorted so you can find them quickly
| |
| that's what my sorted_vector class is for; it simply bolts vector together with sort calls and a b_sorted status
| |
| following STL practices, to get sorting, you have to provide operator< for whatever is in your vector
| |
| BUT... you are not allowed to do operator<(const MyObjectPtr* right) because it would require a reference to a pointer which is not allowed
| |
| BUT... you can provide a FUNCTOR to do the job, then provide it when sorting/searching
| |
| a functor is basically a structure with a bool operator()(const MyObjectPtr* left, const MyObjectPtr* right)
| |
|
| |
| OBSERVATION FOUR
| |
|
| |
| unordered_set works even better when combining frequent CRUD with frequent lookups
| |
|
| |
| SUMMARY
| |
| Dealing with tons of objects is par for the course in any significant app.
| |
| Finding a needle in the haystack of those objects is also standard fare.
| |
| Having multiple indices into those objects is also essential.
| |
| Using unordered_set with object pointers and is very powerful.
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++ stl reverse iterator skeleton
| |
| |-
| |
| | From [http://www.sgi.com/tech/stl/ReverseIterator.html SGI]...
| |
| reverse_iterator rfirst(V.end());
| |
| reverse_iterator rlast(V.begin());
| |
|
| |
| while (rfirst != rlast)
| |
| {
| |
| cout << *rfirst << endl;
| |
| ...
| |
| rfirst++;
| |
| }
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++ stl reading a binary file into a string
| |
| |-
| |
| |
| |
| std::ifstream in("my.zip",std::ios::binary);
| |
| if (!in)
| |
| {
| |
| std::cout << "problem with file open" << std::endl;
| |
| return 0;
| |
| }
| |
| in.seekg(0,std::ios::end);
| |
| unsigned long length = in.tellg();
| |
| in.seekg(0,std::ios::beg);
| |
|
| |
| string str(length,0);
| |
| std::copy(
| |
| std::istreambuf_iterator< char >(in) ,
| |
| std::istreambuf_iterator< char >() ,
| |
| str.begin()
| |
| );
| |
|
| |
| For more, see [[Reading a binary file|c++ stl reading a binary file]]
| |
| |}
| |
|
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! C/C++ best-in-class tool selection
| |
| |-
| |
| | I need to have easy setup of debug-level tool support for portable C++11 code. And I need to decide and stick to it to be efficient.
| |
| * '''Compiler selection'''
| |
| ** linux and mac: gcc
| |
| ** windows: Visual Studio
| |
| * '''IDE selection'''
| |
| ** linux and mac: Qt Creator
| |
| ** windows: Qt Creator (OR Visual Studio OR eclipse?)
| |
| * '''Debugger selection'''
| |
| ** linux and mac: Qt Creator
| |
| ** windows: Qt Creator (OR Visual Studio OR eclipse?)
| |
| |} | | |} |
| |} | | |} |
Line 947: |
Line 488: |
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! C++ | | ! boost |
| |- | | |- |
| | | | | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Deleting multiple elements in a collection
| |
| |-
| |
| |
| |
| * For sequences (vector, list...), best practice is to use the [https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom erase-remove] STL pattern
| |
| * For associative containers (set, map...): just recurse and remove iterators, they won't muck up the sequence. [http://stackoverflow.com/questions/800955/remove-if-equivalent-for-stdmap example]
| |
| See MemoryModel::saveDirtyObjectsAsNeeded() for example code.
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++ Create a portable C/C++ project
| |
| |-
| |
| | Use QtCreator + CMake, both available everywhere!
| |
| set up:
| |
| create a Qt project as: New Project-> Non-Qt/Plain C Project (CMake Build)
| |
| pick the PARENT and use the name of the existing folder
| |
| set up a build folder in the existing folder, called (base)/qtcreator-release-build
| |
| it creates CMakeLists.txt (THIS IS BASICALLY THE PROJECT FILE!)
| |
| also creates main.c or something
| |
| build it! make sure it works
| |
| NOW we can edit CMakeLists.txt - change . to ./src to get it to scan the src folder for code!
| |
| and easily add "known" libs! this was all i needed:
| |
| TARGET_LINK_LIBRARIES(${PROJECT_NAME} pthread websockets)
| |
| make sure it builds
| |
| now we want a DEBUG build as well!
| |
| Projects->Build&Run->pick Build in weird Build/Run pillbox->Edit build configs:
| |
| Rename: release
| |
| CMake build dir: Make sure build dir is set to release ie qtcreator-debug-build
| |
| Add: Clone: release, name: debug
| |
| for debug, add a custom build step BEFORE make step:
| |
| command: /usr/bin/cmake
| |
| args: -DCMAKE_BUILD_TYPE=Debug .
| |
| working dir: %{buildDir}
| |
| (add it, and move it up above make)
| |
| (build em both)
| |
| Projects->Build&Run->pick Run in weird Build/Run pillbox
| |
| Run Configuration: rename to "{...} release"
| |
| clone it into "{...} debug"
| |
| change working dir to match Build path
| |
| change any needed params
| |
| Now you should have build+run debug+release configurations, selectable in the weird project icon in bottom of left-side toolbar ("mode selector")
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! boost release and debug build for linux | | ! boost release and debug build for linux |
Line 997: |
Line 497: |
| # download latest boost, eg: boost_1_59_0 | | # download latest boost, eg: boost_1_59_0 |
| m@wallee:~/development$ 7z x boost_1_59_0.7z | | m@wallee:~/development$ 7z x boost_1_59_0.7z |
| cd boost_1_##_0 | | rm boost && ln -s boost_1_59 boost |
| | cd boost |
| build_boost_release_and_debug.sh | | build_boost_release_and_debug.sh |
| # then patch .bashrc as instructed | | # IMPORTANT: then patch .bashrc as instructed |
| # eclipse and server/nix/bootstrap.sh are customized to match | | # cmake-###/clean.sh and cmake-###/build.sh are customized to match |
| To upgrade a project: | | # (and older eclipse and server/nix/bootstrap.sh) |
| | To upgrade a CMake project: |
| | cd cmake-###/ |
| | ./clean.sh |
| | ./build.sh |
| | To upgrade an older autotools project: |
| cd nix | | cd nix |
| make distclean # removes nasty .deps folders that link to old boost if you let them | | make distclean # removes nasty .deps folders that link to old boost if you let them |
Line 1,028: |
Line 534: |
| |} | | |} |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! c++11 include base constructor (etc) in derived class | | ! boost regex (very similar to c++11, with LESS BUGS and MORE POWER) |
| |- | | |- |
| | The awesome C++11 way to steal the constructor from the base class, oh man I've been waiting for this one... | | | boost regex does everything you could need, take your time to get it right |
| class HttpsServer : public Server<HTTPS>
| | * regex_search will work hard to find substrings, while regex_match requires your regex to match entire input |
| {
| | * smatch is a great way to get back a bunch of iterators to the results |
| // DOES THIS FOR YOU!
| | example: |
| /*
| | virtual bool url_upgrade_any_old_semver(string& url) |
| HttpsServer(unsigned short port, size_t num_threads, const std::string& cert_file, const std::string& private_key_file)
| |
| :
| |
| // Call base class
| |
| Server<HTTPS>::Server(port, num_threads, cert_file, private_key_file)
| |
| {}
| |
| */
| |
| using Server<HTTPS>::Server;
| |
| ....
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 containers
| |
| |-
| |
| | sorted_vector || use when doing lots of unsorted insertions and maintaining constant sort would be expensive; vector is good for a big pile of things that only occasionally needs a sorted lookup
| |
| |-
| |
| | map || sorted binary search tree; always sorted by key; you can walk through in sorted order (choose unordered if not needed!)
| |
| |-
| |
| | multimap || same as map but allows dupe keys (not as common)
| |
| |-
| |
| | unordered_map || hashmap; always sorted by key; additional bucket required for hash collisions; no defined order when walking through
| |
| |-
| |
| | unordered_multimap || same as map but allows dupe keys; dupes are obviously in the same bucket, and you can walk just the dupes if needed
| |
| |-
| |
| | set<br>multiset<br>unordered_set<br>unordered_multiset || sets are just like maps, except the key is embedded in the object, nice for encapsulation.<br />
| |
| Items must be const (!) since they are the key - sounds bad, but this is mitigated by the mutable keyword.<br />
| |
| You can use mutable on the variables that are not part of the key to remove the const.<br />
| |
| This changes the constness of the object from binary (completely const) to logical (constness is defined by the developer).<br />
| |
| So... set is a good way to achieve both encapsulation and logical const - make const work for you, not against! :-)<br />
| |
| |-
| |
| | set (etc.) of pointers || sets of pointers are the pinnacle of object stores<br />
| |
| The entire object can be dereferenced and accessed then without const issues.<br />
| |
| A pointer functor can be provided that does a sort by dereferencing the pointer to the object.<br />
| |
| Two requirements: you must make sure yourself that you do not change the key values - you can mark them const, provided in constructor;<br />
| |
| you must create sort/equal/hash functors that dereference the pointers to use object contents<br />
| |
| (the default will be by pointer address).<br />
| |
| The arguably biggest advantage, as a result, is that you can create multiple sets<br />
| |
| to reference the same group of objects with different sort funtors to create multiple indices.<br />
| |
| You just have to manage the keys carefully, so that they don't change (which would invalidate the sorting).<br />
| |
| The primary container can manage object allocation; using a heap-based unique_ptr allocation<br />
| |
| map vs key redux
| |
|
| |
| use a key in the set, derive a class from it with the contents
| |
| + small key
| |
| + encapsulation
| |
| - requires mutable to solve the const problem
| |
| use a key in the set, key includes a mutable object
| |
| + encapsulation
| |
| - weird bc everything uses a const object but we have const functions like save() that change the mutable subobject
| |
| use a map
| |
| + small key
| |
| - no encapsulation, have to deal with a pair instead of an object
| |
| can we just put a ref to key in the value? sure why not - err, bc we don't have access to it
| |
| + solves const problem bc value is totally mutable by design
| |
| + we can have multiple keys - and the value can have multiple refs to them
| |
| + simpler equal and hash functions
| |
| map:
| |
| create an object with internal key(s)
| |
| create map index(es) with duplicate key values outside the object - dupe data is the downside
| |
| use set(s) with one static key for find():
| |
| create an object with internal key(s)
| |
| create set index(es) with specific hash/equals functor(s)
| |
| when finding, use one static key object (even across indexes!) so there isn't a big construction each time; just set the necessary key values
| |
| that proves difficult when dealing with member vars that are references
| |
| but to solve it, just set up a structure of dummy static key objects that use each other; then provide a function to setKey(Object& keyref) { keyref_ = keyref; }
| |
| nope, can't reassign refs
| |
| the solution: use pointers not references
| |
| yes that's right
| |
| just do it
| |
| apparently there was a reason i was anti-reference for all those years
| |
| two reasons to use pointers:
| |
| dynamically allocated
| |
| reassignment required
| |
| there ya go. simple. get it done.
| |
| when accessing find results from the set, use a const_cast on the object!
| |
| WARNING: a separate base class with the key sounds good... but fails when you have more than one index on the object. just use a static key object for them all!
| |
| | |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 example for large groups of objects with frequent crud AND search
| |
| |-
| |
| | Best solution is an unordered set of pointers:
| |
| typedef boost::unordered_set<MajorObject*> MajorObjects;
| |
| | |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 example for large groups of objects with infrequent crud and frequent search
| |
| |-
| |
| | Best solution is a vector of pointers sorted on demand (sorted_vector):
| |
| TODO
| |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 example to associate two complex objects (one the map key, one the map value)
| |
| |-
| |
| | Use unordered_map with a custom object as key. You must add hash and equals functions. Boost makes it easy:
| |
| static bool operator==(MyKeyObject const& m1, MyKeyObject const& m2)
| |
| {
| |
| return
| |
| m1.id_0 == m2.id_0
| |
| && m1.id_1 == m2.id_1;
| |
| }
| |
| static std::size_t hash_value(MyKeyObject const& mko)
| |
| {
| |
| std::size_t seed = 0;
| |
| boost::hash_combine(seed, mko.id_0);
| |
| boost::hash_combine(seed, mko.id_1);
| |
| return seed;
| |
| }
| |
| typedef boost::unordered_map<MyKeyObject, MyValueObject*> MyMap;
| |
| Note that you can extend this to use a pointer to a key object, whoop.
| |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 example for multiple unordered_set indexes into one group of objects
| |
| |-
| |
| | Objects will be dynamically created. One set should include them all and be responsible for memory allocation cleanup:
| |
| TODO
| |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 example for set with specific sorting
| |
| |-
| |
| | Use set with a specific sort functor. You can create as many of these indexes as you want!
| |
| struct customers_set_sort_functor
| |
| {
| |
| bool operator()(const MyObject* l, const MyObject* r) const
| |
| {
| |
| // the id is the key
| |
| return l->id_ < r->id_;
| |
| }
| |
| };
| |
| typedef set<MyObject*,myobject_sort_by_id_functor> MyObjectsById;
| |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 loop through vector to erase some items
| |
| |-
| |
| | Note that other containers' iterators may not be invalidated so you can just erase() as needed...
| |
| For vectors, you have to play with iterators to get it right - watch for proper ++ pre/postfix!
| |
| for (it = numbers.begin(); it != numbers.end(); ) // NOTE we increment below, only if we don't erase
| |
| {
| |
| if (*it.no_good())
| |
| {
| |
| numbers.erase(it++); // NOTE that we ERASE THEN INCREMENT here.
| |
| }
| |
| else
| |
| {
| |
| ++it;
| |
| }
| |
| }
| |
| I thought I had always looped backwards to do this, I *think* that's ok too, but I don't see it used in my code, I think I'll avoid. :-)
| |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 range based for loop, jacked with boost index if needed
| |
| |-
| |
| | No iterator usage at all. Nice at times, not enough at others. Make SURE to always use a reference or you will be working on a COPY. Make it const if you aren't changing the object.
| |
| for (auto& mc : my_container)
| |
| mc.setString("default");
| |
| for (const auto& cmc : my_container)
| |
| cout << cmc.asString();
| |
| boost index can give you the index if you need it, sweet:
| |
| #include <boost/range/adaptor/indexed.hpp>
| |
| ...
| |
| for (const auto &element: boost::adaptors::index(mah_container))
| |
| cout << element.value() << element.index();
| |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 for loop using lambda
| |
| |-
| |
| | This C++11 for loop is clean and elegant and a perfect way to check if your compiler is ready for c++11:
| |
| vector<int> v;
| |
| for_each( v.begin(), v.end(), [] (int val)
| |
| {
| |
| cout << val;
| |
| } );
| |
| This is using a lambda function, we should switch from iterators and functors to those - but not quite yet, since we're writing cross-platform code. Do not touch this until we can be sure that all platforms provide compatible C++11 handling.
| |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++11 integer types
| |
| |-
| |
| | I really like the "fast" C++11 types, that give best performance for a guaranteed minimum bit width.
| |
| Use them when you know a variable will not exceed the maximum value of that bit width, but does not have to be a precise bit width in memory or elsewhere.
| |
| | |
| Pick specific-width fields whenever data is shared with other processes and components and you want a guarantee of its bit width.
| |
| | |
| And when using pointer size and array indices you should use types defined for those specific situations.
| |
| | |
| FAST types:
| |
| int_fast8_t
| |
| int_fast16_t fastest signed integer type with width of
| |
| int_fast32_t at least 8, 16, 32 and 64 bits respectively
| |
| int_fast64_t
| |
| | |
| uint_fast8_t
| |
| uint_fast16_t fastest unsigned integer type with width of
| |
| uint_fast32_t at least 8, 16, 32 and 64 bits respectively
| |
| uint_fast64_t
| |
| SMALL types:
| |
| int_least8_t
| |
| int_least16_t smallest signed integer type with width of
| |
| int_least32_t at least 8, 16, 32 and 64 bits respectively
| |
| int_least64_t
| |
| | |
| uint_least8_t
| |
| uint_least16_t smallest unsigned integer type with width of
| |
| uint_least32_t at least 8, 16, 32 and 64 bits respectively
| |
| uint_least64_t
| |
| EXACT types:
| |
| int8_t signed integer type with width of
| |
| int16_t exactly 8, 16, 32 and 64 bits respectively
| |
| int32_t with no padding bits and using 2's complement for negative values
| |
| int64_t (provided only if the implementation directly supports the type)
| |
| | |
| uint8_t unsigned integer type with width of
| |
| uint16_t exactly 8, 16, 32 and 64 bits respectively
| |
| uint32_t (provided only if the implementation directly supports the type)
| |
| uint64_t
| |
| SPECIFIC-USE types:
| |
| intptr_t integer type capable of holding a pointer
| |
| uintptr_t unsigned integer type capable of holding a pointer
| |
| size_t unsigned integer type capable of holding an array index (same size as uintptr_t)
| |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! C++11 scoped enumeration
| |
| |-
| |
| | C++11 has scoped enumeration, which lets you specify the SPECIFIC VARIABLE TYPE for the enum. Perfect, let's use uint_fast32_t.
| |
| enum class STRING_PREF_INDEX int_fast32_t: { ... };
| |
| Unfortunately, gcc gives me a scary warning, and stuff fails. For some reason, it does not know about the provided type, although it is definitely defined. Revisit this later if you have time.
| |
| warning: elaborated-type-specifier for a scoped enum must not use the ‘class’ keyword
| |
| Old skool is still cool:
| |
| typedef enum
| |
| {
| |
| // assert( SP_COUNT == 2 );
| |
| SP_FIRST = 0 ,
| |
| SP_SOME_PREF = SP_FIRST ,
| |
| SP_ANOTHA ,
| |
|
| |
| SP_COUNT
| |
| } STRING_PREF_INDEX;
| |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++ in-memory storage of "major" objects
| |
| |-
| |
| |
| |
| OBSERVATION ONE
| |
|
| |
| Consider An Important Qt Design: QObjects cannot normally be copied
| |
| their copy constructors and assignment operators are private
| |
| why? A Qt Object...
| |
| might have a unique QObject::objectName(). If we copy a Qt Object, what name should we give the copy?
| |
| has a location in an object hierarchy. If we copy a Qt Object, where should the copy be located?
| |
| can be connected to other Qt Objects to emit signals to them or to receive signals emitted by them. If we copy a Qt Object, how should we transfer these connections to the copy?
| |
| can have new properties added to it at runtime that are not declared in the C++ class. If we copy a Qt Object, should the copy include the properties that were added to the original?
| |
| in other words, a QObject is a pretty serious object that has the ability to be tied to other objects and resources in ways that make copying dangerous
| |
| isn't this true of all serious objects? pretty much
| |
| | |
| OBSERVATION TWO
| |
|
| |
| if you have a vector of objects, you often want to track them individually outside the vector
| |
| if you use a vector of pointers, you can move the object around much more cheaply, and not worry about costly large vector reallocations
| |
| a vector of objects (not pointers) only makes sense if the number of objects is initially known and does not change over time
| |
| | |
| OBSERVATION THREE
| |
|
| |
| STL vectors can store your pointers, iterate thru them, etc.
| |
| for a vector of any substantial size, you want to keep objects sorted so you can find them quickly
| |
| that's what my sorted_vector class is for; it simply bolts vector together with sort calls and a b_sorted status
| |
| following STL practices, to get sorting, you have to provide operator< for whatever is in your vector
| |
| BUT... you are not allowed to do operator<(const MyObjectPtr* right) because it would require a reference to a pointer which is not allowed | |
| BUT... you can provide a FUNCTOR to do the job, then provide it when sorting/searching
| |
| a functor is basically a structure with a bool operator()(const MyObjectPtr* left, const MyObjectPtr* right)
| |
| | |
| OBSERVATION FOUR
| |
|
| |
| unordered_set works even better when combining frequent CRUD with frequent lookups
| |
| | |
| SUMMARY
| |
| Dealing with tons of objects is par for the course in any significant app.
| |
| Finding a needle in the haystack of those objects is also standard fare.
| |
| Having multiple indices into those objects is also essential.
| |
| Using unordered_set with object pointers and is very powerful.
| |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++ stl reverse iterator skeleton
| |
| |-
| |
| | From [http://www.sgi.com/tech/stl/ReverseIterator.html SGI]...
| |
| reverse_iterator rfirst(V.end());
| |
| reverse_iterator rlast(V.begin());
| |
|
| |
| while (rfirst != rlast)
| |
| {
| |
| cout << *rfirst << endl;
| |
| ...
| |
| rfirst++;
| |
| }
| |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! c++ stl reading a binary file into a string
| |
| |-
| |
| |
| |
| std::ifstream in("my.zip",std::ios::binary);
| |
| if (!in)
| |
| { | | { |
| std::cout << "problem with file open" << std::endl;
| | // Perform a regex to update the embedded version if needed. |
| return 0;
| | // We have to see if (1) we have a semver and (2) it is not the current semver. |
| | // Only then do we take action. |
| | boost::regex regex("/([v0-9.]+?)/(.*)"); |
| | boost::smatch sm_res; |
| | if (boost::regex_match(url,sm_res,regex,boost::match_default)) |
| | { |
| | string incoming_semver(sm_res[1].first,sm_res[1].second); |
| | if (incoming_semver != semanticVersion()) |
| | { |
| | url = string("/")+semanticVersion()+"/"+string(sm_res[2].first,sm_res[2].second); |
| | return true; |
| | } |
| | } |
| | return false; |
| } | | } |
| in.seekg(0,std::ios::end);
| | results: |
| unsigned long length = in.tellg();
| | original string: string(sm_res[0].first,sm_res[0].second); |
| in.seekg(0,std::ios::beg);
| | first group: string(sm_res[1].first,sm_res[1].second); |
|
| | second group: string(sm_res[2].first,sm_res[2].second); |
| string str(length,0);
| | etc. |
| std::copy(
| |
| std::istreambuf_iterator< char >(in) ,
| |
| std::istreambuf_iterator< char >() ,
| |
| str.begin()
| |
| );
| |
| | |
| For more, see [[Reading a binary file|c++ stl reading a binary file]]
| |
| |}
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! C/C++ best-in-class tool selection
| |
| |-
| |
| | I need to have easy setup of debug-level tool support for portable C++11 code. And I need to decide and stick to it to be efficient.
| |
| * '''Compiler selection'''
| |
| ** linux and mac: gcc
| |
| ** windows: Visual Studio
| |
| * '''IDE selection'''
| |
| ** linux and mac: Qt Creator
| |
| ** windows: Qt Creator (OR Visual Studio OR eclipse?)
| |
| * '''Debugger selection'''
| |
| ** linux and mac: Qt Creator
| |
| ** windows: Qt Creator (OR Visual Studio OR eclipse?)
| |
| |} | | |} |
| |} | | |} |
Line 1,389: |
Line 576: |
| |- | | |- |
| | | | | |
| | {| class="mw-collapsible mw-collapsed wikitable" |
| | ! String escape formatting across different languages and systems |
| | |- |
| | | |
| | * c++ to JSON: always use nlohmann::json j.dump() to encode, to ensure strings are properly escaped |
| | * JSON to c++: always use nlohmann::json j.parse() " |
| | * c++ to Javascript: use raw_to_Javascript() to properly escape |
| | * c++ to sqlite: use SqliteLocalModel::safestr(), which uses double_doublequotes(str) |
| | |} |
| | [[Postgres]] |
| | |
| [[Simple-Web-Server]] | | [[Simple-Web-Server]] |
| | |
| | [[Robot Operating System]] |
|
| |
|
| [[C++ https libraries]] | | [[C++ https libraries]] |
Line 1,449: |
Line 649: |
| CC=gcc-4.9 | | CC=gcc-4.9 |
| |} | | |} |
| | |} |
| | <!-- |
| | |
| | |
| | =========================================================================================================================================================================================================================================================================================== |
| | |
| | |
| | --> |
| | {| class="wikitable" |
| | ! [[git]] |
| |} | | |} |
| <!-- | | <!-- |
Line 1,458: |
Line 668: |
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! C/C++ debugging | | ! Debugging |
| |- | | |- |
| | | | | |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! Qt Creator | | ! Chrome capture large JSON variable |
| | |- |
| | | This is just pointlessly bizarre: |
| | * hit a breakpoint in the chrome debugger |
| | * right-click a variable and say "copy to global variable" (console will show name, typically "temp1") |
| | * push the variable to the clipboard by typing this in the console: |
| | copy(temp1) |
| | |} |
| | {| class="mw-collapsible mw-collapsed wikitable" |
| | ! Visual Studio Code capture large string variable |
| | |- |
| | | While debugging, you can use the Debug Console to print memory, including the content of strings that are clipped by default in the variables and watch windows. |
| | View > Open View > Debug Console |
| | From there, send gdb a command to print memory – 300 characters of a string in this example: |
| | -exec x/300sb Query.c_str() |
| | |} |
| | {| class="mw-collapsible mw-collapsed wikitable" |
| | ! Qt Creator conditional breakpoint |
| | |- |
| | | To break on line number with string condition: |
| | * Set the breakpoint on the line as usual: F9 or click in left border |
| | * In the breakpoints list, rclick Edit |
| | * Add a condition; to break on a string value, THIS WORKS: |
| | |
| | ((int)strcmp(strSymbol.c_str(), "GMO")) == 0 |
| | |
| | * BUT THERE IS A PRICE TO PAY. qt/gcc won't continue properly, unless you sset ANOTHER common breakpoint, hit it, and resume from that. It appears gcc continues (we hit the breakpoint after all), but qt does no logging or debugging, bah |
| | |} |
| | {| class="mw-collapsible mw-collapsed wikitable" |
| | ! Qt Creator and linux debug libraries |
| |- | | |- |
| | | | | |
Line 1,473: |
Line 712: |
| -- Up-to-date: /usr/local/include/libwebsockets.h | | -- Up-to-date: /usr/local/include/libwebsockets.h |
| (etc) | | (etc) |
| * valgrind is easy to use. Just find debugger pane top-left dropdown, switch mode from Debugger to Memcheck, and restart debugger.
| |
| * Signals: At some point I needed to force gdb to pass SIGINT, SIGPIPE... signals to the app instead of gdb, after ssl kept causing Qt to pop a message and break in the debugger. To do so: | | * Signals: At some point I needed to force gdb to pass SIGINT, SIGPIPE... signals to the app instead of gdb, after ssl kept causing Qt to pop a message and break in the debugger. To do so: |
| Qt Creator->Options->Debugger-> | | Qt Creator->Options->Debugger-> |
Line 1,485: |
Line 723: |
| at first i thought this would work: /usr/local/lib | | at first i thought this would work: /usr/local/lib |
| but i did a static build so i needed teh actual exe! COOL | | but i did a static build so i needed teh actual exe! COOL |
| | |} |
| | {| class="mw-collapsible mw-collapsed wikitable" |
| | ! QT Creator valgrind EASY |
| | |- |
| | | Valgrind is easy to use. Just find debugger pane top-left dropdown, switch mode from Debugger to Memcheck, and restart debugger. |
| |} | | |} |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
Line 1,561: |
Line 804: |
|
| |
|
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="wikitable" |
| ! Bootstrap | | ! [[Javascript]] |
| |- | | |}<!-- |
| |
| | |
| {| class="mw-collapsible mw-collapsed wikitable" | | |
| ! Single Page Application | | =========================================================================================================================================================================================================================================================================================== |
| |-
| | |
| | css: | | |
| <pre>
| | --> |
| .mdm-scrollable-div
| | {| class="wikitable" |
| {
| | ! [[Node.js]] |
| height: 100%;
| | |}<!-- |
| overflow: auto;
| |
| }
| |
| </pre>
| |
| html:
| |
| <pre>
| |
| <-- header -->
| |
|
| |
|
| <div class="frame" id="frame1top">
| |
| <div class="mdm-scrollable-div">
| |
| ...
| |
| </div>
| |
| </div>
| |
|
| |
|
| <-- footer -->
| | =========================================================================================================================================================================================================================================================================================== |
| </pre>
| |
| js:
| |
| <pre>
| |
| // We need to adjust layout on resize, in ready handler, and programmatically as needed.
| |
| $(window).resize(adjustLayout).resize();
| |
|
| |
|
| $( document ).ready(function() {
| |
|
| |
|
| // We need to adjust in ready handler, on resize, and programmatically as needed
| | --> |
| adjustLayout();
| | {| class="wikitable" |
| | ! [[React]] |
| | |}<!-- |
|
| |
|
| /* your other page load code here*/
| |
|
| |
|
| });
| | =========================================================================================================================================================================================================================================================================================== |
|
| |
|
| function adjustLayout(){
| |
|
| |
|
| // ----------------------
| | --> |
| // Fundamental dimensions
| | {| class="wikitable" |
| var hh = $('#theheader').outerHeight();
| | ! [[Vite]] |
| var fh = $('#thefooter').outerHeight();
| |
| var workspace_height = $(window).height() - hh - fh;
| |
| var workspace_width = $(window).width();
| |
| // ----------------------
| |
|
| |
| var cols = 1;
| |
| var col_gap = 16;
| |
|
| |
| // Margin is based on percent of one column width, so it goes to zero before column width does. :-)
| |
| // Width is based on total width minus margins, then split between columns.
| |
| var margin = ($(window).width() / cols) * .04;
| |
| var w = ($(window).width() - (margin * (cols + 1))) / cols;
| |
|
| |
| var h1 = workspace_height;
| |
|
| |
| $('#frame1top').css({
| |
| display:'block',
| |
| position:'absolute',
| |
| left: margin * 1 + w * 0,
| |
| top: hh,
| |
| width: w,
| |
| height: h1
| |
| });
| |
| }
| |
| </pre>
| |
| |} | | |} |
| {| class="mw-collapsible mw-collapsed wikitable"
| | <!-- |
| ! Button handlers
| | |
| |-
| | |
| | Buttons can be represented with labels; in that case, use a click handler:
| | =========================================================================================================================================================================================================================================================================================== |
| <pre>
| |
| jQuery('<label id="'+cycle.apsID+'" class="btn">MahButt</label>')
| |
| .appendTo('#'+chartid+'-apsbar')
| |
| .on('click', function(){
| |
| $(location).attr('href','/v1/parameters/'+this.id+'.html');
| |
| });
| |
| </pre>
| |
| You can also get the checked state, and prevent the button from being pressed, among other things:
| |
| <pre>
| |
| jQuery('<label id="'+cycle.run+'" ...
| |
| .on('click', function(e){
| |
| var run = this.id;
| |
| // Look for the (label->input)
| |
| if (this.firstChild.checked)
| |
| ...
| |
| // To prevent checked/pressed state if desired:
| |
| e.stopPropagation();
| |
| }
| |
| </pre>
| |
| Button bars are represented by labels wrapped around inputs:
| |
| <pre>
| |
| <div class="btn-group live-buttons" data-toggle="buttons"><div class="btn-group"><label class="btn"><input type="checkbox">text...
| |
| </pre>
| |
| In that case use a change handler on the input:
| |
| <pre>
| |
| var label = jQuery('<label class="btn btn-sm btn-'+color+'"></label>').appendTo(action_button_bar);
| |
| var input = jQuery('<input class="run-'+cmd+'" type="checkbox" autocomplete="off" value="'+cycle.run+'">').appendTo(label)
| |
| .on('change', cycle.owned? function(){
| |
| patchPick(this.value,'{ "action" : "run-hold" }');
| |
| } : function() {
| |
| patchPick(this.value,'{ "action" : "run-buy" }');
| |
| });
| |
| var text = jQuery('<span class="glyphicon glyphicon-'+glyph+'"></span> <span class="hidden-xs">'+cmd+'</span>').appendTo(label);
| |
| </pre>
| |
| If you just need clicks from the button bar, you do NOT NEED input:
| |
| <pre>
| |
| <div class="btn-group live-buttons" data-toggle="buttons"><div class="btn-group"><label class="btn">text...
| |
| </pre>
| |
| Then you can put the change handler right on the label:
| |
| <pre>
| |
| var applybar = jQuery('<div id="applybar-'+cycle.run+'" class="btn-group pull-right" data-toggle="buttons" />');
| |
| var apply_button = jQuery('<label id="apply-'+cycle.run+'" class="btn btn-sm btn-moneygreen"><span class="glyphicon glyphicon-ok"></span><span class="hidden-xs"> Apply</span></input></label>')
| |
| .on('click', function(e) {
| |
|
| |
| // Do work
| |
|
| |
|
| e.stopPropagation();
| |
| })
| |
| .appendTo(applybar)
| |
| ;
| |
| </pre>
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Programmatically pressing a button
| |
| |-
| |
| | You MUST DO TWO THINGS:
| |
| * Set the active class on the button/label
| |
| * Set the input to checked
| |
| <label class="btn active">
| |
| <input type="checkbox" autocomplete="off" checked>
| |
| Click me
| |
| </label>
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Collapsible panel
| |
| |-
| |
| |
| |
| * Use a unique id on content div, data-target to connect panel header to content, mdm-panel-collapser so javascript can find icon, abt-scrollable-panel for margin.
| |
| * HTML for each panel (starts collapsed)
| |
| <pre>
| |
| <div class="panel panel-default abt-scrollable-panel">
| |
| <div class="panel-heading collapsed" data-toggle="collapse" data-target="#my-content-block-one">Software development skills<span class="mdm-panel-collapser text-muted glyphicon glyphicon-chevron-down pull-right"></span></div>
| |
| <div class="collapse" id="my-content-block-one">
| |
| <div class="mdm-panel-body">
| |
|
| |
| <!-- CONTENT, can include another nested panel, just add .mdm-nested-panel to class; example: -->
| |
|
| |
| <div class="panel panel-default mdm-scrollable-panel mdm-nested-panel">
| |
| <div class="panel-heading collapsed mdm-job-panel-heading" data-toggle="collapse" data-target="#toshiba-job"><p><strong>Senior Developer and Offshore Manager</strong><i> - Toshiba Global Commerce Solutions, Inc.</i><span class="mdm-panel-collapser text-muted glyphicon glyphicon-chevron-up pull-right"></span></p><p><small>April 2014 – August 2015</small></p></div>
| |
| <div class="collapse in" id="toshiba-job">
| |
| <div class="mdm-panel-body">
| |
| <!-- SUBCONT(IN)ENT im so funny -->
| |
| </div>
| |
| </div>
| |
| </div>
| |
|
| |
|
| |
|
| </div>
| | --> |
| </div>
| | {| class="wikitable" |
| </div>
| | ! [[JSON]] |
| </pre>
| |
| * For an expanded panel, simply change icon from down to up, and add "in" to content div:
| |
| <pre>
| |
| ... glyphicon-chevron-up ...
| |
| <div class="collapse in mdm-panel-body" id="collapseOrderItems1">
| |
| </pre>
| |
| * Define Javascript collapser once on load
| |
| $('.collapse').on('hide.bs.collapse show.bs.collapse',
| |
| toggleCollapser
| |
| );
| |
| * CSS
| |
| .mdm-nested-panel {
| |
| margin-top: 1em;
| |
| margin-left: 1em;
| |
| }
| |
| collapse.mdm-panel-body collapsing.mdm-panel-body {
| |
| margin: 1em;
| |
| }
| |
| * Common reusable function:
| |
| function toggleCollapser(e) {
| |
| $(e.target)
| |
| .prev('.panel-heading')
| |
| .find('.mdm-panel-collapser')
| |
| .toggleClass('glyphicon-chevron-down glyphicon-chevron-up');
| |
|
| |
| // Prevent bubble up to any parent collapsers.
| |
| // This allows nested collapsers, whoop.
| |
| e.stopPropagation();
| |
| }
| |
| |}
| |
| |} | | |} |
| <!-- | | <!-- |
Line 1,765: |
Line 851: |
|
| |
|
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="wikitable" |
| ! D3 | | ! [[HTML]] |
| |-
| |
| |
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! ALWAYS initialize incoming data
| |
| |-
| |
| | Hard-earned data-import lessons:
| |
| * tsv() will do complete date formatting, so when you remove it to use JSON directly, you HAVE TO convert JSON timestamps of ANY kind to full Javascript date objects:
| |
| var data = [{"date":"2017-04-01T04:00:00.000Z",...
| |
| // MDM WE MUST MASSAGE DATA HERE
| |
| // JSON VALUES ARE ALWAYS STRINGS, we need to change to Javascript DATE!
| |
| // Incoming datasets need a bit of massaging.
| |
| // We do that in a function so we can reuse it on incoming dataset updates.
| |
| function initializeDataset(dataset) {
| |
| // TIME ON X
| |
| // Convert date strings to actual date values.
| |
| // MDM MAKE SURE this matches the incoming format.
| |
| // Adding date so we can run the chart across days without trouble.
| |
| // var parseDate = d3.time.format("%H:%M:%S %m-%d-%Y").parse;
| |
| // var parseDate = d3.timeParse("%Y %b %d");
| |
| var parseDate = d3.utcParse("%Y-%m-%dT%H:%M:%S.%LZ");
| |
| dataset.forEach(function(d) {
| |
| // there is NO SKIPING THIS STEP, you have to get valid Javascript date objects out of JSON strings
| |
| d.date = parseDate(d.date);
| |
| // we WOULD have to divide all data by zero,
| |
| // but we already grabbed post-data that was already converted
| |
| // This WORKS but makes data / 10000 (very small numbers)
| |
| //for (var i = 1, n = dataset.columns.length; i < n; ++i) d[dataset.columns[i]] = d[dataset.columns[i]] / 100;
| |
| });
| |
| }
| |
| initializeDataset(data);
| |
|
| |
| * tsv() will create an ARRAY but it also jams in a columns PROPERY; it takes two steps to duplicate that:
| |
| var data = [
| |
| {"date":"2015-06-15T04:00:00.000Z","Google Chrome":0.48090000000000005,...},
| |
| {"date":"2015-06-22T04:00:00.000Z","Google Chrome":0.48979999999999996,...),
| |
| ];
| |
| data.columns = ["date","Google Chrome","Internet Explorer",... ];
| |
| |} | | |} |
| {| class="mw-collapsible mw-collapsed wikitable"
| | <!-- |
| ! ALWAYS set range and domain properly
| | |
| |-
| | |
| | You have to know your display size (range) and the min and max of your data (domain), on each axis. From [https://bost.ocks.org/mike/bar/ Mike's docs]:
| | =========================================================================================================================================================================================================================================================================================== |
| | |
|
| |
|
| D3’s scales specify a mapping from data space (domain) to display space (range).
| | --> |
| D3’s scales can also be used to interpolate many other
| | {| class="wikitable" |
| types of display-space values, such as paths, color spaces
| | ! [[CSS]] |
| and geometric transforms.
| |
|
| |
| var x = d3.scale.linear()
| |
| .domain([0, d3.max(data)])
| |
| .range([0, 420]);
| |
|
| |
| Although x here looks like an object, it is also a function
| |
| that returns the scaled display value in the range
| |
| for a given data value in the domain.
| |
| For example, an input value of 4 returns 40, and an input value of 16
| |
| returns 160. To use the new scale, simply replace the
| |
| hard-coded multiplication by calling the scale function:
| |
|
| |
| d3.select(".chart")
| |
| .selectAll("div")
| |
| .data(data)
| |
| .enter().append("div")
| |
| .style("width", function(d) { return x(d) + "px"; })
| |
| .text(function(d) { return d; });
| |
| Watch out for Mike's examples where he (trickily) doesn't bother to set a domain because his data is in the [0..1] set, and that's the default domain, apparently.
| |
| |} | | |} |
| |}<!--
| | <!-- |
|
| |
|
|
| |
|
Line 1,842: |
Line 872: |
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! RESTFul http | | ! SQL |
| |- | | |- |
| | | | | |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! Verbs | | ! Count records within a range |
| |- | | |- |
| | | | | This groups records into ranges, sorts by them, and gives a count, sweet: |
| * get - to make requests that are simple -response may be complex | | select count(*), id/1000000 as groupid from AccountHistory group by groupid; |
| * post - to push a form or JSON to the server
| |
| |} | | |} |
| | [[postgres]] - [[sqlite]] - [[mysql]] - [[SQL Server]] - [[Robo 3T]] - [[DBeaver]] - [[pgadmin4]] |
| |} | | |} |
| <!-- | | <!-- |
Line 1,860: |
Line 890: |
|
| |
|
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="wikitable" |
| ! Javascript and JQuery | | ! [[Meteor]] |
| |-
| | |} |
| | | | <!-- |
| {| class="mw-collapsible mw-collapsed wikitable"
| | |
| ! Formatting examples (numbers dates etc.)
| | |
| |-
| | =========================================================================================================================================================================================================================================================================================== |
| |
| |
| // Javascript sucks at dates.
| |
| // d3 to the rescue!
| |
| var parseInitDate = d3.utcParse("%Y-%m-%dT%H:%M:%SZ");
| |
| var initDate = parseInitDate(initial_managed_value_date);
| |
| var initDateString =
| |
| initDate.getUTCFullYear()
| |
| +"/"+ (initDate.getUTCMonth()+1)
| |
| +"/"+ initDate.getUTCDate()
| |
| + " " + initDate.getUTCHours()
| |
| + ":" + initDate.getUTCMinutes()
| |
| + ":" + initDate.getUTCSeconds();
| |
|
| |
|
| var rightNow = new Date;
| |
| var initToNow_DecimalDays = parseFloat(rightNow - initDate) / 864e5; // 86,400,000 ms/day
| |
| var initToNow_PercentOfYear = initToNow_DecimalDays / 365.0;
| |
| var change_in_value = (parseFloat(total_managed_value) - parseFloat(initial_managed_value))/parseFloat(initial_managed_value);
| |
|
| |
|
| $('#initial_managed_value').val(initial_managed_value.toFixed(2));
| | --> |
| $('#initial_managed_value_date').val(initDateString);
| | {| class="wikitable" |
| $('#change_in_value').val((change_in_value*100.0).toFixed(1)+ "%");
| | ! [[Android]] |
| $('#equivalent_apr').val((change_in_value/initToNow_PercentOfYear*100.0).toFixed(1)+ "%");
| |
| $('#total_managed_value_readonly').val(total_managed_value.toFixed(2));
| |
| |} | | |} |
| {| class="mw-collapsible mw-collapsed wikitable"
| | <!-- |
| ! Array vs Object lifetime
| | |
| |-
| | |
| |
| | =========================================================================================================================================================================================================================================================================================== |
| // If the JSON data were an array, we would need to slice-to-clone to keep it around:
| | |
| // var dataCopy = data.slice();
| | |
| // updateStockData(run,dataCopy);
| | --> |
| // We have an object so we can pass a reference, and it will keep the object around.
| | {| class="wikitable" |
| | ! [[Arduino]] |
| |} | | |} |
| {| class="mw-collapsible mw-collapsed wikitable"
| | <!-- |
| ! Event handlers
| | |
| |-
| | |
| | Three basic methods:
| | =========================================================================================================================================================================================================================================================================================== |
| * Attach a function to an event of a specific element; charts.js example:
| |
| var label = jQuery('<label class="btn btn-sm btn-'+color+'"></label>').appendTo(action_button_bar);
| |
| var input = jQuery('<input class="run-'+cmd+'" type="checkbox" autocomplete="off" value="'+cycle.run+'">').appendTo(label)
| |
| .on('change', cycle.owned? function(){
| |
| patchPick(this.value,'{ "action" : "run-hold" }');
| |
| } : function() {
| |
| patchPick(this.value,'{ "action" : "run-buy" }');
| |
| });
| |
| var text = jQuery('<span class="glyphicon glyphicon-'+glyph+'"></span> <span class="hidden-xs">'+cmd+'</span>').appendTo(label);
| |
|
| |
|
| * Add a function handler once, for a class of elements; picks.js example:
| | --> |
| $("input[type='checkbox'][class='run-top' ]").change(function() { patchPick(this.value,'{ "action" : "run-move-top" }'); });
| | {| class="wikitable" |
| * Event delegation: Javascript takes events and "bubbles them up" through the chain of parents; set up a handler on a parent to listen for these bubbles.
| | ! [[Raspberry Pi]] |
| |} | | |} |
| {| class="mw-collapsible mw-collapsed wikitable"
| | <!-- |
| ! Debug clicks on ANY PAGE
| | |
| |-
| | |
| |
| | =========================================================================================================================================================================================================================================================================================== |
| * Press F12 => Sources => Event Listener Breakpoints righthand pane => Mouse => [x] click
| | |
| B O O M we have it captured and can step into ANYTHING.
| | --> |
| |}
| | {| class="wikitable" |
| {| class="mw-collapsible mw-collapsed wikitable" | | ! [[iOS]] |
| ! JWT flow | |
| |-
| |
| | Client is easy!
| |
| <pre>
| |
| Client application API
| |
| -------- -----------
| |
| | |
| |
| | GET /api/employees |
| |
| |----------------------------------------------------->|
| |
| | 403 Forbidden |
| |
| |<-----------------------------------------------------|
| |
| | |
| |
| | |
| |
| | POST /api/authenticate |
| |
| | { login: "john.doe", password: "password" } |
| |
| |----------------------------------------------------->|
| |
| | 200 Success |
| |
| | { token: "my.personal.token" } |
| |
| |<-----------------------------------------------------|
| |
| | |
| |
| | |
| |
| | GET /api/employees |
| |
| | Header { "Authorization: Token "my.personal.token" } |
| |
| |----------------------------------------------------->|
| |
| | 200 Success |
| |
| |<-----------------------------------------------------|
| |
| | |
| |
| </pre>
| |
| |} | | |} |
| | <!-- |
| | |
| | |
| | =========================================================================================================================================================================================================================================================================================== |
| | |
| | |
| | --> |
| | {| class="wikitable" |
| | ! [[.NET Core]] |
| |} | | |} |
| <!-- | | <!-- |
Line 1,963: |
Line 948: |
|
| |
|
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Node.js
| |
| |-
| |
| |
| |
| {| class="wikitable" | | {| class="wikitable" |
| ! [[Node.js]] installation | | ! [[Java]] |
| |} | | |} |
| | <!-- |
| | |
| | |
| | =========================================================================================================================================================================================================================================================================================== |
| | |
| | |
| | --> |
| {| class="wikitable" | | {| class="wikitable" |
| ! [[Node create a new module]] | | ! [[Kotlin]] |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Register with npm
| |
| |-
| |
| | A one-time registration is required on a new machine if you want to publish from it:
| |
| npm adduser
| |
| Username: moodboom
| |
| Password: (see private)
| |
| Email: (this IS public) moodboom@gmail.com
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Publish a node module
| |
| |-
| |
| |
| |
| sudo npm install -g # keep doing this until you are happy with local install
| |
| # update version in package.json
| |
| # this creates a FULL "annotated" tag, not a "lightweight" tag that doesn't show up for [git describe] - it also removes the need for a separate commit
| |
| git tag -a 1.0.5 -m "changes include..."
| |
| git push && git push --tags # NOTE: bitpost has a git hook to push changes all the way up to github
| |
| npm publish
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Update a node module's dependencies
| |
| |-
| |
| |
| |
| # make sure dependency in package.json has a carat at the beginning of its version (^x means "at least" version x)
| |
| # make sure the dependency has a new version available - completely publish it first if it is your own
| |
| # then you can simply reinstall from within the module folder to get all dependencies upgraded
| |
| sudo npm install -g
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Develop several node modules at once
| |
| |-
| |
| | Convert dependencies to use local packages instead of published versions, eg:
| |
| cd ~/development/mah-haus
| |
| npm install -S /home/m/development/thedigitalage/rad-scripts
| |
| Then reinstall everything (local dependent modules, then parent modules, pita - consider links if doing longer-term dev)
| |
| sudo npm install -g
| |
| Then convert back to published versions as they become available (it's up to me to stabilize and publish new module versions):
| |
| cd ~/development/mah-haus
| |
| npm install -S rad-scripts
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! auto AWS
| |
| |-
| |
| |
| |
| * npm install -g aws-sdk
| |
| * Add credentials here: C:\Users\Administrator\.aws
| |
| * see existing scripts, anything is possible
| |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! install bootstrap
| |
| |-
| |
| |
| |
| * npm install -g grunt-cli
| |
| * mkdir mysite && cd mysite
| |
| * npm install bootstrap
| |
| * cd node_modules/bootstrap
| |
| * npm install # to actually pull down dependencies
| |
| * grunt dist # builds and minifies so you're good to go!
| |
| |}
| |
| |} | | |} |
| <!-- | | <!-- |
Line 2,041: |
Line 968: |
|
| |
|
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="wikitable" |
| ! css | | ! [[Maven]] |
| |-
| |
| |
| |
| /* class="first second" */
| |
| .first.second {}
| |
| /* class="first" OR class="second" */
| |
| .first, .second {}
| |
| /* class="first second", or class="second", or class="third second", or class="second third" */
| |
| .second {}
| |
| /* apply to any .child at any depth under .parent */
| |
| .parent .child {}
| |
| /* apply to .child if it is DIRECTLY under .parent */
| |
| .parent > .child {}
| |
| | |
| |} | | |} |
| <!-- | | <!-- |
Line 2,064: |
Line 978: |
|
| |
|
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="wikitable" |
| ! SQL | | ! [[Scala]] |
| |-
| |
| |
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Sqlite timestamp-to-readable-date query
| |
| |-
| |
| |
| |
| select quote, strftime('%d-%m-%Y %H:%M:%S', datetime(timestamp, 'unixepoch')) from StockQuotes as s where s.symbol="TSLA" order by timestamp;
| |
| |}
| |
| |} | | |} |
| <!-- | | <!-- |
Line 2,083: |
Line 989: |
| --> | | --> |
| {| class="wikitable" | | {| class="wikitable" |
| ! [[Java]] | | ! [[Python]] |
| |} | | |} |
| <!-- | | <!-- |
Line 2,093: |
Line 999: |
| --> | | --> |
| {| class="wikitable" | | {| class="wikitable" |
| ! [[Scala]] | | ! [[Go]] |
| |} | | |} |
| <!-- | | <!-- |
Line 2,127: |
Line 1,033: |
| --> | | --> |
| {| class="wikitable" | | {| class="wikitable" |
| ! [[git]] | | ! [[Bash basics]] but please prefer node or python :-) |
| |} | | |} |
| <!-- | | <!-- |