Accessing compilation date and git revision during compilation in HaXe

It is often useful if a program knows the time when it was build and/or the git repository revision id it was build from. Unfortunately, one often forgets to update this information before launching the build. The following code can be used to do this automatically.

(P.S.: The code works even when compiling towards “non-Sys” platforms like JavaScript.)

class BuildInfo {
    /**
     * The time when this library was build.
     */
    public static var buildTime(default, null):Int = getBuildTime();

    /**
     * The git reversion that was used for the build.
     */
    public static var gitRev(default, null):String = getGITRevision();

    /**
     * Macros initalizing the build information.
     */
    public static macro function getBuildTime() {
        var buildTime = Math.floor(Date.now().getTime() / 1000);
        return macro $v{buildTime};
    }
    public static macro function getGITRevision() {
        var gitrev = new sys.io.Process("git", [ "rev-parse", "--verify", "HEAD" ]).stdout.readAll().toString();
        return macro $v{gitrev};
    }

    public static function main() {
        trace("This library was build the " + BuildInfo.buildTime);
        trace("by using revision " + BuildInfo.gitRev);
    }
}

The equal, equal operator in HaXe

The “==” operator to check object equality is implemented differently in the various programming languages. For example in Java, the “==” operator checks only the reference and you need the “equals”-Method in order to check the equality of objects:

String s1 = "foo";
String s2 = "foo";
System.out.println("" + (s1 == s2)); // will return false
System.out.println("" + (s1.equals(s2))); // will return true

In other languages like PHP, the “==”-operator can behave even more … strange …:

$a = "3.14159265358979326666666666";
$b = "3.14159265358979323846264338";
echo "" . ($a == $b); // will be 1 == true

So how is the “==”-operator defined in HaXe that can be cross-compiled into multiple languages including PHP and Java?

Well within Haxe, basic types like Int, Float, Strings and Bools are compared by values. So:

class Test {
    static function main() {
        var c1:String = "Hello";
        var c2:String = "World";
        trace(c1 == c2);  // will return false
        var c1:String = "Hello";
        var c2:String = "Hello";
        trace(c1 == c2);  // will return true
    }
}

However nob basic types are compared by-reference:

class C { public function new() {} }

class Test {
    static function main() {
        var c1:C = null;
        var c2:C = null;
        trace(c1 == c2); // will return true
        var c1:C = new C();
        var c2:C = new C();
        trace(c1 == c2); // will return false
    }
}

Solving npm Usage of the –dev option is deprecated. Use –only=dev instead.

Problem:

You want to install development dependencies for a NodeJS package using

npm install --dev

but you get this error message:

npm WARN install Usage of the `--dev` option is deprecated. Use `--only=dev` instead.

Solution:

You can use

npm install # Install normal (not development) dependencies
npm install --only=dev # Install only development dependencies

instead. Note that npm install --only=dev will only install development dependencies, so in most cases you want to run both commands.

Using nodemon without a global installation

Problem:

You want to use nodemon in order to automatically reload your NodeJS server, however you don’t want to require a global installation (npm install -g nodemon) but instead install it locally into the node_modules directory:

Solution:

First, install nodemon as dependency (

npm install --save-dev nodemon

We installed it as development dependency for this example, but it will work just as well if you install it as a normal dependency using --save instead of --save-dev.

After that, add a script entry in package.json:

"scripts": {
  "devserver": "./node_modules/nodemon/bin/nodemon.js index.js"
}, /* rest of package.json */

Replace index.js with the name of the file you want to run using nodemon.

Now you can start the development server using

npm run devserver

How to use query string parameters in NodeJS request

Problem:

You’re using the request library in order to make a HTTP GET request:

const request = require("request")

request.get("http://localhost:8000", function(err, response, body) {
    console.log(err, body);
})

Now you’re trying to add query parameters to the request. For this example, we’ll assume that you want to add one parameter: foo=bar

Solution:

You can use the qs parameter like this:

const request = require("request")

request.get({url: "http://localhost:8000", qs: {"foo": "bar"}}, function(err, response, body) {
    console.log(err, body);
})

Note that just adding a qs parameter to request.get won’t work, you need to have a dictionary as first argument that contains at least {"url": <your URL>, "qs": {<one or multiple query parameters>}}

Credits to Daniel at StackOverflow

How to solve git: fatal: No configured push destination

Problem:

You  have initialized a git repository in a folder using

git init

Now that you have made some commits, you want to use

git push

but you get the following error message:

fatal: No configured push destination.
Either specify the URL from the command-line or configure a remote repository using

    git remote add <name> <url>

and then push using the remote name

    git push <name>

Solution:

As you initialized your repository using git init, git does not know which server to contact when you use git push.

Therefore, we’ll have to add a server (called remote in git terminology) to the repository:

git remote add origin git@github.com:yourusername/yourrepository.git

This adds a server (remote add) named origin with the URL git@github.com:yourusername/yourrepository.git

The URL (last argument) depends on the server you use, for GitHub, you can get the URL (HTTPS or SSH, both will work) by clicking the green Clone or Download button.

Note that just adding the remote does not communicate with the

Now you can push your existing data to the server. git push by itself won’t work for the first time, because git doesn’t know automatically that you want to push to origin. Therefore we have to tell it using --set-upstream that future git push commands shall automatically push to origin:

git push --set-upstream origin master

If this command lists an error, you likely used the wrong URL for the repository or you don’t use the correct credentials (username/password, SSH key etc).

From now on, you can just use

git push

every time you’ve made a commit in order to push it to the server.

Note: origin is no special name, it’s just the name git uses for the server when you git clone a repository. Therefore it’s the standard name for your main server to push to.

Fixing LaTeX Unknown option fetbodydiode for package circuitikz

Problem:

You want to compile a LaTeX file containing CircuiTikZ code but you get the following error:

LaTeX Error: Unknown option `fetbodydiode' for package `circuitikz'

Solution:

You have an outdated CircuiTikZ version (fetbodydiode is in TeXLive 2016+).  Depending on your distribution, there are several ways to update CircuiTikZ:

For ubuntu, see this post to update to TeXLive 2016

For other distributions, see this post using tlmgr

Fixing CircuiTikZ Error: I do not know the key ‘/tikz/elmech’

Problem:

You want to compile a LaTeX file containing CircuiTikZ code but you get the following error:

Error: I do not know the key '/tikz/elmech'

Solution:

First, be sure that the circuitikz package is included, i.e. there’s a line like

\usepackage{circuitikz}

in your LaTeX file.

If that is the case, you likely have an outdated CircuiTikZ version (elmech is in TeXLive 2016+).  Depending on your distribution, there are several ways to update CircuiTikZ:

For ubuntu, see this post to update to TeXLive 2016

For other distributions, see this post using tlmgr

Identifying the frame length for an unknown serial protocol

Let’s suppose you’re reverse-engineering a serial protocol. You already know the correct configuration for the serial port (baudrate etc.) and you assume the protocol is built from frames of equal length.

For simplicity we will also assume that the device sends the data without the necessity to request data from it first. If this is not the case, you can use a different and much simpler approach (just send the request character and se

The next step is to determine the the frame length of the protocol. This post not only details two variants of one of the algorithms you can use in order to do this, but also provides a ready-to-use Python script you can use for your own protocols.

Approach 1: Autocorrelation with argmax

We will use a simple mathematical approach in order to find out what the most likely frame length will be. This is based on the assumption that frames will have a high degree of self similarity, i.e. many of the bytes in a single frame will match the corresponding bytes in the next frame.

It is not required that all bytes are the same in every frame, but if you have entirely different bytes in every frame, the approach will likely not deduce the correct frame length.

This approach is based on autocorrelation. Although it sounds complicated, it means nothing more Compare a sequence by a delayed/shifted version of itself.

This means we will perform the following steps:

  • Read a set of characters from the serial device
  • Correlate the set of characters with shifted versions of itself
  • The framelength is the shift where the maximum similarity occurs (using np.argmax)

As similiarity score, we’ll use 1 if the bytes equal or 0 else. For specific protocols, it might be a more viable approach to introduce individual bit matching, but this will also introduce noise into the process. 

For most simple protocols I’ve seen, this approach works very well for both ASCII and binary.

Plotting the correlation looks like this:

Approach 2: Multiple-shift aware Autocorrelation

This modified algorithms works well for protocols where there is insignificant similarity between any two frames or if there is a lot of noise. For such protocol, the maximum score approach does not yield the correct result.

However, we can use the property of constant-framelength protocols that we get high matching scores by shifting a frame by an integer multiple of the (unknown) framelength. Instead of just taking one maximum peak, we multiply all the scores for the integer-multiples of any length.

While this approach doesn’t sound too complicated compared to the first one, it has more caveats and pitfalls, e.g. that there are no integer multiples within the data array for the second half of the correlation result array, and the second quarter is not very significant as there are not many multiples to multiply.

The script (see below) works around these issues by only computing the first quarter of the possible result space. Use the -n parameter in order to increase the number of characters read by the script.

After computing the multiple-shift aware correlation, we can use argmax just like in the first approach to find the best correlation. Sometimes this identifies a multiple of the frame length due to noise. You can look at the plot (use -p) and manually determine the frame length in order to find the correct frame length.

As you can see from the result, the “noise” (in between the frame-length shift matches, caused by random matches between characters) is mostly gone.

In many real usecases, this algorithm will produce a more distinct signal in the plot, but the automatically calculated frame size will not be correct as several effects tend to increase the lobe height for multiples of the frame height. Therefore, it is adviseable to have a look at the plot (-p in the script) before taking the result as granted.

Automating the algorithm

Here’s the Python3 script to this article which works well without modification, but for some protocols you might need to adjust it to fit your needs:

#!/usr/bin/env python3
"""
ProtocolFrameLength.py

Determine the frame length of an unknown serial protocol
with constant-length frames containing similar bytes in every frame.

For an explanation, see
Identifying the frame length for an unknown serial protocol
Example usage: $ python3 ProtocolFrameLength.py -b 115200 /dev/ttyACM0 """ import serial import numpy as np import math from functools import reduce import operator __author__ = "Uli Köhler" __license__ = "Apache License v2.0" __version__ = "1.0" __email__ = "ukoehler@techoverflow.net" def match_score(c1, c2): """ Correlation score for two characters, c1 and c2. Uses simple binary score """ if c1 is None or c2 is None: # Fill chars return 0 return 1 if c1 == c2 else 0 def string_match_score(s1, s2): assert len(s1) == len(s2) ln = len(s1) return sum(match_score(s1[i], s2[i]) for i in range(ln)) def compute_correlation_scores(chars, nomit=-1): # Omit the last nomit characters as single-char matches would be over-valued if nomit == -1: # Auto-value nomit = len(chars) // 10 corr = np.zeros(len(chars) - nomit) # Note: autocorrelation for zero shift is always 1, left out intentionally! for i in range(1, corr.size): # build prefix by Nones prefix = [None] * i s2 = prefix + list(chars[:-i]) # Normalize by max score attainable due to Nones and the sequence length (there are i Nones) corr[i] = string_match_score(chars, s2) / (len(chars) - i) return corr def print_most_likely_frame_length(correlations): # Find the largest correlation coefficient. This model does not require a threshold idx = np.argmax(correlations) print("Frame length is likely {} bytes".format(idx)) def plot_correlations(correlations): from matplotlib import pyplot as plt plt.style.use("ggplot") plt.title("Correlation scores for a protocol with 16-byte frames") plt.gcf().set_size_inches(20,10) plt.plot(correlations) plt.title("Correlation scores") plt.ylabel("Normalized correlation score") plt.xlabel("Shift") plt.show() def multishift_adjust(correlations): """ Multi-shift aware algorithm """ corr_multishift = np.zeros(correlations.size // 4) for i in range(1, corr_multishift.size): # Iterate multiples of i (including i itself) corr_multishift[i] = reduce(operator.mul, (correlations[j] for j in range(i, correlations.size, i)), 1) return corr_multishift if __name__ == "__main__": import argparse parser = argparse.ArgumentParser() parser.add_argument('port', help='The serial port to use') parser.add_argument('-b', '--baudrate', type=int, default=9600, help='The baudrate to use') parser.add_argument('-n', '--num-bytes', type=int, default=200, help='The number of characters to read') parser.add_argument('-m', '--multishift', action="store_true", help='Use the multi-shift aware autocorrelation algorithm') parser.add_argument('-p', '--plot', action="store_true", help='Plot the resulting correlation matrix') args = parser.parse_args() ser = serial.Serial(args.port, args.baudrate) ser.reset_input_buffer() chars = ser.read(args.num_bytes) corr = compute_correlation_scores(chars) if args.multishift: corr = multishift_adjust(corr) print_most_likely_frame_length(corr) if args.plot: plot_correlations(corr)

 

Usage example:

python3 ProtocolFrameLength.py -b 115200 /dev/ttyACM0

You can use -m to use the multiple-shift aware approach.

Use -p to plot the results as shown above. If one of the approaches does not work, it is advisable to plot the result in order to see if there is something visible in the plot which has not been detected by the

As the results depend on the actual data read, it is advisable to perform multiple runs and see if the results vary.

Fixing LaTeX Error: File … not found on Debian/Ubuntu

Problem:

You’re using latex or pdflatex to compile a .tex file, but you get an error message similar to this one (the solution will work for any missing file, not just utf8x.def):

! LaTeX Error: File `utf8x.def' not found.

Now you’re wondering which package you need to install

Solution 1: Install everything

This problem can often be fixed once and for all by just installing all packages:

sudo apt-get install texlive-full

However, this pulls in a huge amount of packages and is therefore not recommended for most situations.

Solution 2: Install only required package

You can use apt-file to find the package containing the missing file and install it.

First, update the list of files in all known packages (sudo apt-get install apt-file if required):

sudo apt-file update

You only need to do this once every few months or so, before you use apt-file.

Then, look for the missing file (replace utf8x.def by your missing file):

$ apt-file search utf8x.def
texlive-lang-japanese: /usr/share/texlive/texmf-dist/tex/latex/bxbase/bxutf8x.def
texlive-latex-extra: /usr/share/texlive/texmf-dist/tex/latex/ucs/utf8x.def
texlive-luatex: /usr/share/texlive/texmf-dist/tex/lualatex/luainputenc/lutf8x.def

Now it takes some educated guessing which of the three listed packages (texlive-lang-japanese, texlive-latex-extra, texlive-luatex) needs to be installed. In this case, texlive-latex-extrais the correct choice as the other packages list the missing file only in some subdirectory of package (like luainputenc). If in doubt, you can just install all of the listed packages.

Fixing VTiger “Illegal request” for links from other domains

Problem:

You’ve got a link to your VTiger installation from another domain, but any time you open it, you get an Illegal request error message, even though you are logged in correctly.

Solution:

The reason for this error message is that vtiger validates the Referer (i.e. source URL of the request) as a protection layer against certain security issues, for example CSRF (cross-site request forgery). We will disable the referer check. Be sure to understand the implications before you do as suggested.

Disabling involves only editing a single code line. I tested this with VTiger 6.5.0, but likely only minor adjustments have to be made for other versions.

Steps to fix:

  • Open <your vtiger directory>/includes/http/Request.php in a text editor
  • In the editor. search for Illegal request. You will see a code block like this:
protected function validateReferer() {
$user=  vglobal('current_user');
        // Referer check if present - to over come 
        if (isset($_SERVER['HTTP_REFERER']) && $user) {//Check for user post authentication.
                global $site_URL;
                if ((stripos($_SERVER['HTTP_REFERER'], $site_URL) !== 0) && ($this->get('module') != 'Install')) {
                        throw new Exception('Illegal request');
                }
        }
        return true;
}
 
  • Comment out throw new Exception('Illegal request'); with // (results in //throw new Exception('Illegal request');)
  • The code block should now look like this:
protected function validateReferer() {
$user=  vglobal('current_user');
        // Referer check if present - to over come 
        if (isset($_SERVER['HTTP_REFERER']) && $user) {//Check for user post authentication.
                global $site_URL;
                if ((stripos($_SERVER['HTTP_REFERER'], $site_URL) !== 0) && ($this->get('module') != 'Install')) {
                        //throw new Exception('Illegal request');
                }
        }
        return true;
}
 
  • Save the file
  • The fix should be in effect immediately, else restart your webserver.

How to resolve fatal error: bytecode stream generated with LTO version … instead of the expected …

Problem:

When compiling a program or library with GCC, you get an error message similar to this:

fatal error: bytecode stream generated with LTO version 5.1 instead of the expected 5.2

Solution:

This error basically means that you’ve got some binary build results (mostly object files) which are incompatible with other binary build results, but you’re trying to link them together. The LTO part just means that the incompatibility is due to you having link-time optimization enabled – but you don’t need to worry about that, you can just treat it like any other incompatibility.

In almost all cases, there is a very simple reason for the error: You have built your project with an older GCC version, then updated GCC and re-compiled (partially, as not all files have been changed) later. In this case, there is a simple solution: Just clean your build and re-build from scratch.

If you use make (or CMake), this is usually as simple as

make clean # Remove old, incompatible files
make # Rebuild

For other buildsystems, lookup how to clean your build accordingly – or just delete your build or dist directory if that doesn’t cause any unintended side effects.

In some very rare cases, an issue in the build system configuration causes the software to be built with two different compilers. If you think that might be the case (i.e. if the cleaning process does not help), I suggest trying to look at the verbose output of your build system — however, keep in mind that it’s more likely that you’re trying to link a stray object file that has been built with an older version of the compiler.

If you’re happy with just fixing the symptom while ignoring the possibility of hard-to-debug incompatibilities, you can just omit the -flto flag in the build system config. This hides the LTO incompatibility as it disables the link-time optimizer altogether, but even if no new error codes are shown, this approach is generally not recommended.

Disabling SSL certificate checking in unirest (NodeJS)

Problem:

You want to make a HTTP request with unirest like this:

const unirest = require('unirest');
unirest.get("https://mydomain.net").end(console.log)

but you encounter the following error:

{ error: 
   { Error: unable to verify the first certificate
       at TLSSocket.<anonymous> (_tls_wrap.js:1088:38)
       at emitNone (events.js:86:13)
       at TLSSocket.emit (events.js:188:7)
       at TLSSocket._finishInit (_tls_wrap.js:610:8)
       at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:440:38) code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' } }

 Solution:

You can work around this problem by using strictSSL(false) like this:

const unirest = require('unirest');

unirest.get("https://mydomain.net")
.strictSSL(false)
.end(console.log)

Note however that this might have negative effects on the security of your application as this request will be vulnerable to man-in-the-middle attacks.

How to use concurrent.futures map with a tqdm progress bar

Problem:

You have a concurrent.futures executor, e.g.

import concurrent.futures

executor = concurrent.futures.ThreadPoolExecutor(64)

Using this executor, you want to map a function over an iterable in parallel (e.g. parallel download of HTTP pages).

In order to aid interactive execution, you want to use tqdm to provide a progress bar, showing the fraction of futures

Solution:

You can use this function:

from tqdm import tqdm
import concurrent.futures

def tqdm_parallel_map(executor, fn, *iterables, **kwargs):
    """
    Equivalent to executor.map(fn, *iterables),
    but displays a tqdm-based progress bar.
    
    Does not support timeout or chunksize as executor.submit is used internally
    
    **kwargs is passed to tqdm.
    """
    futures_list = []
    for iterable in iterables:
        futures_list += [executor.submit(fn, i) for i in iterable]
    for f in tqdm(concurrent.futures.as_completed(futures_list), total=len(futures_list), **kwargs):
        yield f.result()

Note that internally, executor.submit() is used, not executor.map() because there is no way of calling concurrent.futures.as_completed() on the iterator returned by executor.map().

Script user input

Problem

You want to remote control a program but unfortunately this program has only a “klick&gaudy”(*) interface.
(*) Okok – only has a graphical user interface (short GUI).

Solution

You may use xdotool in order to script user actions. To install this tool, use:

sudo apt-get install xdotool

Now you can get the position of the mouse pointer with:

xdotool getmouselocation

or set it via:

xdotool mousemove 400 300 (This means set the mouse to position x=400, y=300; Point of origin is the top left corner of the screen.)

In order to click use:

xdotool click 1

And in order to type a text (e.g. into a control field of the GUI)

xdotool type 'Hello World'

(P.S.: xdotool has much more options … Once this tool got installed type man xdotool in order to see them all.)

Exporting campaign contact CSVs from VTiger using SQL

In Exporting campaign account CSVs from VTiger using SQL we investigated how to use direct SQL database access to export names and emails for organizations for a given campaign.

This post shows how to do the same thing. Please refer to the previous post for a detailed explanation.

SELECT CONCAT(cont.firstname, " ", cont.lastname) AS "Name", cont.email AS "EMail" FROM vtiger_campaigncontrel AS ccr JOIN vtiger_contactdetails cont ON (cont.contactid = ccr.contactid) WHERE `campaignid` =(SELECT postvalue FROM `vtiger_modtracker_detail` WHERE fieldname = "record_id" AND `id` = (SELECT `id` FROM `vtiger_modtracker_detail` WHERE postvalue = (SELECT campaign_no FROM vtiger_campaign WHERE `campaignname` = "MyCampaign") and fieldname = "campaign_no")) AND cont.email <> ''

Besides joining on vtiger_contactdetails and vtiger_campaigncontrel instead of the account-related equivalent, the only major difference is in assembling the name. For contacts, first name and last name are stored separatedly. Therefore we use CONCAT(cont.firstname, " ", cont.lastname) to get a single name string out of that information.

As shown in the previous post, you can use phpmyadmin to export the result of the query to CSV or to Excel directly. While this might seem like a tedious process, it is much less tedious than copy-and-pasting hundreds of contacts manually.

Play a sound in a Webbrowser

Problem:

You want to play some sounds in a webbrowser.

Solution:

Modern Browsers have a fancy integrated AudioContext that allows you to play sounds. Here is an example (JavaScript Code):

// get the AudioContext
window.AudioContext = window.AudioContext || window.webkitAudioContext;

// Initialize audio context
var context = new AudioContext();

// Create an oscillator ... via this oscillator we can then play different sounds
var oscillator = context.createOscillator();
oscillator.frequency.value = 440; // this is an "A"
oscillator.type = "square";

// attach the oscillator to the sound output
oscillator.connect(context.destination);

oscillator.start(0); // start the oscillator (0=now) ...
oscillator.stop(1);  // stop playing this sound after 1 second

Exporting campaign account CSVs from VTiger using SQL

Update: Related post for exporting contacts instead of accounts

Although VTiger works great as CRM, its campaign management feature is missing one of most important features: It doesn’t support exporting

This post aims to provide technically oriented users a guide on how to use SQL queries to perform that task. We assume basic knowledge of SQL syntax, MySQL and PHPMyAdmin.

The goal for our example is to export a table of Account name and E-Mail. For the email, the primary email will be used, unless it’s empty in which case the secondary email is used.

The input for the query is the campaign name (in our example, this will be MyCampaign).

Querying the campaign number

The campaign number is a string, e.g. CAM4 or CAM9 which is stored in vtiger_campaign.

SELECT campaign_no FROM vtiger_campaign WHERE `campaignname` = "MyCampaign"

 Finding the campaign record ID

In the campaign account relations n-to-n relations table, the campaign number is not used directly – instead, the campaign record ID is used. We need to query that from vtiger_modtracker_detail, which contain metadata key-value-data about the campaigns (among other things). One of the K-V pairs contain the campaign identifier (key campaign_no) whereas another one contains the record ID (key record_id).

SELECT postvalue FROM `vtiger_modtracker_detail` WHERE `id` = (SELECT `id` FROM `vtiger_modtracker_detail` WHERE postvalue = <<campaign number>> and fieldname = "campaign_no") AND fieldname = "record_id"

Full query:

SELECT postvalue FROM `vtiger_modtracker_detail` WHERE `id` = (SELECT `id` FROM `vtiger_modtracker_detail` WHERE postvalue = (SELECT campaign_no FROM vtiger_campaign WHERE `campaignname` = "MyCampaign") and fieldname = "campaign_no") AND fieldname = "record_id"

The result of this query is the numeric campaign record ID, e.g. 315.

Querying campaign-to-account relations

We can now use the campaign record ID to query the n-to-n table vtiger_campaignaccountrel. There are other, similar tables for leads (vtiger_campaignleadrel) and contacts (vtiger_campaigncontrel).

SELECT accountid FROM vtiger_campaignaccountrel WHERE `campaignid` = <<campaign record ID>>

Full query:

SELECT accountid FROM vtiger_campaignaccountrel WHERE `campaignid` = (SELECT postvalue FROM `vtiger_modtracker_detail` WHERE fieldname = "record_id" AND `id` = (SELECT `id` FROM `vtiger_modtracker_detail` WHERE postvalue = (SELECT campaign_no FROM vtiger_campaign WHERE `campaignname` = "MyCampaign") and fieldname = "campaign_no"))

The result of this query is a list of account IDs related to the campaign. The order is usually the same as displayed in VTiger.

Querying account information

Using the list of account IDs, we can JOIN on vtiger_account to query the account details. Note that you need to use the appropriate table for leads or contacts if you used an alternative relations table in the previous step.

SELECT acc.accountname AS "Name", COALESCE(acc.email1, acc.email2) AS "EMail" FROM vtiger_campaignaccountrel AS car JOIN vtiger_account acc ON (acc.accountid = car.accountid) WHERE `campaignid` =(SELECT postvalue FROM `vtiger_modtracker_detail` WHERE fieldname = "record_id" AND `id` = (SELECT `id` FROM `vtiger_modtracker_detail` WHERE postvalue = (SELECT campaign_no FROM vtiger_campaign WHERE `campaignname` = "MyCampaign") and fieldname = "campaign_no")) AND (acc.email1 <> '' OR acc.email2 <> '')

Note that besides the SELECT column list there are some aspects which are specific to the Name and Email query:

  1. COALESCE(acc.email1, acc.email2) uses email2 if email1 is empty
  2. AND (email1 <> '' OR email2 <> '') ignores accounts that have neither email1 nor email2 set

If you want a custom list of columns, you need to modify that appropriately.

Exporting CSV

When entering the query into a tool like PHPMyAdmin, you can click the Export button in order to export the result to different formats, including CSV and Excel.

While this might not be the most convenient option, it’s a very flexible way of generating and exporting the data. Any more convenient ways are likely to be less flexible.

Fixing PPA Unable to identify ‘package’: user@mycomputer in launchpad

Problem:

You’ve uploaded a DEB package to a Launchpad PPA (e.g. using dput), but you get an error message similar to this:

Solution:

You need to use a proper email address (which must be registered in Launchpad) in debian/changelog .

In order to do this, set the $DEBEMAIL environment variable before running dch

Example:

export DEBEMAIL=myemail@example.com
dch [...]

If $DEBEMAIL is not set, [username]@[hostname] will be used

Graph layouting via Graphviz

Problem:

You want to display a Graph.

Solution:

Create a simple text file describing your graph and save it with a .dot file extension:

graph {
node1 -- node2;
node2 -- node3;
node3 -- node4;
node4 -- node1;
}

Afterwards you can use a program of the graphviz package (sudo apt-get install graphviz) in order to visualize the graph. This package contains different layouting programs like dot, neato, fdp (all from the GraphViz project) etc. Simply call one of these programs in order to visualize the graph:

neato -Tsvg yourFile.dot -o outputFile.svg

Output from this command: