Saturday, July 11, 2020

My Custom Precision Bass

Kit

  • Kit from BYO
    • The tuners and bridge are of better quality than expected (They are better than the one found on a Fender Squire PJ Bass Affinity).
    • Inserting the neck in the body was not a problem but required multiple tries, though one of the pre-drilled holes was not perfectly aligned, the mounting plate is not straight.
    • 3 frets needed correction as they were too high
    • The pickup is also surprisingly good. It does not sound like a Seymour  Duncan '60s Pride. But it is clear. See below for my evaluation of affordable P Bass pickups.
    • So far I was able to set up the action to a low level
    • The bass is very enjoyable to play
    • Intonation was an issue at first. I had to drill new holes 15 cm further and I used a $60 Omega bridge that I already bought.
  • Things I missed
    • I should have given more attention to sanding the body, I am not sure how I missed it, but in the end, there were more scratch and some holes on the body.
    • Applying a stain before painting may have been better for the coloring. In the back  the coloring is uneven, it seems part of the wood absorbed more or less the paint. I did not spend has many coats of paint in the back than in the front and it shows.
    • Building a painting stand for the body like in this Video would have avoided some bumps when applying the Vernis?
    • Bridge positioning. But how can you know in advance the length of the strings from the 12 fret to the bridge will be 17.5 inches, instead of 17 inches to reach acceptable intonation.
      So I had to drill holes twice and re-position the bridges, this is not a big issue except for the fact that there are 2 marks trying to conceal 2 previous holes.
  • Most Challenging
    • I probably mounted and un-mounted the neck 6 times, before I found the perfect position (these things require practice). But I could tell right away that it was a perfect feat and the not so perfect drilled holes created some issues.
    • Mounting the bridge was challenging because it has to be positioned perfectly in a 90-degree angle, and I am not sure what I could have used as a reference point.
      Watch some video on youtube about that.
      I found that one person was applying some painting tape around the bridge areas and then draw some line with a ruler using as reference the right and left side of the neck.
      The distance is not a problem we know it is  17 ". The problem is the Angle.
      Once I drew the lines I centered the 4 main holes from the bridges on the lines.
    • Since I positioned the pickups after the bridge there was a little miss alignment between the strings and the pickups. This can be corrected by moving the saddle, but it may affect intonation. It may be better to mount the pickup before the bridge and use some light write to verify the alignment

Kit




Audio Test

This is with the BYO Kit + Omega Bridge + G.M. Thumpers! 60's Style P-Bass Alnico 5 Pickups 
I used Guitar Rig 5, Bass Amp, Precise Bottom
  • Bass + 2 Guitars + Drums - Audio
  • Bass + Drums - Audio

Painting

The oil paint used took at least 5 full days to dry. So it took 2 weeks to finish the painting.
Using the Vernis spraymax (see above link), is relatively easy

Painting days

First coat on Saturday 1 and second coat Sunday 1.
Took up to Friday to dry.

Third coat on Saturday 2
Took up to Friday to dry.

Vernis on Saturday 3
Take 24 hours to dry



The Vernis looks better in these pictures taken 1 hour after applying than in the end.




Assembling Week End 3

On Sunday 3, I was able to assemble the P Bass.
  • There are issues with fret 12 and 13 on the D string
  • I did not even try to finalize the intonation
  • Action is low
  • Tuning is stable













This is not the Nut from the kit, I bought this one
Graph Tech Black TUSQ XL 42mm Flat Bottom P Bass N PT-1205-00




Assembling Week End 3

Fix the fret 12 and 13 on the D string.

As almost visible on the picture and in real life, the fret 12 and 13 on the D string are higher.



Using a general all-purpose file. and 600 and 1500 grits sandpaper, I was able to remove the bump.

Intonation and bridge placement issue.

Having set up the saddle in the bridge at mid-distance, when I placed the bridge for the first time.
I could not complete the intonation, as I needed more distance to lengthen the strings.

My Omega Bridge, positioned exactly in the same holes gave me more distance to work with.
But this was not enough, I had to moved the bridge15 cm further, which mean more holes


In the final result, I can complete the intonation. But there are 2 holes.
To fix the intonation, the distance between the 12 fret and the bridge/saddle string connection point is almost 17.5 inch, instead of 17 inch. I do not know what this mean and is this wrong or expected.



Evaluating PickUp 

References - YouTube Video

I found these 2 videos on YouTube that demonstrate what a P Bass should sound.
For now I am going to evaluate cheap P Bass pickup between $12 and $30 dollars, all from China (I guess). I have 3 Pickups




More Fret Fixing

After 2 weeks playing with the bass, I tackled fixing 2 other frets that were too high





Reference Videos




Thursday, March 5, 2020

Winmerge for git


Download tool from
https://winmerge.org/downloads/?lang=en


Update file C:\Users\username\.gitconfig
with configuration (from https://gist.github.com/shawndumas/6158524)

[mergetool]
    prompt = false
    keepBackup = false
    keepTemporaries = false

[merge]
    tool = winmerge

[mergetool "winmerge"]
    name = WinMerge
    trustExitCode = true
    cmd = "/c/Program\\ Files\\ \\(x86\\)/WinMerge/WinMergeU.exe" -u -e -dl \"Local\" -dr \"Remote\" $LOCAL $REMOTE $MERGED

[diff]
    tool = winmerge

[difftool "winmerge"]
    name = WinMerge
    trustExitCode = true
    cmd = "/c/Program\\ Files\\ \\(x86\\)/WinMerge/WinMergeU.exe" -u -e $LOCAL $REMOTE


Thursday, December 19, 2019

rxjs Reminders

 Links

This blog post is based on the free training video "Learn RxJS in 60 Minutes for Beginners - Free Crash Course" from Gary Simon.


Code Samples



Cold Observable

import { Observable } from 'rxjs/Observable';

// Observable producer actived when subscribed
const observable = Observable.create((observer: any) => {
    try {
        observer.next('Hey guys!'); // Emit a value
        observer.next('how are you?'); // Emit a value
        let counter = 0;
        setInterval(() => {
            observer.next(`I am good [${counter++}]`);
        }, 2000);
        // observer.complete();
        // observer.next('This will not be sent'); 
    }
    catch(ex) {
        observer.error(ex);
    }
});

const observer = observable.subscribe(
    (x:any) => { addItem(`[1] ${x}`); }, // next
    (error:any) => { addItem(`[ERROR]${error}`); }, // error
    () => { addItem('Completed'); }, // complete
);

const observer2 = observable.subscribe(
    (x:any) => { addItem(`[2] ${x}`); }, // next
);
observer.add(observer2); // Now observer2 will be canceled when observer is unsubscribed
//observer.remove(observer2); // undo the add

setTimeout(() => { // Canceled the observer to receive value after 6 seconds
    observer.unsubscribe();
}, 6001);

function addItem(val:any) {
    var node = document.createElement("li");
    node.appendChild(document.createTextNode(val));
    document.getElementById("output").appendChild(node);
}

Warn Observable

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/share';

// Observable producer actived when subscribed - Cold Observer
const observable = Observable.create((observer: any) => {
    try {
        observer.next('Hey guys!'); // Emit a value
        observer.next('how are you?'); // Emit a value
        let counter = 0;
        setInterval(() => {
            observer.next(`'I am good [${counter++}]`);
        }, 2000);
    }
    catch(ex) {
        observer.error(ex);
    }
}).share(); // Make it a warn Observable, subscriber only receive 
            // the stream from the moment they subscribed rather 
            // then from the beginning

const observer = observable.subscribe(
    (x:any) => { addItem(`[1] ${x}`); }, // next
    (error:any) => { addItem(`[ERROR]${error}`); }, // error
    () => { addItem('Completed'); }, // complete
);

setTimeout(() => {
    const observer2 = observable.subscribe(
        (x:any) => { addItem(`[2] ${x}`); }, // next
    );
}, 1000);

function addItem(val:any) {
    var node = document.createElement("li");
    node.appendChild(document.createTextNode(val));
    document.getElementById("output").appendChild(node);
}

Hot Observable

import { Observable } from 'rxjs/Observable';
import { fromEvent } from 'rxjs/Observable/fromEvent';

// Create hot Observable
const observable = fromEvent(document, 'mousemove');
setTimeout(() => {
    const subscription = observable.subscribe(
        (x:any) => { addItem(x); }
    );
}, 2000);

function addItem(val:any) {
    var node = document.createElement("li");
    node.appendChild(document.createTextNode(val));
    document.getElementById("output").appendChild(node);
}

Subject

import { Subject } from 'rxjs/Subject';

// A subject is an observable that can also emit values
const subject = new Subject();

subject.subscribe( 
    (data) => addItem(`Observer 1: ${data}`), // Subscribe call back/notification
    (err) => addItem(err),
    () => addItem(`Observer 1 Completed`)
);

subject.next('this first thing has been sent'); // Emit a value

const observer2 = subject.subscribe( // Add a second observer, will only receice new value emitted
    (data) => addItem(`Observer 2: ${data}`)
);

subject.next('this SECOND thing has been sent');
subject.next('this THIRD thing has been sent');

observer2.unsubscribe();

subject.next('this FINAL thing has been sent');

function addItem(val:any) {
    var node = document.createElement("li");
    node.appendChild(document.createTextNode(val));
    document.getElementById("output").appendChild(node);
}

BehaviorSubject

import { BehaviorSubject } from 'rxjs/BehaviorSubject';

// A subject is an observable that can also emit values
const subject = new BehaviorSubject('First');

subject.subscribe(
    (data) => addItem(`Observer 1: ${data}`), // Subscribe call back/notification
    (err) => addItem(err),
    () => addItem(`Observer 1 Completed`)
);

subject.next('this first thing has been sent'); // Emit a value
subject.next('...Observer 2 is about to subscribe'); // Emit a value

const observer2 = subject.subscribe( // Add a second observer, will start receiving from the LAST value emitted before subscription
    (data) => addItem(`Observer 2: ${data}`)
);

subject.next('this SECOND thing has been sent');
subject.next('this THIRD thing has been sent');

observer2.unsubscribe();

subject.next('this FINAL thing has been sent');

function addItem(val:any) {
    var node = document.createElement("li");
    node.appendChild(document.createTextNode(val));
    document.getElementById("output").appendChild(node);
}

ReplaySubject

import { ReplaySubject } from 'rxjs/ReplaySubject';

// A subject is an observable that can also emit values
const subject = new ReplaySubject(2); // <= Number of values to send to new observer

subject.subscribe(
    (data) => addItem(`Observer 1: ${data}`), // Subscribe call back/notification
    (err) => addItem(err),
    () => addItem(`Observer 1 Completed`)
);

subject.next('this first thing has been sent'); // Emit a value
subject.next('Another thing has been sent'); // Emit a value, will be received by both observer
subject.next('...Observer 2 is about to subscribe'); // Emit a value, will be received by both observer

const observer2 = subject.subscribe( // Add a second observer, will start receiving from the LAST value emitted before subscription
    (data) => addItem(`Observer 2: ${data}`)
);

subject.next('this SECOND thing has been sent');
subject.next('this THIRD thing has been sent');

observer2.unsubscribe();

subject.next('this FINAL thing has been sent');

function addItem(val:any) {
    var node = document.createElement("li");
    node.appendChild(document.createTextNode(val));
    document.getElementById("output").appendChild(node);
}

AsyncSubject

import { AsyncSubject } from 'rxjs/AsyncSubject';

// With AsyncSubject all values are sent only when the Observable is completed.
const subject = new AsyncSubject();

subject.subscribe(
    (data) => addItem(`Observer 1: ${data}`), // Subscribe call back/notification
    (err) => addItem(err),
    () => addItem(`Observer 1 Completed`)
);
let i = 1;
let intervalId = setInterval(() => { 
    if(i < 10) subject.next(i++);
    subject.complete();
}, 200); // Emit a integer value every 100 ms

setTimeout(() => {
    const observer2 = subject.subscribe( // Add a second observer, will start receiving from the 30 values, within the last 200 emitted before subscription
        (data) => addItem(`Observer 2: ${data}`)
    );
}, 1600);

function addItem(val:any) {
    var node = document.createElement("li");
    node.appendChild(document.createTextNode(val));
    document.getElementById("output").appendChild(node);
}

Merge Operator

import { Observable } from 'rxjs/Observable';
import { merge } from 'rxjs/observable/merge';

const observable = Observable.create((observer: any) => {
    observer.next(`Hey guys`);
});
const observable2 = Observable.create((observer: any) => {
    observer.next(`How is it going?`);
});

const newObservable = merge(observable, observable2);

newObservable.subscribe((x:any) => {
    addItem(x);
});

function addItem(val:any) {
    var node = document.createElement("li");
    node.appendChild(document.createTextNode(val));
    document.getElementById("output").appendChild(node);
}

Map Operator

import { Observable } from 'rxjs/Observable';
import { merge } from 'rxjs/observable/merge';

/* 
    RX JS OPERATOR: 
    https://rxjs-dev.firebaseapp.com/api/operators
    https://rxjs-dev.firebaseapp.com/guide/operators
*/

const observable = Observable.create((observer: any) => {
    observer.next(`Hey guys`);
});
const observable2 = Observable.create((observer: any) => {
    observer.next(`How is it going?`);
});

const newObservable = merge(observable, observable2);

newObservable.subscribe((x:any) => {
    addItem(x);
});

function addItem(val:any) {
    var node = document.createElement("li");
    node.appendChild(document.createTextNode(val));
    document.getElementById("output").appendChild(node);
}

Pluck Operator

import { from } from 'rxjs/Observable/from';
import 'rxjs/add/operator/pluck';

from([
    { first:'Gary', last: 'Simon', age:34 },
    { first:'Frederic', last: 'Torres', age:35 },
])
    .pluck('first')
    .subscribe((firstName:string) => {
        addItem(firstName);
    });
    
function addItem(val:any) {
    var node = document.createElement("li");
    node.appendChild(document.createTextNode(val));
    document.getElementById("output").appendChild(node);
}

SkipUntil Operator

import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { interval } from 'rxjs/Observable/interval';
import 'rxjs/add/operator/skipUntil';

const observable1 = Observable.create((data: any) => { // data is an Observable
    let i=1;
    setInterval(() => {
        data.next(i++);
    }, 1000);
});

const observable2 = new Subject();
setTimeout(() => {
    observable2.next('Hey!');
}, 3500);

const newObservable = observable1.skipUntil(observable2);
newObservable.subscribe((x: number) => {
    addItem(x);
}); 

function addItem(val:any) {
    var node = document.createElement("li");
    node.appendChild(document.createTextNode(val));
    document.getElementById("output").appendChild(node);
}

Wednesday, September 18, 2019

React Hooks ~ Quick Practice

Overview


Reading and practicing React 16 hooks (useState and useEffect)

Source Code


/*
  About React Hooks
  Introducing Hooks - https://reactjs.org/docs/hooks-intro.html
  https://reactjs.org/docs/hooks-overview.html
  Using the Effect Hook - https://reactjs.org/docs/hooks-effect.html
*/
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
    // Create a property message stored in the component state
    // and a funtion setMessage to update the value
    const [message, setMessage] = useState("no message!");
    // Create a property previousMessage stored in the component state
    const [previousMessage, setPreviousMessage] = useState(null);
    // Create a property counter stored in the component state
    const [counter, setCounter] = useState(0);

    // Everytime the component update, this function is executed
    // Similar to componentDidMount and componentDidUpdate
    useEffect(() => {
        console.log(`[useEffect] -- GLOBAL -- message:${message}, counter:${counter}`);
    });

    // Everytime the component update because the property message has changed,
    // this function is executed
    useEffect(() => {
        // Only run when message changed
        console.log(`[useEffect] -- message:${message}, counter:${counter}`);

        // We return a function that will be executed before the parent
        // function is executed the next time. This is used for clean up.
        return () => {
            // Run when the component unmount,
            // as well as before re-running the effect due to a subsequent render
            setPreviousMessage(message);
            console.log(`[useEffect Previous] -- message:${message}, counter:${counter}`);
        };
    }, [message]);

    const click = () => {
        setMessage(` msg-${Date.now()}`);
    };

    const onClickCounter = value => {
        setCounter(counter + value);
    };

    return (
        

React useState, useEffect

Counter: {counter}



Message: {message}

previousMessage: {previousMessage}

); } const rootElement = document.getElementById("root"); ReactDOM.render(, rootElement);

Saturday, June 29, 2019

Difference between JavaScript Engines

Spread operator

JavaScriptCore the JavaScript engine in SAFARI Mac Os and iOS as well as in Chrome iOS implements the spread operator differently than V8 (Chrome) or Spider Monkey (Firefox).


o1 = { id1:{ isSelected: false}, id2:{ isSelected: false}, id3:{ isSelected: false} }
selected = { id2:{ isSelected: true} }
r = {...o1, ...selected}

// Chrome Windows, FireFox Windows, Chrome MacOs
// The order of the key/property is preserved based on variable o1
{ id1:{ isSelected: false}, id2:{ isSelected: true}, id3:{ isSelected: false} }

// Safari Mac, Safari iOS, Chrome iOS
// The order of the key/property is NOT preserved based on variable o1
// The key/property id2 is now at the end
{ id1:{ isSelected: false}, id3:{ isSelected: false}, id2:{ isSelected: true}  }


This is not a bug, as you should not assume the order of the key/property in an dictionary or object.

Issue sorting array of objects in different browser 

Chrome and Firefix Windows will not return the same result.