Thursday, September 26, 2024
Sunday, November 13, 2022
Stable Treemaps
Thinking of implementing a stable tree map algorithm as per Sonda, Speckmann, and Verbeek in this article.
What this is saying is when the data or the size of the window changes, the tree map could look very different. Things could move drastically within the map. Something that was on the lower left could now be in the upper right kind of thing. This is called instability. But with the stable tree map, as the data or the window size changes, things stay relatively close to where they were previously. It also looks like their approach will help with aspect ratio problems if you have any.
Saturday, November 12, 2022
Cypress
Cypress is a test automation framework for testing Web Applications. It is implemented in Javascript and part of the framework runs inside the same browser where the application under test is being executed. Cypress executes your test scripts inside that same browser too. That architecture gives Cypress a lot of power for interacting with the pages of the application and puts it into a position to interact with backend API calls as well. It also means all your test scripts are written in Javascript.
Saturday, August 13, 2022
How JSX Gets Compiled to Javascript
With JSX, the compiler turns each tag into a function call, so a <div> tag becomes something like a call to createElement() that creates the div in the DOM. It doesn't directly call document.createElement, instead it's calling React's version of createElement, called: React.createElement().
Here is an example:
Thursday, August 11, 2022
Using Inline Styles with React
<div style={"background-image: url("+imgUrl+")"}> </div>
Turns out that does not work. React requires that style attributes are set using objects.
So the correct way to do this is:
MongoDB
If you are deploying MongoDB on your own servers you need to ensure high availability and data protection. That means you need to run it in a cluster of at least three nodes. You then have to make sure
Sunday, July 31, 2022
2 Years of My Life Truncated, Then Recovered
I had started recording data about my daily activities (workouts, etc) a few years ago. At first, I didn't think of it as anything serious but as time passed by, I had accumulated over two years of data/notes in this simple text file.
Disaster struck a week ago on an early Sunday morning.
I had just woken up and I was saving my notes file, but I was low on disk space so the write was not completing and the computer seemed to be hung. Wanting to get rid of the dreaded spinning beachball, I powered off and rebooted. After the reboot, I found that the file was truncated to zero bytes. In disbelief, I scrolled up and down. Nothing. All content was lost.
By then, I was fully awake.
Saturday, July 09, 2022
Diagonal Menu
A sailboat cannot sail directly into the eye of the wind, but can sail to within
45 degrees of the wind or closer when close-hauled. If you head into the
wind, your sails will start luffing and you will lose power and the
ability to steer. Describing a sailboat's course in relation
to the wind direction, the points of sale on the right
show a starboard tack and assume that the
wind is blowing from the top of your
screen. Boat drawings and info from
me and Chapman Piloting
and Seamanship,
65th edition
by E. Maloney.
Run
When the wind is almost directly behind you, the boat is said to be "running". If the wind is light, it'll feel like you are not moving but just look behind the boat and you'll see a rippling line of water.Close-Hauled
When there's the smallest angle between wind direction and heading, the boat is said to be "close-hauled" meaning that it's sails are pulled in close to the boat.Close Reach
When the angle between heading and wind direction is increased, the boat begins to "close reach". A close reach is somewhat toward the wind, and broad reach is a little bit away from the wind. Fast point of sale for most boats. The sails are eased about halfway out.Beam Reach
The boat is "beam reaching" when the wind is on the beam at a right angle to the boat.Broad Reach
Further increases to the angle between heading and wind direction (more than 90 degrees) bring the boat to a "broad reach"
Monday, July 04, 2022
Symbolic Links
Symbolic links are a useful feature of many disk file systems. They let you make a directory of content or an individual file appear in multiple locations while only storing it once.
In my case I had a directory with many images and I needed those same images in another directory. Rather than copying all the images, I created a symbolic link.
Saturday, June 25, 2022
JS Map, Join Methods & The Spread Operator
The Javascript Array
map
method takes each element of an array and
maps it to a new value. The mapping is done by the callback function
that is passed to map
. These values are returned in a new array.
The original array is unchanged.
Sunday, June 19, 2022
Relocating a Site to a New Server
I have a Linode server that I've been wanting to shut down for a long time. In preparation of that, yesterday, I copied the database and any files that are not part of a repository to an external drive. Here are some of the steps that I took when transferring the site to a Digital Ocean server:
- Change DNS settings for xyz.com on GoDaddy so they point it
to Digital Ocean.
It turns out my domain was registered with Namecheap so I changed two(2) records there. I copied the IP address of my e20 server at Digital Ocean and changed the value in host records for xyz.com at Namecheap. - Make DNS entries for "xyz" on Digital Ocean. (use the e20 server)
I did not have to do this because I just updated the DNS records that were already at Namecheap. -
Make this entry in .ssh/config file for "xyz":
- Hostname xyz.com
- User root
- IdentityFile ~/ssh/id_rsa_e20
- ssh into xyz.com server.
Possible Hiccups: If you get a "Remote host identification has changed" warning, it means that your ssh client is trying to tell you that the IP address is now different for this host which could be a security issue but in this case, I intentionally changed the IP address so it's not a problem. To get past this error, what I did was I deleted the "known_hosts" file from the .ssh directory. Best practice is to just remove the single offending entry with this command: ssh-keygen -R hostname - I keep project_1 under my htdocs directory so cd'ed into that directory and did a "git status" and a "git pull" to make sure that my repo is up to date. From within the same directory, I did a "cat .git/config" to find out the url of the repository. I'm going to clone the repository to the server using this url.
- From a terminal window, ssh into your server: ssh xyz
- Ubuntu already comes with this directory:
cd /var/www/html - Clone the Github repository (project_1) to /var/www/html.
git clone git@github.com:your_github_acct_name/project_1.git - Another hiccup: Got this error => Permission denied (publickey).
- Going over to github to look at my SSH keys since github is not recognizing the SSH keys of my server.
- Looks like I'm missing an SSH key for my e20 server so will copy the SSH key from the server and paste it into a new SSH key that I will create on github.
- Run from your server and copy the output of the following command:
cat $HOME/.ssh/id_rsa.pub - Add a new SSH key to github and paste the contents of id_rsa public key.
- Ran the clone command again at my server and now have a project_1 repo.
- Update the project configs/ to match directory location. On my local machine, I added these two lines to
/Applications/MAMP/htdocs/project_1/CI3/ci/application/config/config.php file:
-
$config['base_url'] = 'https://xyz.com';
-
$config['site_path'] = "/var/wwww/html/project_1/CI3/public/";
-
$config['base_url'] = 'https://xyz.com';
- Create an Apache config for the site in /etc/apache2/sites-available
-
cd'ed into /etc/apache2/sites-available to look for a conf file. There wasn't one so copied another configuration file like this:
cp minikit.eloquentcss.com.conf xyz.com.conf. -
Some of the edits in xyz.com.conf include:
ServerName xyz.com
ServerAlias www.xyz.com
DocumentRoot /var/www/html/project_1/CI3/public
ErrorLog /var/www/html/project_1/storage/logs/error.log
-
I have /var/www/html/project_1 directory but missing storage and logs under it.
In /var/www/html/project_1, created storage folder.
In /var/www/html/project_1/storage, created logs folder.
- Check ownership of the directory that I'm going to store the logs in.
/var/www/html/project_1/storage $ ls -l
drwxr-xr-x 3 root root 4096 Jun 15 06:45 storage
- Ownership for "storage" is root so change that to Apache with this command:
chown www-data storage - Recheck ownership:
drwxr-xr-x 3 www-data root 4096 Jun 15 06:45 storage
-
cd'ed into /etc/apache2/sites-available to look for a conf file. There wasn't one so copied another configuration file like this:
- Enabling the xyz configuration in Apache. Can run it from anywhere on the server, the command knows where to find
the config files:
/var/www/html $ a2ensite xyz.com
/var/www/html $ service apache2 reload
- Setting up the SSL certificate: New approach using Electronic Frontier Foundation's certbot tool much easier than the old process. It's also free.
-
I may already have installed certbot so check on that:
/var/www/html $ which certbot
-
I have it so I ran following command and answered a few questions:
certbot --apache
-
I want to check if the certbot renewal is active:
/var/www/html $ systemctl status certbot.timer
-
Checking certbot auto renewal to make sure that it will succeed when it tries to auto-renew:
/var/www/html $ certbot renew --dry-run
-
I may already have installed certbot so check on that:
-
Create additional directories the site uses (e.g. uploads). Some of these I already had. I changed ownership for all of them. Check with a "ls -l" to see that Apache has ownership of the directories.
/var/www/html/project_1/CI3/public $ chown www-data captcha
/var/www/html/project_1/CI3/public $ mkdir img
/var/www/html/project_1/CI3/public $ mkdir imgs2
/var/www/html/project_1/CI3/public $ mkdir pimg
/var/www/html/project_1/CI3/public $ mkdir scrape
/var/www/html/project_1/CI3/public $ chown www-data img pimg scrape uploads
- Create the database in MySQL: I have the backup of the database on my disk so I copied that over to the new server. This is just the data and the schema which I will load into the MySQL database.
- Get password for the database:
- Digital Ocean saves the passwords for MySQL to:
/root/.digitalocean_password - ~ $ cat /root/.digitalocean_password
root_mysql_pass="c5dce......." - Get your sql file and name of the database:
- ~ $ ls *.gz
- ~ $ gunzip m2017-1000.sql.gz
- The name of my database is in this file: CI3/ci/application/config/database.php
- Go into MySQL from the terminal
-
username is root, -p to prompt for password
Enter the DO password I have cat'ed above.
~ $ mysql -u root -p - mysql> create database m2017;
- mysql> show databases;
- mysql> use m2017;
Database changed - Load data into database
- mysql>source m2017-1000.sql;
- Creating a user and giving it privileges
- username and password come from CI3/ci/application/config/database.php for the following two commands
- CREATE USER 'username'@'localhost'IDENTIFIED WITH mysql_native_password BY 'password'
- GRANT ALL PRIVILEGES ON *.* TO 'username'@'localhost' WITH GRANT OPTION;
- I forgot a big one!.. Install and configure Solr. It's a lot of pain to install and configure Solr especially if there are version mismatches between your operating system and the version of Solr that you are using. To make this easier, I use Docker which insulates us from version mismatch problems.
- I'm going to add a subdomain for Solr so go to Namecheap, Advanced DNS, Add New Record, "A" Record (Host: solr, value: same IP address www)
- nslookup solr.xyz.com
- Run Solr in a Docker Container:
- docker login docker_username (and enter password)
- docker run -d --name solr --restart always --net="host" docker_username/solr-image:v2
- Log in to Solr docker container and configure:
- docker exec -it solr /bin/bash
- export COLLECTION=masc
- solr create_core -c $COLLECTION -d server/solr/configsets/xyz/conf
- cd /opt/solr/server/solr/xyz/conf
- cat db-data-config.xml | sed 's/mysql-mariadb/localhost/' > new_db_config
- cp new_db_config db-data-config.xml
- Setup secure Apache Virtual Host to Proxy access to Solr:
- Create a password for solr: htpasswd /etc/apache2/.htpasswd solr
- vim /etc/apache2/sites-available/solr.xyz.com.conf
- Contents:
<VirtualHost *:80> ProxyPreserveHost On ProxyPass / http://localhost:8983/ ProxyPassReverse / http://localhost:8983/ Timeout 5400 ProxyTimeout 5400 ServerName solr.xyz.com <Proxy *> Order deny,allow Allow from all Authtype Basic Authname "Password Required" AuthUserFile /etc/apache2/.htpasswd Require valid-user </Proxy> </virtualhost>
- Enable the site: a2ensite solr.xyz.com
- Reload Apache: service apache2 reload
- Bring up Solr UI: http://solr.xyz.com
- Install PHP Extension for Solr:
- apt-get install php-dev libxml2-dev libcurl4-gnutls-dev libcurl
- cd /usr/local/include
- ln -s /usr/include/x86_64-linux-gnu/curl curl
- apt-get install php-pear
- pear install pecl/solr
- vim /etc/php/7.0/apache2/php.ini (and add line: extension=solr.so)
- service apache2 reload
- Bring up site.
Image: Y. Apollon, CC-BY-SA 3.0
Tuesday, June 14, 2022
Updating NodeJS
Listing NodeJS versions:
nvm list
I chose the latest version for my upgrade:
nvm install v16.15.1
To start using this version of Node:
nvm use v16.15.1
To create a React application template:
npx create-react-app myapp
Friday, June 10, 2022
Friday, April 01, 2022
Empty Array, truthy or falsey?
return (matching_r) ? matching_r : -1;
to this:
return (matching_r.length) ? matching_r : -1;
to cover the cases when there's an empty array because I was never hitting minus one with the first statement.
Empty strings are falsey. Zero, of course, is falsey so I thought an empty array would be falsey. But as it turns out, that's not the case. Note about the syntax: Paranthesis around the condition is not required.
Saturday, March 26, 2022
Routing in Express
“Routing refers to determining how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on).
Each Express router can have one or more handler functions, which are executed when the route is matched”
© John Matychuk, CC-BY-SA 3.0
Route definition takes the following structure:
app.METHOD(PATH, HANDLER)
Where:
app is an instance of Express.
METHOD is an HTTP request method, in lowercase.
PATH is a path on the server.
HANDLER is the function executed when route is matched.
There are two different routing mechanisms in Express: the App Router, and Express Routers. The App Router lets you define routes at the global app level. This is useful for very simple applications with just a few routes. The Express Router on the other hand, provides a modular solution that allows you to define multiple routers, where each router handles a group of routes.
For example, you might have one router for user account related operations, another router for handling photos, etc.. And then you can mount each router at a specific path using app.use('/some/path', someRouter);
CSS Style for the Post: www.cssrule.com
Thursday, March 24, 2022
/routes
Express Router allows you to group routes into logical bundles and then mount them at appropriate paths using app.use() in app.js. So it's a better way to organize routes that will improve program structure and modularity.
This routing pattern - having Express Routers defined under /routes - and then mounting the routes in app.js - is what you get by default when you run Express Generator.
Wednesday, March 16, 2022
NodeJS
- FILE-BASED: Node modules that we write
- CORE: modules that are built into Node, such as access to the filesystem (fs), or to operating system services (os)
- EXTERNAL: modules that can be installed via npm. They reside in the npm repository. When you install them, they go under the node_modules sub-directory.
Node is for running Javascript outside the browser. Node uses the V-Eight(8) Javascript interpreter that is part of the Chrome browser. In the browser environment, we pull in multiple JS files using the script tag. But outside the browser, we don't have a script tag. We don't want to put our whole application in one JS file, so we need a way to support multiple files. This is why we have node modules.
Each separate JS file becomes a file-based node module. In each module, the module.exports object determines which symbols are exported from the module, to the code that makes use of the module. The code that makes use of the module, pulls in the module by using require().
Node is for running Javascript outside the browser.
CSSRule.com
We can use Javascript to implement backend web applications, desktop applications, and command line tools. For web backends,can process multiple HTTP requests using a single process rather than a process per request as Apache does, thus using fewer system resources per request. Messages from the browser to the server are called HTTP requests, from the server to the browser are called HTTP responses.
A request can be a GET, POST, PUT, or DELETE. REST APIs are built upon this. The request will be GET/POST/PUT/DELETE and will include a url that refers to some resource on the server.
Large library of node modules available to install via npm. Since a single process handles multiple requests, we can do things like have a shared data structure in memory that can be accessed across multiple HTTP requests. In PHP you'd need something like a database, or shared memory service (memcache, redis) to accomplish this.
CSS Style for the Post: www.cssrule.com
Image: Michael Niessl, CC-BY-SA 3.0
Tuesday, March 15, 2022
mime-type
Restarting Node on DO
However, if all you are trying to do is stop your current Node process so that you can start a different one on the same port, then you don’t need to reboot your droplet at all. You can find the process id of the Node process and kill it from the command line. For example, if you started your process with
Parsing the POST Message
Monday, March 14, 2022
Resolving localhost to an IP Address
When you type "localhost" into the browser, it calls the operating system to resolve that name to an IP address and the O/S will go on and take a peek at /etc/hosts before it starts talking to DNS servers ...
For localhost, it'll always find it in etc/hosts as this a standard entry. In general, if it doesn't find an entry in etc/hosts, it'll do a DNS query to a DNS server.
When you run Node though, ifconfig will give you a list of network interfaces, lo0 (local) lists 127..... and another on en0, by default Node will listen in on all of these IP addresses.
When you type in "localhost:8000" into the address bar, the browser will turn that into a number (IP Address) (domain name part not the route stuff meaning the part before the slash part)
Once the browser has the IP Address, 127.0.0.1:8000 will establish a TCP connection to that IP address and that port number. The destination port will be 8000. Opening up a TCP connection to that IP Address and Port. Once it sets up the TCP connection, it will send an HTTP request over that TCP connection. HTTP GET with whatever you put after the slash so Node will be receving that.
Image: NASA, Public Domain
TCP Connections & Port Numbers
Port numbers are 16 bit integers, 0 through 65535 (2 to the 16 minus 1, like a byte is 255, can't represent 256) You can represent 256 unique values: 1 through 255 and 0.
Monday, February 14, 2022
var vs. let
If you declare a variable using let within a block, then it's locally scoped to that block (see note). For example, everytime you go through a loop, Javascript creates a new stack frame if you have locally scoped variables declared in that block. If you have an asynchronous event going on within that block, then the async code that runs later can safely refer to that variable without worrying that it's changed by another iteration of the loop.
Tuesday, January 04, 2022
Thursday, September 30, 2021
LTI: Learning Tools Interoperability
By using LTI, a tool provider, such as Yellowdig, or Cisco WebEx can implement their tool to a single standard interface, that works with Canvas, Moodle, Blackboard, and other LMS platforms. This enables the creation of app marketplaces, where vendors can sell their apps to anyone using an LMS that supports LTI.
Friday, August 06, 2021
Closure Rules
Three rules for a closure to be created:
- A function is defined within an outer function.
- The outer function has variables and/or parameters (these will be on its stack frame).
- A reference to the inner function is kept somewhere in the system.
It could be that the outer function returns a reference to the inner function that’s stored, or
It could be that the outer function passed a reference to the inner function to some other function which holds on to the reference (e.g. setTimer, addEventListener, etc…).
If no reference to the inner function is maintained, then a closure will not be formed and the stack frame of the outer function will be deallocated by the garbage collector.
Closures are useful because when the inner function does get executed, it’ll have access to the variables and parameters from the outer function’s stack frame.
function main(param) {
// Parameters and local variables are on the stack frame of
// function main
// closures are for keeping a parameter or a variable alive after
// the function has returned.
function interior() {
console.log("interior function: ", param);
}
// this will return a reference to the function
return interior;
}
// Creating two (2) closures
let f = main("hello");
f();
let g = main("hi");
g();
Image Credit: Andrea Rapuzzi, CC-BY-SA 3.0
Tuesday, August 03, 2021
Syntax Highlighting
<link href='//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.1.0/styles/stackoverflow-light.min.css' rel='stylesheet'/>
<script src='//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.1.0/highlight.min.js'/>
<script>hljs.highlightAll();</script>
In each post, you use a pre and a code tag like this:
<pre>
<code class="language-js">
let myPromise = new Promise( (resolve, reject) => {
setTimeout(()=>resolve('my results'),1000)
});
myPromise.then(result => console.log(result));
</code>
</pre>
Sunday, August 01, 2021
Javascript Promises
Javascript Promises are useful when you have some asychronous operation (e.g. talking to a backend server, waiting for some time interval to expire, etc...), and you want to structure your code a little nicer than a bunch of nested callback functions.
Note that nested callback functions can usually achieve the functionality you need, but you can end up with deeply nested functions and what is often referred to as "callback hell". Promises let you structure the code without all the nested callbacks.
You create a Promise by invoking the Promise constructor: new Promise(). You pass one parameter to the Promise constructor: A callback function where you will implement your asynchronous operation.
The most important detail about the callback function is that it will be called with two parameters: resolve and reject. These parameters are references to functions provided by the Promise. You will call resolve() when your async operation is complete, or reject() if your operation fails. Note that when you call resolve(), you pass it the results of your operation (e.g. the results returned from the server).
That's all there is to setting up your async operation. Now you need to process the results. For this you use the "then" method of the Promise.
let myPromise = new Promise( (resolve, reject) => {
setTimeout(()=>resolve('my results'),1000)
});
myPromise.then(result => console.log(result));
In the above code, myPromise is created with an async operation that will take 1 second to complete. myPromise.then() is called to register a callback function to run when the promise has resolved. Note that then() is called right away, while the async operation is ongoing. After one second, the promise resolves and the callback registered with then() will run and console.log the result.
There are a few more details to understand about Promises, but the example I've given shows the main underlying idea. Your async operation runs and let's the promise know when it's done, or when it's failed, and the Promise object takes care of informing any code that has registered interest in the result by calling then().
In a later post I'll talk about what happens when you call then() multiple times, and also how to handle an array of multiple promises to deal with a set of parallel async operations.
Image Credit: Alex Blajan, CC-BY-SA 2.0
Javascript Assignment by Reference
If you have an array variable, say 'a', and you peform an assignment b=a; Javascript does not make a copy of the array. There is just one array in memory. Both 'a' and 'b' are references to the same array. You can change b[0] and that will also change a[0].
If you really want to copy an array, you can execute b=a.splice(0);
However, note that if the elements of the array contain references to other arrays or objects, then those will still be shared between the old array and the new one. Making a complete clone of a complex data structure can be tricky.
One approach is to turn the whole thing into a JSON string using JSON.stringify, and convert it back into a data structure using JSON.parse. This mostly works, but any objects that have methods will lose those methods in the conversion since methods are not encoded in JSON by the JSON.stringify.
The same assignment by reference rules also apply to objects, not just arrays.
Image Credit: Ajay Kumar, CC-BY-SA 2.0
Friday, July 30, 2021
Call, Apply and Bind in Javascript
In Javascript call(), apply(), and bind() are all methods of Function objects. A Function object is automatically created for you when you define a function in your code. If your function is named "calculateTax" then you can call the method calculateTax.bind(), or calculateTax.apply(), or calculateTax.call().
So what good are these methods?
They allow you to control how 'this' is set when the function is invoked.
I'll focus on bind() since that's the one I use most commonly.
When you call yourFunction.bind(someObject), it will return a new version of the function where the 'this' parameter will be bound to whatever object you specify as the parameter (someObject in this case). Here's an example:
// Controller Class:
class ShoppingCartController {
constructor() {
this.total = 0;
this.taxRate = 0.08;
// Create a new version of calculateTax where 'this'
// will be bound to the ShoppingCart object (this).
this.calcTax = this.calculateTax.bind(this);
}
setTotal(total) {
this.total = total;
}
calculateTax(req, res) {
this.tax = this.total * this.taxRate;
res.json({tax: this.tax});
}
}
export new ShoppingCartController();
// In Express Router File:
let shoppingCart = require('../controllers/ShoppingCart')
// Note: using shoppingCart.calculateTax would not work.
router.get('calctax', shoppingCart.calcTax);
This is a Node/Express application where there is a ShoppingCart controller. We want to make it so that a particular route calculates and returns the tax. In the route.get() call, if we use shoppingCart.calculateTax, it will not work because 'this' will not be set correctly when the method executes. However, if we use the calcTax() method, 'this' will be set to point to the ShoppingCartController object and the method will be able to compute the tax.
Bind is essiential when you have a method of an object that you want to use as a callback function. The code that invokes the callback (e.g. the Express Router in this case) doesn't know how 'this' should be set. It just calls the callback function it's given. In this situation - since we've called bind() ahead of time - the code that executes the callback can simply call the function without worrying about how 'this' will be set. We've already bound 'this' to the appropriate object.
Image Credit: Wikimedia, CC-BY-SA 2.0
Saturday, June 20, 2020
Atomic Habits
"With our bad habits, the immediate outcome usually feels good, but the ultimate outcome feels bad. With good habits, it is the reverse: the immediate outcome is unenjoyable, but the longterm outcome will be splendid."
Here's the rest of what James Clear, the author of Atomic Habits says:
© Drew Beamer, CC-BY-SA 2.0
We all want better lives for our future selves. However, when the moment of decision arrives, instant gratification usually wins. You are no longer making a choice for Future You, who dreams of being fitter or wealthier or happier.
You are choosing for Present You, who wants to be full, pampered, and entertained. As a general rule, the more immediate pleasure you get from an action, the more strongly you should question whether it aligns with your long term goals.
Friday, June 19, 2020
Markdown Syntax
_**app_mvcs:**_
## is a heading underlined with a thin line. It looks good. To italicize, bookend the string with the underscore character on both sides. To bold, double asterisks on both sides.
Tuesday, June 16, 2020
Updating SSL Certificate
Setting up SSL Certificates used to be a painful process. No more. LetsEncrypt provides FREE SSL certs and an easy way to install and renew them. It's provided by the Internet Security Research Group, a non-profit. They do this for the public benefit, and because it used to be so expensive and so much trouble to setup HTTP over SSL.
Saturday, May 23, 2020
Deploying Angular Express Application
Question For an application with an Angular front-end and Node/Express back-end, should the Express application serve the Angular files, or should the Angular files be served from a different server? Would I need two domains to serve Angular files from a different server?
My Answer Your compiled Angular application is just a set of static files that needs to be downloaded to the browser. So they don't have to be served from an Express/Node application. You could host them on an Amazon S3 bucket for example.
Or, you could use some other server technology like nginx that's efficient at serving static files. You don't need a whole separate domain, just a separate sub-domain (so your API might be at https://api.mydomain.com ("api" subdomain), while your Angular code might be served from https://mydomain.com).
Follow-up Question Thanks for the explanation! What about authentication? Is that done on Angular or Express? What is the best practice for this? If I were to pass back a set of static Angular files, wouldn't I also be passing back to a user who hasn't logged in, the files he is not supposed to see yet? Sorry I am new to this, just trying to figure out how the authentication will work. In Express, I understand how it works, but with Angular and Express together, I feel lost.
My Answer In most cases what you want to protect with authentication are the REST APIs - i.e. the resources/data that are stored in the back-end. So you'd allow anyone to download the Angular app, and it would use "route guards" to locally protect parts of the app that require authentication. It would also provide a sign-in user interface to allow you to authenticate with the back-end. Once you successfully authenticate then the Angular app can start calling back-end APIs providing an authentication token in each call so that each REST API call is individually authenticated.
If you really needed to prevent un-authenticated users from downloading parts of the Angular app then you could use other measures like putting the app behind a VPN, using HTTP authentication to access the static files, or using Angular lazy loaded modules that only get loaded for authenticated users.
(See the Angular CanLoad route guard: https://angular.io/api/router/CanLoad )
Massimiliano Morosinotto, CC-BY-SA 2.0
Monday, May 11, 2020
Return Statement
Wednesday, May 06, 2020
Quick HTML
Thursday, January 03, 2019
Learning Flexbox
justify-content is a CSS property that aligns items along the main axis. The default main axis is row but you can set it to column with flex-direction: column. So if your main axis is row, then justify-content will align items horizontally. But if you reset it to column, then the alignment will be done vertically. This is an important distinction and one that is not clear in Flexbox Froggy because on their Level 2 page they state that the property aligns items horizontally.
Possible values for this property are flex-start, flex-end, center, space-between, space-around and space-evenly.
When the main axis is the row, flex-start aligns items to the left side of the flex container, with flex-end items align to the right side of the flex container. If main axis is column, then flex-start will align flex items to the top of the flex container and flex-end will align them to the bottom of the container.
With space-between, there is no space to the left of the first item or to the right of the last item. The space between all the items is equal. So items display with equal spacing between them as Flexbox Froggy states.
space-around puts equal spacing between the items but adds space to the left and to the right of the first and last items that is equal to half the space in between items. Flexbox Froggy says that space-around is equal spacing around items.
Then, space-evenly similar to space-around except that the left and the right spacing is equal to the space that is between the items instead of being half.
align-items is a CSS property that aligns items on the cross axis. So there's the main axis that you can set to row or column and your cross axis is the perpendicular to your main axis. If you main is row, then align-items will do the alignment vertically since the cross axis is the perpendicular y-axis.
The values for this property are flex-start, flex-end, center, baseline and stretch. Assuming the default value of row for the main axis, flex-start will align items to the top of their container, flex-end will align items to the bottom of the container, and center will align items to the vertical center of their flex container. Just keep in mind that if the main axis was the column, then flex-start will align items to the left of their container, flex-end will align them to the right.
flex-direction property can be set to row which causes the flex items to be displayed horizontally as a row. If set to column, then flex items are displayed vertically as a column. row-reverse and column-reverse are the same things but in reverse order. The default value for flex-direction is row.
flex-wrap property accepts nowrap, wrap, wrap-reverse. In nowrap, every item fits into a single line, in wrap, items wrap around to additional lines, wrap-reverse does the same in reverse. The default value is nowrap.
flex-basis property sets the size of the flex item along the main axis. If the main axis is row, then it controls the width, if main is column, then it controls the height. It can be set to px, percentages, or any other available units. flex-basis is a property for the flex items.
I wrote a Javascript program to produce the CSS rules for a Flexbox grid system, given a number of columns.
flex-flow property is a shorthand for flex-direction and flex-wrap. To set the main axis to row and set the flex-wrap to wrap, you can write, flex-flow: row wrap.
This file shows the difference flexbox can make for centering both horizontally and vertically (sometimes called the "holy grail" of CSS styling). You can achieve this by setting justify-content and align-items to center. Given flex-direction of row which is the default, first property aligns items horizontally, second property vertically.
For CSS Grid, there is Grid Garden.
Thursday, December 27, 2018
Wednesday, December 26, 2018
Browser Market Shares in 2018
- 14%
- 6.6%
- 64%
- 7.3%
- Safari
- Firefox
- Chrome
- IE & Edge
- 100
- 75
- 50
- 25
- 0
Browser Market Share
Sunday, January 07, 2018
Adding a New Property to an Object
var myObject = {
key1: "val1",
key2: "val2",
key3: "val3"
};
DOT NOTATION:
myObject.key4 = "val4";Object { key1: "val1", key2: "val2", key3: "val3", key4: "val4" }
SQUARE BRACKET NOTATION:
With square brackets, it'll want the key name as a string.myObject["key5"] = "val5";
Object { key1: "val1", key2: "val2", key3: "val3", key4: "val4", key5: "val5" }
Image Credit: Spot the Skylab by NASA at nasa.gov
Thursday, December 21, 2017
Evolution of CSS Layouts
CSS provides a number of properties that affect the layout of elements on the page, including those associated with floats, positioning, inline-block, columns, flexbox and grid. Some of these CSS features are not generally useful for laying out entire pages. Positioning, while it looks promising at first, is problematic when elements have a variable heights based on content from a database for example, making it impossible to know ahead of time where to place each element.
Inline-block is good at flowing blocks next to each other and wrapping to the next line when necessary, but it can’t easily create layouts that span columns/rows. CSS columns are good for one purpose: laying out text in multiple columns, while flowing text from one column to the next, but it is not for page layout. That leaves: floats, flexbox, and grid, which are are the main focus here.
Floats have been the tool of choice for page layout for many years. They have the advantages of universal browser support, and the ability to flow other page elements around them, or below them with clears. Many page layouts can be achieved with floats, but they do not provide for vertical centering, and can’t produce the “holy grail” layout where elements are centered both horizontally and vertically. They are also complex to use, and were not intended for page layout.
Flexbox is a major advance for page layout. It’s not as universally supported in browsers as floats, but support is good and getting better. Flex items in a flex container will adjust their sizes based on the width of the container and available space. The “holy grail” layout is achievable with both horizontal and vertical centering. One disadvantage of flexbox is that it is only one dimensional. It can layout a row for each flex container, and column spanning is possible by using multiple flex containers, but two dimensional layouts with both row and column spanning are harder to achieve and generally require multiple levels of nested flex containers.
Grid is designed to solve the problem of global page layout. Unlike flexbox, it works in two dimensions, allowing you to control both the row and column positioning and spanning of elements. Like flexbox it intelligently resizes boxes based on the size of the container and available space. Browser support is not yet as good as flexbox, but it will be widely supported in the next year or two.
Grid is best for laying out large areas of the page, but for UI elements, or things like image galleries, flexbox is still the tool of choice as it can handle a variable number of elements (e.g. a variable number of images for an image gallery), and is still the best way to perform vertical centering. Thus, the ultimate “best” choice for page layout is a combination of grid and flexbox, with grid controlling the big picture, and flexbox for individual UI elements. At last, floats can now return to their original intended purpose of flowing paragraph text around images!
Image Credit: Chicago by NASA at nasa.gov
Tuesday, December 12, 2017
CSS Grid
I just learned this technique from Jen Kramer. You can use CSS Grid to create a layout that looks like an existing Mondrian painting.
Start with the painting you want to re-create, and identify all the grid lines, both vertical and horizontal. To determine the vertical grid lines, start with number 1 at the far left, then scan across the painting. Anywhere you see the right edge of a box, create the next vertical grid line. Number them in sequence from left to right.
Do the same for the horizontal grid lines. Grid line 1 is at the top of the painting. Then anywhere you see the bottom edge of a box, create the next horizontal grid line.
Now that you have the grid lines defined, you can easily determine the grid-row and grid-column values for each box. For example in the drawing above, box "e" has grid-row: 3/6; and grid-column: 2/3.
Next you need to determine how wide each column is and how tall each row is. Put these dimensions into the properties "grid-template-columns" and "grid-template-rows" of the grid container. When measuring these dimensions be sure to not include the black gaps between the boxes. For example, for row 2/3 in the diagram, measure from the top of box "g" to the bottom of box "b".
You'll also need measurements for the horizontal and vertical gaps between the boxes. Put these measurements into the "grid-gap" property of the grid container.
Next set the background colors of your boxes. The container should have a black background, and various boxes within the container should have their own background colors to match the original painting.
Image Credit: Kristine, Mondrian Dress, 1965, CC BY NC 2.0
Friday, September 23, 2016
To The Point
Saturday, August 13, 2016
Regular Expressions
/ [^ ] * / g Door County is beautiful year-round
Match a sequence of zero or more characters that are not a space. The /g in the first one
above makes the match global.
/ [^ ] * / Door County is beautiful year-round
Without /g only the first occurrence in the string is matched.
/ .*[ ] / U Door County is beautiful year-round
Match a sequence of zero or more characters that ends with a space. The dot (.) will match any character, including spaces. The * says zero or more. Then there is a space, so the string we are matching must end with a space character. The /U option makes it "ungreedy", so that it matches the first, smallest substring it encounters, rather than the longest substring.
/ ^https?:\ / \ / / http://www.https.com
Match "http://" or "https://" at the beginning of a sequence. s? says match a single s if there's one otherwise skip. The two forward slashes which are special characters have to be escaped with two backward slashes.
Some regex rules:
- Dot (.) matches any character, except newlines. If you provide a /s modifier then it will match newlines too. Example: /^The.*/s would match any sequence of text where the first line starts with the word "The", until it reaches the end of the text being searched.
- If you need to explicitly match a dot (aka period), then you need to escape it. Let's change the example above as follows: /^The.*\./s Now it will only match until it encounters a period, which could be on a different line of the text.
- The ^ character in the above examples means match from the beginning of the text being searched.
- You can also match at the end of the text being searched with $. So /\.$/ would match any string that ends with a period.
- Instead of matching zero or more, you can also match one or more using +
- You can also match zero or one, using ?
- Curly braces let you define a length range you want to match, so you write {minlength,maxlength}. Example: Suppose you want to match a series of the character "a" that has a length between 3 and 6. You can do it like this: a{3,6}
- Square brackets defines a set of characters to match. So [ab] will match either a or b. This could also be written as [a-b]. If you wanted to match any lower case alphabet character, you'd write [a-z].
- You can also use an "or", so that you match one string or another. Suppose you want to match "abc" or "xyz". You write it like this: /(abc)|(xyz)/ Actually the parenthesis are not needed, but are good for making it clear.
- Note that the starting and end slashes / are the delimiters of the regular expression (the start and end). You can place modifiers, like the g after the ending slash to change the way the regular expression is interpreted.
Saturday, February 06, 2016
Secure Shell
Then let's run the keygen command from the terminal: ssh-keygen -t rsa -C "myblog@gmail.com"
which will generate a new set of keys. One of the parameters "rsa" is a type of encryption scheme. ls -l will show the new and the old backup keys.
To add the new key to the ssh-agent: ssh-add id_rsa
Do a "cat id_rsa.pub" and copy the contents of your public key. Then go to your github account, and under Profile, find "Settings" and choose "SSH keys" from the left pane. Add "New Key" then test your new key by doing a pull to make sure everything still works with github. You'll also be copying the new public key over to your server.
To connect to github.com over SSH and test your new key:
$ssh -T git@github.com
If you receive a message telling you that you have successfully authenticated, then all is well.
Chrome Debugging from JSFiddle
httpd.exe
git
If you don't have git, to install it: http://git-scm.com/downloads
To find out which version of Git that you have: $git --version
"which" tells you where the command is located on the disk so it gives you the path to it. It will only work on executables. To find out where Git is installed: $which git
There's one file called .gitconfig in the home directory with global git settings. To setup username and email key to associate with your commits:
$git config --global user.name "Josephine March"
To make your Git color coded: $git config --global color.ui true
If you change your permissions, git will ignore it if you run this command:
$git config --global core.filemode
Telling git to use nano as your CL text editor. This is very helpful with merges.
$git config --global core.editor nano
To see all the configurations:
$git config --list
To add a single untracked file into the repository:
$git add {filename}
To add all untracked files into the repository:
$git add .
$git add --all
To show what changes have been made:
$git diff
To show what changes have been made in a single file:
$git diff {filename}
Adding a file is staging. If you want to undo a stage:
$git reset HEAD {filename}
If you make changes in a file that's in a git repository and you have not yet staged them, you can reverse the changes with this command:
$git checkout {filename}
Github.com, place to store git repositories
Wednesday, February 03, 2016
d r w x r - x r - x Miné Jan 31 22:00
Friday, December 18, 2015
Helvetica Neue
Do you know what Crate & Barrel, Lufthansa, Energizer, SAAB, North Face, American Airlines, Urban Outfitters, NASA, Fendi, Staples and IRS Tax Forms have in common?
Helvetica.
Originally named Haas Neue Grotesk, the company wanted to rename it Helvetia after Switzerland, the country. Some people opposed that suggesting Helvetica instead. That's the short story of the very popular and widely used Swiss type.
Image Credit: Wikipedia
Friday, December 11, 2015
BNF Notation For Syntax
Monday, July 20, 2015
How To Disable Text Area Resize
visually.
Tuesday, July 07, 2015
Sunday, June 28, 2015
Testing Mobile with Google Chrome
Tuesday, May 26, 2015
How to Hang a Picture
Never one good with a level, or finding the two by fours in American walls, I consider myself successful if a picture is not noticeably crooked. But if you wanted to hang things perfectly, the experts have figured out the science behind hanging pictures:
© cssrule.com
The rule of thumb is to hang your picture at anywhere between 56” and 60” on center. For 57 inches, "on center” means that the middle of the picture is always 57” from the floor.
Measuring from the floor, mark 57” on the wall. Measure the height of your picture and divide by two. This is your center. Measure the top of your picture to its tightened wire, tw.
Subtract tw from ½ the picture’s height. This number will tell you how far above your initial 57” mark you should place your hook.
Example: A 20” tall photo with a tight wire located 2” below
the top should have a hook placed at 8” above the mark. 10” – 2” = 8”; the hook should be placed 65” off the floor.
* This post was made using a blockquote class from a previous CSS post.
Sunday, March 01, 2015
Half Billion Dollar Art Heist Still a Mystery
Thursday, January 01, 2015
Those Woven Things
I'm not crazy about tapestries hanging on walls but that's what was on display in the museum. When we arrived at the exhibition hall, we overheard a man say to his companion as they entered the building, "It's those woven things, we've come to see". Maybe the companion did not want to go in either? Anyway, it was actually interesting once you learned the story behind each tapestry.
Sunday, November 16, 2014
Saturday, September 27, 2014
Image Captioning Tool Enhancements
There's a new version of the Image Captioning Tool, my jQuery plug-in. I've added capabilities to truncate a larger image and also play an MP3 audio when the user hovers over an image. Move your mouse over the example image above to see how it works. To try it out on one of your images, see the Captioning Tool. Music by Coldplay.
For the example image shown, the captioning tool generates this code to call the plug-in:
<script type='text/javascript'> $(window).load(function(){ $('#mybasinjpg').cssBakeryCaption({'opacity':'0.2','center':true,'centerCaption':true,'round':true, 'audioUrl':'MP3 URL','hide':true,'color':'white','height':'38','speed':1000,'bgcolor':'black'}); }); </script> <img id='mybasinjpg' style='display:none;' src='IMAGE URL' alt='Early Evening [leaving dock & out on water] © 2014 Copyright www.cssrule.com All Rights Reserved'>
Thursday, September 04, 2014
Basic CSS Drop Cap
The styling of this dropcap which I came across in an online magazine article is very similar to dropcaps we have done before. The basic approach is: Use a span to mark it up, increase the font-size, and float the letter to the left. You can change its color (#DB0404) and choose any font you like. The font for this example is Typekit "ltc-bodoni-175". If you want to place the dropcap letter on a circle or a square, please see this post. Below, same dropcap, larger and positioned differently:
Alorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ornare velit sed libero tristique, ut pellentesque quam porta. Proin iaculis posuere aliquam. Aenean semper vulputate nisl et ornare. In adipiscing pretium ante vestibulum faucibus. Cras molestie, urna vel dignissim sollicitudin, mauris nisl condimentum leo, sit amet hendrerit nisi magna ut lorem. Sed ac porta augue. Sed feugiat odio at auctor venenatis. Donec eu scelerisque neque. Nulla facilisi.
A neat site for different dropcap ideas.
Friday, August 29, 2014
Javascript Apply
Sunday, August 24, 2014
CSS3 Keyframes & Animation Property
In the first fifteen percent of the animation, we sit still. Notice that we have to initialize all the values like height, width, top, left, opacity and angles that are set for change later.
15% { /* Stop all animation for a little while */ height: 154px; width: 154px; left: 0; top: 0; opacity: 1.0; transform: rotate(0deg); }
As the blue div starts turning with the rotate property, its opacity will slowly become translucent, it'll shrink in size due to the new smaller height and width dimensions and it will anchor at a new location, 226px, 226px. Those are coordinates for top and left. You can think of them as x and y.
For plain red and white stripes, instead of the checked pattern, use the following for the "container" div pattern:
background-color: red; background-image: linear-gradient(transparent 50%, rgba(255,255,255,1.0) 50%); background-size: 50px 50px;
If you'd like to keep the rotating blue div with the stars, the movingBox div, within the "container" div at all times during its traveling up and down, add overflow:hidden to the parent element which is the "container" div in this case. As the property name and value implies, any parts of the child element that goes beyond the confines of the containing element, will be hidden or clipped from sight.
The Start/Stop button has a Javascript click handler attached that sets the CSS animationPlayState of the moving element to either 'paused' or 'running'.
You can see the entire CSS file here.
Monday, July 28, 2014
A New Search Engine: DuckDuckGo
Take for example the following link that is supposed to take me to a newspaper article. The Google search results page certainly looks as if I will directly go to the newspaper's site but that's not what really happens behind the scenes. While the yellow portion of the link is where I chose to go - my actual and eventual destination - the unhighlighted portion has been inserted into the link string by Google without my knowledge.
So before I view the newspaper article, I will go through Google where they will collect more information on me although this portion of my journey will be invisible to me.
If you want to see how this works, go to google.com and search on something. You'll get the usual search results page that all of us are familiar with. Right click on one of the links and choose "Copy Link Location". You'll find out that the link is reconstructed such as the one I have above and looks different than what Google's showing you on their search results page.
To understand what this means for the user:
"Google knows too much about you" | EU Data Initiative
The popularity of a relatively new service called DuckDuckGo, which offers searches without user tracking, storing of IP addresses or unique user agent strings, might force big name search engine companies to reconsider how they handle user data.
Tuesday, July 22, 2014
Rotating Text & Making Columns with CSS3
I saw a page layout in the Costco store magazine and wanted to try to reproduce it using CSS3. Something that looked simple enough turned out to be a time-wasting challenge with CSS so before long my design took a different turn. The new column property has its uses but comes with its own quirkiness.
This is an example of rotating text and dividing your text into a number of columns using the new CSS properties, transform:rotate(), column-count and column-gap. The class for the dropcap is included at the end of the style block.
Lopsang "Tea" Souchong is a kind of tea and not a real name.
Mindful Matters, Costco Connection, July 2014
Thursday, July 17, 2014
Friday, July 11, 2014
Flat Design
Thursday, July 10, 2014
Tuesday, July 08, 2014
Setting up SSL on an Apache Server
Saturday, July 05, 2014
CSS Vendor Prefixes
To review the prefixes, we have: -webkit- for Google Chrome and Safari, -moz- for Firefox, -ms- for Internet Explorer and -o- for Opera. If you are unsure whether a CSS property needs a vendor prefix, there's a website which will answer that question for you.
Friday, June 27, 2014
CSS Drop Caps
Sed tempus adipiscing eleifend. Aenean aliquam nibh quis enim varius cursus. Cras ut neque eget eros mattis volutpat. Nulla et pretium massa. Suspendisse potenti. Nam id quam mauris. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sodales, leo dictum tempor auctor, nulla urna commodo lacus, eget vehicula nulla neque mollis velit. Quisque lobortis feugiat pharetra. Vivamus id nibh facilisis, dictum dolor quis, mattis tellus.
We have styled drop caps before. Another short post here. This is an easier and faster way of styling them using CSS3 and Typekit fonts.
The CSS:
.circle_dropcap { color: white; background-color: #338FD1; font-family: "p22-fllw-eaglefeather"; font-weight: bold; font-size: 340%; display: block; float: left; border-radius: 50%; height: 1.4em; width: 1.4em; text-align: center; line-height: 1.5em; /* was 1.4em */ margin-right: 7px; margin-top: 4px; box-shadow: 1px 1px 2px 0 #828282;
The first 5 lines are just setting the colors and font we want to use:
color: white; background-color: #338FD1; font-family: "p22-fllw-eaglefeather"; font-weight: bold; font-size: 340%;
We then turn the span into a block element so that we can size it using width and height, and use margins and padding as we please. When an element is inline width and height are ignored as well as vertical margins and padding. Next we float the new block element left so that the remaining text will flow around it.
Since we want to show a circle, we set border radius to 50%. That means each corner of the block element will make an arc that is one half the width and height of the block element. The result is a circle.
We next set the width and height using em's so that the circle will scale according to the font size used. Make the font larger, and the circle will grow with it.
Now we want to make sure the letter is centered both horizontally and vertically within the circle. We can take care of the horizontal centering with text-align: center. For the vertical centering we just set the line height equal to the height of our circle. (We could also tweak this a bit by setting vertical-align).
To put some space between the circle and the text to the right of it, we set a right margin.
To move the circle down a bit, we set a top margin.
And finally, we want a little drop shadow from the circle, so we set the box-shadow property.
Here's the CSS for the square drop cap:
.square2_dropcap { border-radius:4px; color: white; font-family: "museo"; font-weight: bold; font-size: 340%; display: block; float: left; box-shadow: 2px 2px 2px 0 #828282; height: 1.2em; width: 1.2em; text-align: center; line-height: 1.18em; margin-right: 8px; margin-top: 8px; background-color:#c342da; }