|
|
(34 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 59: |
Line 64: |
| |- | | |- |
| | Among competing hypotheses, the one with the fewest assumptions should be selected. | | | Among competing hypotheses, the one with the fewest assumptions should be selected. |
| |}
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Security
| |
| |-
| |
| | Notes to review before interviews, etc:
| |
|
| |
| ---------------------------
| |
| fedramp cloud certification
| |
| ---------------------------
| |
| strong encryption, eg AES 256-bit
| |
| data should be encrypted before it leaves end-user "organization"
| |
| encrypt: data-at-rest, data-in-transit, data-in-use
| |
| encryption keys MUST be kept within end-user org
| |
| CSP requirements: implement security, third-party assess, maintain authorization, comply with continous monitoring
| |
|
| |
| basics review
| |
|
| |
| public-private key
| |
| ------------------
| |
| plain -> encrypted -> plain
| |
| ^ ^
| |
| publickey privatekey
| |
|
| |
|
| |
| SSL HANDSHAKE
| |
| -------------
| |
| client server
| |
| -> hello ->
| |
| < cert
| |
| (check)
| |
| send secret encryped with server public key > decrypt secret)
| |
| (opt) send client cert > (check - but not otherwise used?)
| |
| ack>
| |
| <ack
| |
| exchange with shared secret key
| |
|
| |
| best encryption to date
| |
| ssl labs:
| |
| Key RSA 2048 bits (e 65537)
| |
| signature SHA256withRSA
| |
| certchain includes Let's Encrypt Authority X3, RSA 2048 bits, Signature: SHA256withRSA
| |
| TLS 1.2 (not allowed: TLS 1.1, 1.0; SSL 3, SSL 2
| |
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f) ECDH secp256r1 (eq. 3072 bits RSA) FS 128
| |
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027) ECDH secp256r1 (eq. 3072 bits RSA) FS 128
| |
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013) ECDH secp256r1 (eq. 3072 bits RSA) FS 128
| |
| TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x9e) DH 2048 bits FS 128
| |
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x67) DH 2048 bits FS 128
| |
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x33) DH 2048 bits FS
| |
|
| |
| review
| |
|
| |
| AES 256-bit for encryption
| |
| aka Rijndael, which won in the original NIST AES selection process (in 2001!)
| |
| symmetric key algorithm (same key to encrypt and decrypt)
| |
| block size 128
| |
| key length 256 (can be 128 and 192)
| |
|
| |
| SHA-256 for signatures
| |
| a bit-specific SHA-2
| |
| deprecates SHA-1
| |
| NOT deprecated by SHA-3 (an alternative developed through NIST competition)
| |
| 256-bit "hash values" aka digests aka signatures)
| |
| server + client ssl certificate process
| |
|
| |
| HMAC is a signature with a key - what I'm doing with JWT (HMAC-SHA256)
| |
|
| |
| broken: RC2 RC4 DES IDEA ...
| |
|
| |
| next-gen: https://security.stackexchange.com/questions/135054/whats-after-aes
| |
| TLS 1.3, which is still a draft, is going with two authenticated ciphers as its required choices:
| |
| AES-GCM, with either 128- or 256-bit keys;
| |
| ChaCha20/Poly1305
| |
| The reasons we have two are the following:
| |
| As a backup—if one of them is broken, everybody can switch to the other;
| |
| They have different strengths:
| |
| AES-GCM has excellent hardware support in many platforms;
| |
| ChaCha20/Poly1305 has faster all-software implementations than AES-GCM does.
| |
|
| |
| good for https with SSL certs, according to SSL labs:
| |
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f) ECDH secp256r1 (eq. 3072 bits RSA) FS 128
| |
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027) ECDH secp256r1 (eq. 3072 bits RSA) FS 128
| |
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013) ECDH secp256r1 (eq. 3072 bits RSA) FS 128
| |
| TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x9e) DH 2048 bits FS 128
| |
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x67) DH 2048 bits FS 128
| |
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x33) DH 2048 bits FS
| |
|
| |
|
| |
| NIST (National Institute of Standards and Technology)
| |
|
| |
| SHA-3 competition 2007-2012 (SHA = Secure Hash Algorithm)
| |
| 64 entries
| |
| 5 finalists: BLAKE, Grøstl, JH, Keccak and Skein
| |
| winner: Keccak
| |
| schneier's feedback:
| |
| Yes, I would have rather my own Skein had won, but it was a good choice.
| |
|
| |
| NSA has Suite A (classified algorithms that will not be released) and Suite B cryptography algorithms
| |
| Suite B's components are:
| |
|
| |
| Advanced Encryption Standard (AES) with key sizes of 128 and 256 bits.
| |
| For traffic flow, AES should be used with either
| |
| the Counter Mode (CTR) for low bandwidth traffic or
| |
| the Galois/Counter Mode (GCM) mode of operation for high bandwidth traffic (THIS CAN BE PARALLELIZED)
| |
| Elliptic Curve Digital Signature Algorithm (ECDSA) – digital signatures
| |
| Elliptic Curve Diffie–Hellman (ECDH) – key agreement
| |
| Secure Hash Algorithm 2 (SHA-256 and SHA-384) – message digest
| |
|
| |
| talk about my projects
| |
|
| |
| nopc
| |
| energy market
| |
| need to measure power behind the consumers meter
| |
| i wrote a client that lives on embedded devices
| |
| i cross-compiled openssl, libmodbus, libcurl, libwebsockets, zlib
| |
|
| |
| ssl / websockets work:
| |
| libwebsockets uses openssl, but i have played a bit with optional ssl: wolfssl
| |
| has streaming media support, including the HC-128 and RABBIT stream ciphers
| |
| Standard ciphers are supported, including EDH on both the client and server side.
| |
| wolfSSL recently added support for BLAKE2b, one of the SHA-3 finalists as well.
| |
| wolfSSL’s underlying cryptography library is called wolfCrypt.
| |
| i wouldn't want to stray from openssl unless there was a more compelling reason, since it gets so many eyeballs on it
| |
| people don't like its depth of support for other algorithms, just stick with best-in-class
| |
| Key RSA 2048 bits (e 65537)
| |
| signature SHA256withRSA
| |
| pki: rsa
| |
|
| |
| given a guid token, it uses that to generate ssl certs on the device
| |
| then it runs 24/7 on the embedded device
| |
| it has a tight loop with callbacks, C is gross but you can do pretty much anything
| |
| in factthats the problem, you have to do everything!
| |
| again, i heavily rely on reusable helpers
| |
| so it has a single-threaded loop with callbacks
| |
| poll:
| |
| if !config configure client
| |
| else poll and store meter data, buffered to memory then volatile then nonvolatile storage
| |
| if ws not connected initiate connection
| |
| service the connection callbacks (sending bi-directionally as needed)
| |
|
| |
| just added jwt to abettertrader
| |
| uses HMAC-SHA256 (uses a secret during signature generation)
| |
| client sends u/p
| |
| server builds header+payload+HMAC-SHA256 signature with its own secret
| |
| server sends back base64-encoded token to client
| |
| client uses token on every API call
| |
| when token times out, user must log in again
| |
| server can almost instantly determine user's priviledges without a db hit
| |
| that's why they call it stateless
| |
|
| |
| abettertrader c++ based webserver, gets A+ rating at ssllabs
| |
| via haproxy!
| |
| I serve up several domains from my home
| |
| most of them use SNI with apache
| |
| with SNI the hostname is sent outside of the encrypted traffic
| |
| so you can serve up different apache sites based on the requested hostname
| |
| it's fantastic - for years i had to serve up my different sites on different ports
| |
| and it was hard to do https that way
| |
| but! ... i'm running a C++ https server as well
| |
| and i had to solve the problem of getting incoming https traffic to that server running on that port
| |
| haproxy is THE BOMB for these kinds of things
| |
| i configured haproxy to read the domain name and redirect traffic to the c++ http server and port
| |
| but i am so excited about this, i got these bonuses with zero effort:
| |
| ALL ssl handshaking is now done by haproxy! i just give it ALL my certs, and it does the negotiations
| |
| i was able to limit availabe ciphers to those listed as secure at ssllabs
| |
| ssl-default-bind-options no-sslv3 no-tls-tickets force-tlsv12
| |
| ssl-default-bind-ciphers AES128+EECDH:AES128+EDH
| |
| ALSO i was able to turn on HSTS - this forces all http requests into https requests
| |
| and that got me an A+ rating on ssllabs - for ALL My sites - in one fell swoop!
| |
| i felt like that giant that killed 7 flies or whatever
| |
|
| |
| abettertrader uses a map of lambas and regexs
| |
| when a url comes in, it plays it against all the registered regexs
| |
| if it finds a match, it calls the lambda
| |
| it's really fast and really fun
| |
|
| |
| i set up node.js scripting for my continuous integration
| |
| i have an open source package called radscripts - it does an automatic semver bump on every commit
| |
| i'm totally addicted to that
| |
| you can turn it off and still get all the benefits -
| |
| i turned off auto-tagging at causam because they wanted to control the specific numbers of releases
| |
| but semver dictates: ...
| |
|
| |
| i am always tinkering, i keep track of my projects in phabricator, an agile ticket tool that sprang out of facebook
| |
| do you want to see it?
| |
| willcodeforcoffee.org moodboom/G
| |
|
| |
| write a c++ app that sorts an array then encrypts it then decrypts it
| |
| int main() {
| |
| return 0;
| |
| }
| |
|
| |
| review c++11, c++14, interview questions
| |
| RAII resource acquisition is initializaztion- constructor acquires, destructor releases
| |
|
| |
| c++
| |
| c++11 features I love:
| |
| automatic type detection - this is great esp for iterators so you don't have to type as much
| |
| for loops
| |
| if you don't need to walk forwards or backwards as you loop, these greatly simplify code profile
| |
| but if you need the iterator as you loop, you can stick with the old way
| |
| lambda expressions - really fast to write inline functions
| |
| move semantics - you don't have to copy out results when you're done in a function, you can move them - and it's largely automatic, really nice
| |
| initialization syntax - i love this for creating test data, you can easily initialize big arrays, whatever, right in code
| |
| delegating constructors - this si great, so you don't have to rewrite all the base class constructors to be able to add a new one
| |
| threading - a lot of this is available with boost - but it's nice to have the standard incorporate all the best boost work
| |
| c++14 seems much more incremental than 11 was
| |
| you can use auto for function return types - that was already how lambdas worked in c++11, i thought...
| |
| lamdba parameters can be auto - kind of like templating, seems really crazy and cool - haven't played with this much yet
| |
| and closures, how cool is that!!! "lambda captures" it carries along the scope from where it was called.
| |
| javascript of course makes us a huge fan of this.
| |
| but i wonder about the performance penalty involved. - again, haven't played with it much
| |
| deprecated keyword, binary literals
| |
| and then c++17 is on the way - c++ has always made me happy, i find it incredibly elegant compared to lower C or higher java/C# arenas
| |
| i think javascript actually hits a sweeter spot than those
| |
| so i'm enjoying C++ and javascript more than anything these days
| |
| i wrote some utilities in node so i can use node for scripting, which has been really productive
| |
| but i have to say, python would be a welcome addition
| |
|
| |
| c++ containers
| |
|
| |
| i use hashmaps of pointers via unordered_map
| |
| unordered set lets you contain pointers, and specify the hash and equals values for the object pointed to
| |
| typedef std::unordered_set<AutotradeParameterSet*,PersistentIDObject_hash,PersistentIDObjects_equal > AutotradeParameterSets;
| |
| then you can set up a second "index" into the object store
| |
| you have to maintain all indexes as you add and remove, of course
| |
|
| |
| unordered_map uses the hash to find the right bucket O(1)
| |
| map uses a binary tree and a comparison operator O(log(n))
| |
| std::find() on vector uses quicksort O(N*log(n)) or insertsort which uses heapsort for worst case
| |
| mergesort is good to preserve order of equal items (in-place)
| |
|
| |
| python has TimSort, pretty cool - looks for presorted sections, then merges those, COOL
| |
| in use in python since about 2002
| |
|
| |
| i also use a sorted vector class i derived from the standard vector class
| |
| it too can use pointers instead of objects, allowing for multiple indexes on a set of objects
| |
| it has push_unsorted(), bSorted() and sort(sort_function) functions
| |
| usually with vectors you use lower_bound to find things
| |
| sorted vector has find helpers, and they always sort if unsorted
| |
| it's really useful when you have a huge amount of objects and only sort on occasion
| |
|
| |
| - nagging question: how do you add functionality to a product that's new?
| |
| this was a very valuable question that I didn't answer well
| |
| can i ammend my answer?
| |
| i mentioned that I would diagram function flows - that would definitely be a key strategy
| |
| and to read any and all available documentation on the software
| |
| what should have also been part of my answer:
| |
| generate my own documentation as needed
| |
| a fantastic tool for that is doxygen
| |
| i ran it yesterday against a recent project, and it did a nice job creating class hierarchies etc.
| |
|
| |
| clang-tidy is suggested to be the best on reddit
| |
| even has a -fix flag to fix in place, ha
| |
| cmake can call it for you!!
| |
| cppcheck
| |
| coverity for Paid solutions
| |
|
| |
| jsonlint
| |
| |} | | |} |
| |} | | |} |
Line 829: |
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 889: |
Line 649: |
| CC=gcc-4.9 | | CC=gcc-4.9 |
| |} | | |} |
| | |} |
| | <!-- |
| | |
| | |
| | =========================================================================================================================================================================================================================================================================================== |
| | |
| | |
| | --> |
| | {| class="wikitable" |
| | ! [[git]] |
| |} | | |} |
| <!-- | | <!-- |
Line 898: |
Line 668: |
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! C/C++ debugging | | ! Debugging |
| |- | | |- |
| | | | | |
| | {| class="mw-collapsible mw-collapsed wikitable" |
| | ! 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" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! Qt Creator conditional breakpoint | | ! Qt Creator conditional breakpoint |
Line 1,017: |
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
| |
| {
| |
| 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() {
| | --> |
| | {| class="wikitable" |
| | ! [[Node.js]] |
| | |}<!-- |
|
| |
|
| // We need to adjust in ready handler, on resize, and programmatically as needed
| |
| adjustLayout();
| |
|
| |
|
| /* your other page load code here*/
| | =========================================================================================================================================================================================================================================================================================== |
|
| |
|
| });
| |
|
| |
|
| function adjustLayout(){
| | --> |
| | {| class="wikitable" |
| | ! [[React]] |
| | |}<!-- |
|
| |
|
| // ----------------------
| |
| // Fundamental dimensions
| |
| var hh = $('#theheader').outerHeight();
| |
| 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"
| |
| ! Handling the UNCHECK event on a pushbutton
| |
| |-
| |
| | Again you MUST SET BOTH active and checked STATES PROPERLY when creating the button (see above). Do not set either if the button is unpressed; set both if it is pressed.
| |
|
| |
|
| Then you can use a single change event:
| |
| $("input[type='checkbox'][class='run-hold-on-buy' ]").change(function() { patchPick(this.value,'{ "action" : "'+(this.checked?'hold-on-buy-on' :'hold-on-buy-off' )+'"}'); });
| |
| |}
| |
| {| 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>
| | ! [[Vite]] |
| </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,229: |
Line 841: |
|
| |
|
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="wikitable" |
| ! D3 | | ! [[JSON]] |
| |-
| |
| |
| |
| {| 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
| | ! [[HTML]] |
| 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,305: |
Line 861: |
|
| |
|
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="wikitable" |
| ! Vega-lite | | ! [[CSS]] |
| |-
| |
| |
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Coloring by numbers
| |
| |-
| |
| |
| |
| | |
| "color": {
| |
| "field": "year",
| |
| "type": "ordinal",
| |
| "scale": {
| |
| "domain": [1955, 2000],
| |
| "range": ["#e6959c", "#911a24"]
| |
| },
| |
| "legend": {
| |
| "title": "Year"
| |
| }
| |
| },
| |
| "size": {"value": 100},
| |
| | |
| |} | | |} |
| |}<!--
| | <!-- |
|
| |
|
|
| |
|
Line 1,336: |
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,354: |
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);
| |
| $('#change_in_value').val((change_in_value*100.0).toFixed(1)+ "%");
| |
| $('#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="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.
| | ! [[Android]] |
| * At end of handler, prevent further bubbling with stopPropagation() - still finishes the current event (eg following the href of an <a>):
| |
| <pre>
| |
| var datepicker = jQuery(
| |
| '<div class="input-group date form-inline pull-left" data-provide="datepicker" id="datepicker'+cycle.run+'">'+
| |
| '<input type="text" class="input-sm form-control">'+
| |
| '<div class="input-group-addon">'+
| |
| '<span class="glyphicon glyphicon-th"></span>'+
| |
| '</div>'+
| |
| '</div>'
| |
| )
| |
| .on('changeDate', function(e){
| |
| alert('next '+cycle.run);
| |
| e.stopPropagation();
| |
| })
| |
| ;
| |
| </pre>
| |
| * Or use preventDefault() to stop completely:
| |
| <pre>
| |
| var datepicker_next = jQuery(
| |
| '<a href="">My javascript action</a>'
| |
| )
| |
| .on('click', function(e){
| |
| alert('next '+cycle.run);
| |
| e.preventDefault();
| |
| })
| |
| ;
| |
| </pre>
| |
| |}
| |
| {| 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="mw-collapsible mw-collapsed wikitable"
| |
| ! 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>
| |
| |}
| |
| |} | | |} |
| <!-- | | <!-- |
Line 1,484: |
Line 910: |
|
| |
|
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Node.js
| |
| |-
| |
| |
| |
| {| class="wikitable" | | {| class="wikitable" |
| ! [[Node.js]] installation | | ! [[Arduino]] |
| |} | | |} |
| | <!-- |
| | |
| | |
| | =========================================================================================================================================================================================================================================================================================== |
| | |
| | --> |
| {| class="wikitable" | | {| class="wikitable" |
| ! [[Node create a new module]] | | ! [[Raspberry Pi]] |
| |}
| |
| {| 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!
| |
| |} | | |} |
| | <!-- |
| | |
| | |
| | =========================================================================================================================================================================================================================================================================================== |
| | |
| | --> |
| | {| class="wikitable" |
| | ! [[iOS]] |
| |} | | |} |
| <!-- | | <!-- |
Line 1,562: |
Line 938: |
|
| |
|
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="wikitable" |
| ! css | | ! [[.NET Core]] |
| |-
| |
| |
| |
| /* 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 1,585: |
Line 948: |
|
| |
|
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="wikitable" |
| ! SQL | | ! [[Java]] |
| |-
| |
| |
| |
| {| class="mw-collapsible mw-collapsed wikitable"
| |
| ! Sqlite timestamp-to-readable-date query
| |
| |-
| |
| |
| |
| select quote, timestamp, strftime('%Y-%m-%d %H:%M:%S', datetime(timestamp, 'unixepoch')) from StockQuotes as s where s.symbol="TSLA" order by timestamp;
| |
| |}
| |
| |} | | |} |
| <!-- | | <!-- |
Line 1,604: |
Line 959: |
| --> | | --> |
| {| class="wikitable" | | {| class="wikitable" |
| ! [[Android]] | | ! [[Kotlin]] |
| |} | | |} |
| <!-- | | <!-- |
Line 1,614: |
Line 969: |
| --> | | --> |
| {| class="wikitable" | | {| class="wikitable" |
| ! [[Java]] | | ! [[Maven]] |
| |} | | |} |
| <!-- | | <!-- |
Line 1,624: |
Line 979: |
| --> | | --> |
| {| class="wikitable" | | {| class="wikitable" |
| ! [[Python]] | | ! [[Scala]] |
| |} | | |} |
| <!-- | | <!-- |
Line 1,634: |
Line 989: |
| --> | | --> |
| {| class="wikitable" | | {| class="wikitable" |
| ! [[Scala]] | | ! [[Python]] |
| |} | | |} |
| <!-- | | <!-- |
Line 1,669: |
Line 1,024: |
| /etc/init.d/apache restart | | /etc/init.d/apache restart |
| |} | | |} |
| |}
| |
| <!--
| |
|
| |
|
| |
| ===========================================================================================================================================================================================================================================================================================
| |
|
| |
|
| |
| -->
| |
| {| class="wikitable"
| |
| ! [[git]]
| |
| |} | | |} |
| <!-- | | <!-- |