Friday, 28 June 2024

[blogger.com] How to use syntax highlighting (or in blogspot.com)

I do not know of any designs of blogger.com that support syntax highlighting out-of-the-box. Alex Gorbatshev's syntax highlighter does not seem to work any longer. I am not sure, if it is me using having begone to use it wrongly or whether something else broke. So, I switched to highlight.js.

To make your design fit for it, you have to alter its html putting the following, e.g. directly at the end of the html header. As time of writing, however, this is not include the latest version. That is 11.9.0, but I have not found the according link tag for it.

    <!-- Thiemo, 2024-06-28 -->
    <link crossorigin='anonymous' href='https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/styles/default.min.css' integrity='sha512-3xLMEigMNYLDJLAgaGlDSxpGykyb+nQnJBzbkQy2a0gyVKL2ZpNOPIj1rD8IPFaJbwAgId/atho1+LBpWu5DhA==' referrerpolicy='no-referrer' rel='stylesheet'/>
    <script crossorigin='anonymous' integrity='sha512-Pbb8o120v5/hN/a6LjF4N4Lxou+xYZ0QcVF8J6TWhBbHmctQWd8O6xTDmHpE/91OjPzCk4JRoiJsexHYg4SotQ==' referrerpolicy='no-referrer' src='https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/highlight.min.js'/>
    <script>hljs.highlightAll();</script>

Key is that you put your code inside the a vanilla code tag that resides within a vanilla pre tag.

<pre><code>
</code></pre>

The language should get detected but you can force it with the according value to the class attribute of the code tag.

<pre><code class="">
</code></pre>

Some examples

SQL

-- language-sql
select * from dual;

XML (HTML, …)

<!-- language-html -->
<tag1>
    <tag2 attribute="attr"/>
    <tag3>bla<tag3>
</tag1>

R

# language-r
# Program to find the H.C.F of two input number

# define a function
hcf  y) {
        smaller = y
    } else {
        smaller = x
    }
    for(i in 1:smaller) {
        if((x %% i == 0) && (y %% i == 0)) {
            hcf = i
        }
    }
    return(hcf)
}

# take input from the user
num1 = as.integer(readline(prompt = "Enter first number: "))
num2 = as.integer(readline(prompt = "Enter second number: "))

print(paste("The H.C.F. of", num1,"and", num2,"is", hcf(num1, num2)))

Java

// language-java
/**
 * Diese Klasse ist eine allgemeine Klasse für jedes beliebige Tier und bietet
 * Methoden an, die alle Tiere gemeinsam haben.
 */
public class Tier {
	/**
	 * Diese Methode lässt das Tier kommunizieren. Die Unterklassen dieser
	 * Klasse können diese Methode überschreiben und eine passende
	 * Implementierung für das jeweilige Tier anbieten.
	 */
	public void kommuniziere() {
	    // Wird von allen Unterklassen verwendet, die diese Methode nicht überschreiben.
	    System.out.println("Tier sagt nichts.");
	}
}

/**
 * Deklariert die Klasse "Hund" als Unterklasse der Klasse "Tier".
 * Die Klasse "Hund" erbt damit die Felder und Methoden der Klasse "Tier".
 */
class Hund extends Tier {
	/**
	 * Diese Methode ist in der Oberklasse "Tier" implementiert. Sie wird
	 * in dieser Klasse überschrieben und für die Tierart "Hund" angepasst.
	 */
	@Override
	public void kommuniziere() {
		// Ruft die Implementierung dieser Methode in der Oberklasse "Tier" auf.
		super.kommuniziere();
		// Gibt einen Text in der Konsole aus.
		System.out.println("Hund sagt: 'Wuff Wuff'");
	}
}

/**
 * Deklariert die Klasse "Katze" als Unterklasse der Klasse "Tier".
 * Die Klasse "Katze" erbt damit die Felder und Methoden der Klasse "Tier".
 */
class Katze extends Tier {
	/**
	 * Diese Methode ist in der Oberklasse "Tier" implementiert. Sie wird
	 * in dieser Klasse überschrieben und für die Tierart "Katze" angepasst.
	 */
	@Override
	public void kommuniziere() {
		// Ruft die Implementierung dieser Methode in der Oberklasse "Tier" auf.
		super.kommuniziere();
		// Gibt einen Text auf der Konsole aus.
		System.out.println("Katze sagt: 'Miau'");
	}
}

class Main {
	/**
	 * Methode die beim Programmstart aufgerufen wird.
	 */
	public static void main(String[] args) {
		// Deklariert eine Variable für Instanzen der Klassen "Hund" und "Katze"
		Tier tier;

		// Erstellt eine Instanz der Klasse "Hund" und speichert die Instanz in
		// der Variable "tier"
		tier = new Hund();
		// Ruft die Methode Hund.kommuniziere() auf
		tier.kommuniziere();

		// Erstellt eine Instanz der Klasse "Katze" und speichert die Instanz in
		// der Variable "tier"
		tier = new Katze();
		// Ruft die Methode Katze.kommuniziere() auf
		tier.kommuniziere();
	}
}

PowerShell broken?

# language-powershell
# Fixes the problem that updates of M$ Windoof overwrite the general EFI file
# for booting. An impertinent behavior of M$ that annoys me to fix. So it shall
# be done by an automatic task.

# $Header: svn+ssh://thiemo__fileserver/srv/svn_repos/Dokumente/software/PowerShell/fix_grub.ps1 1443 2018-12-31 15:45:36Z thiemo $

# Constants
# You can figure out following numbers with
# Get-Disk
# Set-Disk -Number $figured_from_above -IsOffline $False
# Get-Volume -Disknumber 
# Get-Partition -DiskNumber $figured_from_above
Set-Variable number_of_efi_harddisk -Option Constant -Value 0
Set-Variable number_of_efi_partition -Option Constant -Value 1
Set-Variable partition_lettre_access_path -Option Constant -Value 'Z:'
Set-Variable source_path -Option Constant `
                         -Value ($partition_lettre_access_path +
								 '\EFI\ubuntu\grubx64.efi')
Set-Variable target_path -Option Constant `
                         -Value ($partition_lettre_access_path +
								 '\EFI\Boot\bootx64.efi')

# I boot my Windoof from an external USB, so I might need to bring online 
# the internal disk.
Set-Disk -Number $number_of_efi_harddisk -IsOffline $False

# I mount the EFI volume.
Add-PartitionAccessPath -DiskNumber $number_of_efi_harddisk `
 						-PartitionNumber $number_of_efi_partition `
 						-AccessPath $partition_lettre_access_path

# The actual fix
Copy-Item $source_path -Destination $target_path

# I unmount the EFi volume to not endanger it.
Remove-PartitionAccessPath -DiskNumber $number_of_efi_harddisk `
 						   -PartitionNumber $number_of_efi_partition `
 						   -AccessPath $partition_lettre_access_path

Python

# language-python
#!/usr/bin/python3

# Developed with Python 3.6
# $Header: svn+ssh://thiemo__fileserver/srv/svn_repos/Dokumente/software/deploy.py 1665 2019-12-22 22:33:19Z thiemo $
u"""============================================================================
deploy
================================================================================
Script to easen deployment
It is required to start it within the directory structure to install, e. g.
the release tag.

:Version: $Rev: 1665 $
$Header: svn+ssh://thiemo__fileserver/srv/svn_repos/Dokumente/software/deploy.py 1665 2019-12-22 22:33:19Z thiemo $
Developed against Python 3.6.5
"""


# import libraries and stuff
###
# import argparse
from datetime import datetime
import logging
from logging.handlers import RotatingFileHandler
import lzma
from os import system   # NOTE system calls are not portable usually!
import os
from pathlib import Path
from pathlib import WindowsPath
import re
import subprocess
import sys
import traceback


u"""Global constants
--------------------------------------------------------------------------------
"""
SQLPLUS_LOG_FILE = "install_master.log"
RE_ENV_NON_DEV = re.compile('^INT|KONS|PROD$')
RE_ORACLE_ERROR_LINE = \
  re.compile('^(ERROR at line \d+:|(ORA|PLS)-\d{5}:|(SP2|CPY)-\d{4})')


u"""Classes
--------------------------------------------------------------------------------
"""
class Error(Exception):
    u"""Base class for exceptions."""
    pass

class InputError(Error):
    u"""Exception raised for errors in the input.

    Attributes:
        expression -- input expression in which the error occurred
        message -- explanation of the error
    """
    def __init__(self, expression, message):
        self.expression = expression
        self.message = message

u"""Functions
--------------------------------------------------------------------------------
"""
def executeExternalAndLog(cmd, logger, reErrorLine):
    u"""Executes given 'exploded' command and logs its results to given logger.

    Given compiled regular expression is used to log lines as errors.
    """
    try:
        result = \
          subprocess.run(args=cmd,
                         check = True,
                         stdout = subprocess.PIPE, # to capture output
                         stderr = subprocess.PIPE, # to capture error
                         encoding = 'utf-8',
                         universal_newlines=True)
    except subprocess.CalledProcessError as e:
        logger.debug('Command: {}'.format(e.cmd)) # DEBUG because can contain password
        logger.info('Return code: {}'.format(e.returncode))
        logger.info("Stdout")
        for line in e.stdout.splitlines():
            if reErrorLine.match(line):
                logger.error(line)
            else:
                logger.info(line)
        logger.critical("Stderr")
        for line in e.stderr.splitlines():
            logger.critical(line)
        raise
    except:
        logger.critical(sys.exc_info())
        raise
    else:
        for line in result.stdout.splitlines():
            logger.info(line)

def createLZMACompressedFile(fileNameIn, fileNameOut, logger, removeIn = False):
    u"""Compresses in file to out file using LZMA.

    The in file gets removed optionally.
    """
    logger.debug("fileNameIn: {}".format(fileNameIn))
    logger.debug("fileNameOut: {}".format(fileNameOut))
    logger.debug("Current path: {}".format(os.getcwd()))

    # Treat data as bytes to compress (wb and rb respectively)
    with lzma.open(filename = fileNameOut,
                   mode = 'wb',
                   format = lzma.FORMAT_ALONE,
                   preset = lzma.PRESET_EXTREME) as fileOut:
        with open(fileNameIn, 'rb') as fileIn:
            data = fileIn.read()

        fileOut.write(data)

    if removeIn:
        os.remove(fileNameIn)



u"""Main
--------------------------------------------------------------------------------
Deploys database objects to database schema

Features:
    - Logging with compressed commit to subversion for the main log file. The database log file is compressed only.
    - Detection if installation must go to DEV.
"""
if __name__ == '__main__':
    system('color 3e')
    scriptPathParts = Path(__file__).resolve().parts
    logDirectoryName = 'logs'
    scriptDirectory = Path(__file__).parent.resolve()
    logDirectory = scriptDirectory.joinpath(logDirectoryName)
    logDirectoryCreated = False
    if not logDirectory.is_dir():
        logDirectory.mkdir(parents = True, exist_ok = True)
        logDirectoryCreated = True

    # set up logging
    startTimestamp = datetime.now().strftime("%Y%m%d%H%M%S")
    logger = logging.getLogger('deploy')
    logLevel = 'INFO'
    logger.setLevel(logLevel)
    formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    logHandlerStream = logging.StreamHandler()
    logHandlerStream.setFormatter(formatter)
    logger.addHandler(logHandlerStream)
    logFileName = scriptPathParts[-1].replace('.py', '')
    # for debugging it is easier if the log file name stays the same
    if (not logger.isEnabledFor(logging.DEBUG)):
        logFileName = logFileName + '_' + startTimestamp
    logFileName = logFileName + '.log'
    logFile = logDirectory.joinpath(logFileName)
    # FIXME for some unknown reason to me the mode does not get respected, the log
    # file is appended. Maybe this is a "feature" of Windoof.
    logHandlerFile = RotatingFileHandler(
            filename = str(logFile),
            mode = 'w',
            maxBytes = 10485760,
            backupCount = 10,
            encoding = 'utf-8',
            delay = True)
    logHandlerFile.setFormatter(formatter)
    logger.addHandler(logHandlerFile)


    try:
        # Determine whether I run from within a tag, branch or the trunk and
        # extract the release name
        logger.debug('logFileName: {}'.format(logFileName))
        logger.debug('scriptPathParts: {}'.format(scriptPathParts))
        try:
            processingRootPathPartIndex = scriptPathParts.index('tags') + 1
            processingTag = True
            releaseName = scriptPathParts[processingRootPathPartIndex]
        except ValueError:
            processingTag = False
            try:
                processingRootPathPartIndex = scriptPathParts.index('trunk')
                releaseName = scriptPathParts[processingRootPathPartIndex]
            except ValueError:
                processingRootPathPartIndex = \
                  scriptPathParts.index('branches') + 1
                releaseName = scriptPathParts[processingRootPathPartIndex]

        logger.debug(
            'processingRootPathPartIndex: {}'.format(
                processingRootPathPartIndex))
        logger.debug(
            'scriptPathParts[processingRootPathPartIndex]: {}'.format(
                scriptPathParts[processingRootPathPartIndex]))
        logger.debug('releaseName: {}'.format(releaseName))

        # Get user input
        if processingTag:
            env = input('Please enter the instance ( INT KONS PROD ) ' +
                        'to deploy to: ')
            while env is None or RE_ENV_NON_DEV.match(env) is None:
                env = input('Please enter the instance ( INT KONS PROD ) ' +
                            'to deploy to: ')
            if env == 'INT':
                instance = 'DWHI_OLTP'
                # subprocess.run(["color", "0b"]) color seems to be a cmd internal
                system('color 0b')
            elif env == 'KONS':
                instance = 'DWHK_OLTP'
                # subprocess.run(["color", "0e"]) color seems to be a cmd internal
                system('color 0e')
            elif env == 'PROD':
                instance = 'DWHP_OLTP'
                # subprocess.run(["color", "0c"]) color seems to be a cmd internal
                system('color 0c')
        else:
            env = 'DEV'
            instance = 'DWHE_OLTP'
            logLevel = 'DEBUG'
            logger.setLevel(logLevel)
            # subprocess.run(["color", "0a"]) color seems to be a cmd interna
            system('color 0a')
        logger.debug('instance: {}'.format(instance))
        if (processingTag and env == 'DEV'):
            raise InputError('Get instance', 'It is not allowed to install a ' +
                             'tag release to {} environement!'.format(DEV))
        reValidSchema = re.compile('^CDWH|IL|TZ|LZ$')
        schema = input('Please enter the schema ( CDWH IL TZ LZ ) ' +
                       'to deploy to: ')
        while (schema is None or reValidSchema.match(schema) is None):
            schema = input('Please enter the schema ( CDWH IL TZ LZ ) ' +
                           'to deploy to: ')
        logger.debug('schema: {}'.format(schema))
        password = input('Please enter schema''s password: ')
        logger.debug('password: {}'.format(password))

        print('\nYou are going to install release "{}" against "{}@{}"'.\
          format(releaseName,schema, instance))
        reYesNo = re.compile('^[ynYN]$')
        goAhead = input('Are you ready to go? (Y, N) ')
        while (goAhead is None or reYesNo.match(goAhead) is None):
            goAhead = input('Are you ready to go? (Y, N) ')
        if goAhead == 'N' or goAhead == 'n':
            logger.info('User decided to end processing.')
            exit(0)
        logger.info('Installing release "{}" against "{}@{}". This may take a while, so please be patient.'.\
          format(releaseName,schema, instance))

        # Finally we can process things
        # Assemble database schema path and enter it
        databaseSchemaPath = WindowsPath()
        for part in scriptPathParts[0:processingRootPathPartIndex + 1]:
            databaseSchemaPath = databaseSchemaPath.joinpath(part)
        databaseSchemaPath = databaseSchemaPath.joinpath('database')
        databaseSchemaPath = databaseSchemaPath.joinpath(schema)
        logger.debug('databaseSchemaPath: {}'.format(databaseSchemaPath))
        os.chdir(databaseSchemaPath)
        # Install db objects
        executeExternalAndLog(["sqlplus",
                               "-L",
                               '{}/{}@{}'.format(schema, password, instance),
                               "@install_master.sql"],
                              logger,
                              RE_ORACLE_ERROR_LINE)

        # Compress log file if not DEV env
        if RE_ENV_NON_DEV.match(env):
            sqlplusLogFileNew = \
                "install_master_{}_{}@{}_{}.log.lzma".format(releaseName,
                                                        schema,
                                                        instance,
                                                        startTimestamp)
            logger.debug("sqlplusLogFileNew: {}".format(sqlplusLogFileNew))
            createLZMACompressedFile(fileNameIn = SQLPLUS_LOG_FILE,
                                     fileNameOut = sqlplusLogFileNew,
                                     logger = logger,
                                     removeIn = True)

    except Exception:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        logger.critical(exc_type)
        logger.critical(exc_value)
        logger.info('\n' + '\n'.join(
                traceback.format_tb(exc_traceback)))
        raise
    finally:
        # Doing some log file handling so the file handler of the logger better
        # be removed. Explicit close is required. Othe wise the file does not
        # get released causing 'PermissionError: [WinError 32]'
        logHandlerFile.close()
        logger.removeHandler(logHandlerFile)
        # Commit compressed log file to subversion if not DEV env
        if RE_ENV_NON_DEV.match(env):
            logFilNameNew = logFile.stem + "_{}_{}@{}.log.lzma".\
              format(releaseName,
                     schema,
                     instance)
            logger.debug("logFilNameNew: {}".format(logFilNameNew))
            logFileNew = logDirectory.joinpath(logFilNameNew)
            logger.debug("logFileNew: {}".format(str(logFileNew)))
            createLZMACompressedFile(fileNameIn = str(logFile),
                                     fileNameOut = str(logFileNew),
                                     logger = logger,
                                     removeIn = True)
            # Subversion interpretes the last @ within a name as delimiter to
            # a the revision. To prevent that we suffix the file name with @.
            # See the paragraph containing "append an at sign" of e. g.
            # http://svnbook.red-bean.com/en/1.7/svn.advanced.pegrevs.html
            logFileNewSvnCompatible = str(logFileNew) + '@'
            logger.debug("logFileNewSvnCompatible: {}".\
              format(str(logFileNewSvnCompatible)))
            if logDirectoryCreated:
                executeExternalAndLog(["svn",
                                       "add",
                                       "--depth=empty",
                                       str(logDirectory)],
                                      logger,
                                      None)
                executeExternalAndLog(["svn",
                                      "commit",
                                      "-m",
                                      "Run and commited by $Header: svn+ssh://thiemo__fileserver/srv/svn_repos/Dokumente/software/deploy.py 1665 2019-12-22 22:33:19Z thiemo $",
                                      str(logDirectory)],
                                     logger,
                                     None)

            executeExternalAndLog(["svn",
                                    "add",
                                    str(logFileNewSvnCompatible)],
                                   logger,
                                   None)
            executeExternalAndLog(["svn",
                                   "commit",
                                   "-m",
                                   "Run and commited by $Header: svn+ssh://thiemo__fileserver/srv/svn_repos/Dokumente/software/deploy.py 1665 2019-12-22 22:33:19Z thiemo $",
                                   str(logFileNewSvnCompatible)],
                                  logger,
                                  None)
        else:
            logger.info(
                "Log file '{}' not commited to subversion as we are in DEV.".\
                  format(logFile.name))
        logger.debug('main finished')

    exit(0)

Zsh

# language-zsh (apparently inexistant, bash might do instead)
#!/usr/bin/env zsh

set -e

# constants
    #_C_A_URLS="https://www.splittermond.de/downloads-neu/ https://www.aborea.de https://www.earthdawn-wiki.de/ https://ulisses-spiele.de/game-system/earthdawn/"
    typeset -r _C_SUFFIXES_ACCEPTED="pdf,PDF,htm,html,HTM,HTML,css,CSS"
    typeset -r _C_RATE_LIMIT="128k"
    typeset -r _C_DIR_TARGET="/srv/thiemo/mirrors"
    typeset -r _C_DIR_LOG="${HOME}/logs"
    typeset -r _C_FILE_NAME_LOG="$(basename -s "zsh" ${0})log"
    typeset -r _C_FILE_NAME_LOG_REJECTED="$(basename -s ".zsh" ${0})_rejected.log"
    typeset -r _C_FILE_PATH_LOG="${_C_DIR_LOG}/${_C_FILE_NAME_LOG}"
    typeset -r _C_FILE_PATH_LOG_REJECTED="${_C_DIR_LOG}/${_C_FILE_NAME_LOG_REJECTED}"

# variables
    _V_=unused

# functions
    mirror() {
        wget --mirror \
             --relative \
             --continue \
             --no-check-certificate \
             --limit-rate="${_C_RATE_LIMIT}" \
             --append-output="${_C_FILE_PATH_LOG}" \
             --no-verbose \
             --execute robots=off \
             --force-directories \
             --rejected-log="${_C_FILE_PATH_LOG_REJECTED}" \
             --convert-links \
             "${1}"
    }

# main
set -x
mkdir -p "${_C_DIR_TARGET}" "${_C_DIR_LOG}"
cd "${_C_DIR_TARGET}"
cat /dev/null > "${_C_FILE_PATH_LOG}"
#for _URL in ${_C_A_URLS} ; do
for _URL in https://www.splittermond.de/downloads-neu/ https://www.aborea.de https://www.earthdawn-wiki.de/ https://ulisses-spiele.de/game-system/earthdawn/ ; do
    # prepare target folder name
    # remove the protocols
    _FOLDER="${_URL/#https:\/\//}"
    _FOLDER="${_FOLDER/#http:\/\//}"
    # remove the folders
    _FOLDER="${_FOLDER%%\/*}"

    mkdir -p "${_FOLDER}"
    cd "${_FOLDER}"
    mirror "${_URL}"
    cd -
done

Bash

# language-bash
#!/usr/bin/env bash
# $LastChangedRevision: 1404 $
# $HeadURL: svn+ssh://thiemo__fileserver/srv/svn_repos/Dokumente/software/shell/roundTripPlaner.bash $
# $LastChangedDate: 2018-10-15 23:34:47 +0200 (Mo, 15 Okt 2018) $
# $LastChangedBy: thiemo $


# logging constants
declare -r _me="$(basename ${0})"
declare -r _startTimestamp="$(date '+%Y%m%d%H%M%S')"
declare -r _logDirPath="/tmp"
declare -r _logFileName="$(basename ${0} | cut -f 1 -d '.')_${_startTimestamp}_${$}.log"
declare -r _logFilePath="${_logDirPath}/${_logFileName}"

# functions
printSynopsis() {
   echo
   echo "${_me} [-d] -f <flag file path> [-c <currency to convert into> -r <currency conversion ration>] "
   echo "   -d                   switch on debugging"
   echo "   -f <flag file path>  path to the file where all the stations are"
   echo "                        listed:"
   echo "                        - must be ordered"
   echo "                        - can be addresses or co-ordinates"
   echo "                        - you should not repeat first station as last"
   echo "                          station"
   echo "   -c                   currency the amount in ${_currency} is to be converted into"
   echo "   -r                   ratio ${_currency}/<currency defined by -c switch>"
}

setupDebugging() {
   PS4="## "  # set another "prompt" for set -x output
   set -x
   if [[ "${BASH_VERSINFO[0]}" -gt "2" || ( \
            "${BASH_VERSINFO[0]}" -eq "2" && \
                  "$(echo ${BASH_VERSINFO[1]} | cut -c1-2)" -gt "05"
         ) \
      ]]
   then
      # not available in bash 2.05b.0(1)
      set -E
      set -T
   fi
   if [[ -z ${_debugging_switch} ]]
   then
      declare -r _debugging_switch="-d"
   fi
}

floatEval() {
   if [[ -n "${2}" ]]
   then
      echo "scale=${2}; ${1}" | bc -q
   else
      echo "scale=0; ${1}" | bc -q
   fi
}

reduceStarFileToDesired() {
   # BEWARE, sed scripts and tr string to replace contain field separator, i.e.
   # chr(28) or ^\ as dummy character as a direct replacement with Unix
   # linebreak was not possible
   sed \
         -e 's!\(<[Dd][Ii][Vv]><[Bb]>\)!\1!g' \
         -e 's!\(</[Bb]></[Dd][Ii][Vv]>\)!\1!g' "${1}" | \
         tr '' '
' | grep -Ei '^<DIV>[0-9]' | \
         cut -c9- | \
         cut -f 1 -d '&' > \
         "${1}.tmp"
   mv -f "${1}.tmp" "${1}"
}

reduceRoundTripFileToDesired() {
   # BEWARE, sed scripts and tr string to replace contain field separator, i.e.
   # chr(28) or ^\ as dummy character as a direct replacement with Unix
   # linebreak was not possible
   sed \
         -e 's!\(<[Dd][Ii][Vv]>\)!\1!g' \
         -e 's!\(</[Dd][Ii][Vv]>\)!\1!g' "${1}" | \
         tr '' '
' | grep -Ei '^<DIV>[0-9]' | \
         cut -c6- | \
         cut -f 1 -d '&' > \
         "${1}.tmp"
   mv -f "${1}.tmp" "${1}"
}

{
   # other constants
   declare -r _tmpDirPath="/tmp"
   declare -r _tmpFileName="$(basename ${0} | cut -f 1 -d '.')_tmp_${_startTimestamp}_${$}.html"
   declare -r _tmpFilePath="${_tmpDirPath}/${_tmpFileName}"
   _pricePerKm="1.5"
   _pricePerHorse="50"
   declare -r _scale="6"
   declare -r _priceScale="2"
   declare -r _baseUrl="http://maps.google.ch/maps?f=d&source=s_d&saddr="
   declare -r _urlTrailer="&hl=de&geocode=&mra=ls&t=h&z=10"
   _currency="CHF"
   _currencyConversionRation="1"
   _newCurrencySet="false"
   _newCurrencyConversionRationSet="${_newCurrencySet}"

   # get and check run parameters
   while getopts "c:df:r:" _option
   do
      case ${_option} in
         c )   _currency="${OPTARG}"
               _newCurrencySet="true"
               ;;
         d )   setupDebugging
               _wgetVerbosity="--debug"
               ;;
         f )   declare -r _flagFile="${OPTARG}"
               ;;
         r )   _currencyConversionRation="${OPTARG}"
               _newCurrencyConversionRationSet="true"
               ;;
         * )   echo "I do not know what to do with option ${_option}!"
               printSynopsis
               exit 1
               ;;
      esac
   done

   if [[ -z ${_flagFile} || "${#_flagFile}" == "0" || "${_newCurrencyConversionRationSet}" != "${_newCurrencySet}" ]]
   then
      echo "You must provide a file name!"
      printSynopsis
      exit 1
   fi
   if [[ -z "${_wgetVerbosity}" ]]
   then
      _wgetVerbosity="--quiet"
   fi

   # variables
   _pricePerKm="$(floatEval "${_pricePerKm} / ${_currencyConversionRation}" "${_scale}")"
   _pricePerHorse="$(floatEval "${_pricePerHorse} / ${_currencyConversionRation}" "${_scale}")"
   declare -i i
   declare -i _maxDistancesIndex
   declare -i _totalNumberOfHorses
   declare -a _flags
   declare -a _urls
   declare -a _distances
   declare -a _weighedDistances
   declare -a _numberOfHorses
   declare -a _comment
   _roundTripUrl=""

   # read in flags and number of horses from file
   # format is
   # <flag address or co-ordinates>:<number of horses>
   grep -Ev "^[[:space:]]*#" "${_flagFile}" > "${_tmpFilePath}"
   i=-1
   _totalNumberOfHorses=0
   while read _line
   do
      if [[ -n "${_line}" && "${#_line}" -gt 0 ]]
      then
         let "i += 1"
         if [[ "${i}" == "0" ]]
         then
            _startEndFlag="$(echo ${_line} | cut -d ':' -f 1)"
            _comment[${i}]="Start"
         else
            _numberOfHorses[${i}]="$(echo ${_line} | cut -d ':' -f 2 | tr -d ' ')"
            let "_totalNumberOfHorses = ${_totalNumberOfHorses} + ${_numberOfHorses[${i}]}"
            _comment[${i}]="$(echo ${_line} | cut -d ':' -f 3)"
         fi
         _flags[${i}]="$(echo ${_line} | cut -d ':' -f 1)"
      fi
   done < "${_tmpFilePath}"
   # if last in array does not equal the start add the closing flag for the
   # round trip
   if [[ "${_flags[${i}]}" != "${_startEndFlag}" ]]
   then
      let "i += 1"
      _flags[${i}]="${_startEndFlag}"
   fi
   let "_maxFlagIndex = ${#_flags[@]} - 1"

   # Loop through array to create the URLs
   roundTripUrl="${_baseUrl}"
   i=-1
   while [[ ${i} -lt ${_maxFlagIndex} ]]
   do
      let "i += 1"
      if [[ -n ${_debugging_switch} || "${#_debugging_switch}" != "0" ]]
      then
         echo "## i: ${i}"
         echo "## _flags[${i}]: ${_flags[${i}]}"
      fi
      _flag="$(echo ${_flags[${i}]} | tr ' ' '+')"
      if [[ "${i}" == "0" ]]
      then
         roundTripUrl="${roundTripUrl}${_flag}"
      else
         if [[ "${i}" == "1" && -n "${_flag}" ]]
         then
            roundTripUrl="${roundTripUrl}&daddr=${_flag}"
         else
            roundTripUrl="${roundTripUrl}+to:${_flag}"
         fi
         if [[ "${_startEndFlag}" != "${_flag}" ]]
         then
            _urls[${i}]="${_baseUrl}${_flag}&daddr=$(echo ${_startEndFlag} | tr ' ' '+')${_urlTrailer}"
         fi
      fi
   done

   # Display the round trip URL
   # firefox "${roundTripUrl}" &

   # Get the temporary html file for the round trip
   wget \
         --output-document="${_tmpFilePath}" \
         --no-directories \
         --no-host-directories \
         "${_wgetVerbosity}" \
         "${roundTripUrl}"

   # Get the total distance of the round trip
   i=0
   _totalRoundTripDistance=0
   reduceRoundTripFileToDesired "${_tmpFilePath}"
   while read _line
   do
      let "i += 1"
      _totalRoundTripDistance="$(floatEval "${_totalRoundTripDistance} + ${_line}")"
   done < "${_tmpFilePath}"

   # Get the single distances between start and one flag, and their total
   _totalHorsesStarDistance=0
   i=0
   let "_maxDistancesIndex = ${#_urls[@]} - 1"
   while [[ ${i} -lt ${_maxDistancesIndex} ]]
   do
      let "i += 1"
      wget \
            --output-document="${_tmpFilePath}" \
            --no-directories \
            --no-host-directories \
            "${_wgetVerbosity}" \
            "${_urls[${i}]}"
      reduceStarFileToDesired "${_tmpFilePath}"
      _distances[${i}]="$(head -1 ${_tmpFilePath})"
      _weighedDistances[${i}]="$(floatEval "(1 - ${_numberOfHorses[${i}]} / ${_totalNumberOfHorses} ) * ${_distances[${i}]}" "${_scale}")"
      _totalHorsesStarDistance="$(floatEval "${_totalHorsesStarDistance} + (${_numberOfHorses[${i}]} * ${_distances[${i}]})")"
   done


   # Display results
   echo
   echo "Service: $(echo "${_baseUrl}" | cut -d '/' -f1-3)"
   echo "Price per km: ${_pricePerKm} ${_currency}"
   i=-1
   while [[ ${i} -lt ${_maxDistancesIndex} ]]
   do
      let "i += 1";
      if [[ "${i}" == "0" ]]
      then
         echo "Start: ${_flags[${i}]}"
         echo
      else
         _part="$(floatEval "${_numberOfHorses[${i}]} * ${_distances[${i}]} / ${_totalHorsesStarDistance}" "${_scale}")"
         _price="$(floatEval "${_part} * ${_totalRoundTripDistance} * ${_pricePerKm}" "${_priceScale}")"
         _part="$(floatEval "100 * ${_part}")"
         _distance="$(floatEval "2 * ${_distances[${i}]}")"
         echo -e "\E[37;34m${_flags[${i}]}\033[0m"
         echo -e "   Total:              \E[37;34m$(floatEval "(${_numberOfHorses[${i}]} * ${_pricePerHorse}) + ${_price}" "${_priceScale}") ${_currency}\033[0m"
         echo -e "   Total way:           \E[37;34m${_price} ${_currency}\033[0m"
         echo -e "   Total per horse:     \E[37;34m$(floatEval "(${_pricePerHorse}) + (${_price} / ${_numberOfHorses[${i}]})" "${_priceScale}") ${_currency}\033[0m"
         echo -e "   Price way per horse: \E[37;34m$(floatEval "${_price} / ${_numberOfHorses[${i}]}" "${_priceScale}") ${_currency}\033[0m"
         echo -e "   Price per horse:     \E[37;34m${_pricePerHorse} ${_currency}\033[0m"
         echo -e "   Round trip distance: ${_totalRoundTripDistance} km"
         echo -e "   Part: ${_part} %"
         echo -e "   Number of horses: ${_numberOfHorses[${i}]}"
         echo -e "   Distance if only to this client: ${_distance} km"
         echo -e "   Comments: ${_comment[${i}]}"
         echo
      fi
   done
   echo
   echo -e "\E[37;32mTotal\033[0m: \E[37;32m${_totalRoundTripDistance} km\033[0m -> 100 % -> \E[37;32m$(floatEval "${_totalRoundTripDistance} * ${_pricePerKm}") ${_currency}\033[0m"
   echo

   if [[ -n ${_debugging_switch} || "${#_debugging_switch}" != "0" ]]
   then
      rm -f "${_tmpFilePath}"
   fi

} 2>&1 | tee "${_logFilePath}" # log everything

# clean up the files
if [[ -n ${_debugging_switch} || "${#_debugging_switch}" != "0" ]]
then
   rm -f "${_logFilePath}"
fi

No comments:

Post a Comment

[git] Create a local branch from another branch

From the active branch git checkout -b <LOCAL_BRANCH> From a donator branch git checkout -b <LOCAL_BRANCH> <DONATING_BRANCH...