text:
package ch.brickwork.bsuit.matcher;

import ch.brickwork.bsuit.database.Record;
import ch.brickwork.bsuit.database.Value;
import ch.brickwork.bsuit.database.Variable;
import ch.brickwork.bsuit.globals.IBoilersuitApplicationContext;
import ch.brickwork.bsuit.interpreter.DefaultCommandInterpreter;
import ch.brickwork.bsuit.interpreter.ScriptProcessor;
import ch.brickwork.bsuit.interpreter.interpreters.MatchInterpreter;
import ch.brickwork.bsuit.interpreter.interpreters.ProcessingResult;
import ch.brickwork.bsuit.util.Partition;
import ch.brickwork.bsuit.util.Partitioning;
import ch.brickwork.bsuit.util.TextUtils;
import net.ricecode.similarity.DiceCoefficientStrategy;
import net.ricecode.similarity.JaroStrategy;
import net.ricecode.similarity.JaroWinklerStrategy;
import java.util.*;

/**
 * Used in {@link MatchInterpreter} and takes care for whole process of matching.
 */
public class MagicMatcher {

    private static final int MAX_MATCH_BUFFER_RECORDS = 5000;

    private static final int PARTITION_SIZE = 10000;

    private static final double THRESHOLD = -1;

    private final String leftTableAttrPrefix;

    private final Variable leftVariable;

    private final IBoilersuitApplicationContext context;

    private final MatchArguments matchArguments;

    private final String rightTableAttrPrefix;

    private final Variable rightVariable;

    private final String targetTableName;

    private final String targetVariableName;

    private final List<String> temporaryTables = new ArrayList<>();

    /**
     * left attributes name -> exact match flag name for this attribute
     */
    private Hashtable<String, String> exactAttributeNameMap;

    /**
     * temporary solution - should be introduced as a matching option! if yes, means that once an exact match
     * is found, the corresponing right entry will be removed such that it is not available for other left items
     * to match with
     */
    private boolean greedyLeft = false;

    /**
     * temporary solution - should be introduced as a matching option! if false, means that once an exact match
     * is found, the corresponing left entry will not again be checked because it is already matching exactly. If it
     * is hungry, then even if we already have an exact match, it will further look out for inexact ones
     */
    private boolean hungryLeft = false;

    private boolean initialized = false;

    private String leftKeyAttributeNameTarget;

    private List<String> leftTableColumnNamesMatchRelevant;

    /**
     * writing matches
     */
    private List<Record> matchBuffer = null;

    private Hashtable<MatchOption, String> matchOptionAttributeNameMap;

    private String matchTemporaryIdentifier;

    private String reducedLeftSetName;

    private String reducedRightSetName;

    private String rightKeyAttributeNameTarget;

    private List<String> rightTableColumnNamesMatchRelevant;

    /**
     * match options
     */
    private boolean suppressSecondBest = false;

    private double threshold = THRESHOLD;

    /**
     * Invoked by {@link MatchInterpreter}
     *
     * @param leftVariable       left variable for matching
     * @param rightVariable      right variable for matching
     * @param matchArguments     arguments of match command
     * @param targetVariableName is name of target variable
     * @param targetTableName    is name of target table (mostly the same as target variable)
     * @param context                is a instance of logger
     */
    public MagicMatcher(final Variable leftVariable, final Variable rightVariable, final MatchArguments matchArguments,
                        final String targetVariableName, final String targetTableName, final IBoilersuitApplicationContext context)
    {
        this.leftVariable = leftVariable;
        this.rightVariable = rightVariable;
        this.matchArguments = matchArguments;
        this.targetTableName = targetTableName;
        this.targetVariableName = targetVariableName;
        this.context = context;
        leftTableAttrPrefix = leftVariable.getTableName() + "_";
        rightTableAttrPrefix = rightVariable.getTableName() + "_";
        init();
    }

    /**
     * Invoked by {@link MatchInterpreter}
     * Creates the sub results which have the fuzzy and the exact matching results.
     *
     * @return ProcessingResult
     */

    public ProcessingResult match()
    {
        final ProcessingResult processingResult = new ProcessingResult(ProcessingResult.ResultType.COMPOSITE, "Match result");

        if (!initialized) {
            return null;
        }

        processingResult.addSubResult(exactMatch());
        processingResult.addSubResult(fuzzyMatch());

        removeTemporaryTables();

        return processingResult;
    }

    /**
     * @param tableName            is name of table which will be created for match results
     * @param additionalAttributes is a list of names for additional attributes which will be added to created table
     */
    private void createMatchTable(final String tableName, final List<String> additionalAttributes)
    {
        context.getDatabase().dropIfExistsViewOrTable(tableName);
        context.getDatabase().createOrReplaceVariable(tableName, "Matching " + leftVariable.getVariableName() + " on " + rightVariable.getVariableName(), "");

        if (leftVariable.getTableName().equalsIgnoreCase(rightVariable.getTableName())) {
            return;
        }

        context.getDatabase().createCombinedTable(leftTableColumnNamesMatchRelevant, rightTableColumnNamesMatchRelevant, leftVariable.getVariableName(),
            rightVariable.getVariableName(), additionalAttributes, tableName);
    }

    /**
     * Prepare the temporary tables used in this process (and remove them after process is finished) and take care of all of steps of exact matching.
     *
     * @return ProcessingResult of exact matching.
     */

    private ProcessingResult exactMatch()
    {
        context.getLog().info("First, looking for exact matches (ignoring whitespaces, i.e. XY 123 will match X Y123 and XY123)...");

        // concatenate attribute names of left and right keys
        final String leftKeyConcatenation = TextUtils.serializeListWithDelimitator(matchArguments.getLeftAttributes(), "|| '_' ||", "replace(", ", ' ', '')");
        final String rightKeyConcatenation = TextUtils.serializeListWithDelimitator(matchArguments.getRightAttributes(), "|| '_' ||", "replace(", ", ' ', '')");

        // create view containing all attributes + the concatenated combined key (left)
        final String leftTempViewName = matchTemporaryIdentifier + "_left_all_plus_key";
        temporaryTables.add(leftTempViewName);
        final String leftTempKeyAttributeName = leftVariable.getVariableName() + "_match_key";
        context.getDatabase().dropIfExistsViewOrTable(leftTempViewName);
        final String leftAttributesConcatenationWithAlias = TextUtils.serializeListWithDelimitator(leftTableColumnNamesMatchRelevant, ", ", "",
            " as " + leftVariable.getTableName() + "_<item>");
        final String rightAttributesConcatenationWithAlias = TextUtils.serializeListWithDelimitator(rightTableColumnNamesMatchRelevant, ", ", "",
            " as " + rightVariable.getTableName() + "_<item>");
        final String leftAttributesConcatenation = TextUtils.serializeListWithDelimitator(leftTableColumnNamesMatchRelevant, ", ",
            leftVariable.getTableName() + "_", "");
        final String rightAttributesConcatenation = TextUtils.serializeListWithDelimitator(rightTableColumnNamesMatchRelevant, ", ",
            rightVariable.getTableName() + "_", "");

        String createLeftTempView = "CREATE TABLE " + leftTempViewName + " AS SELECT " + leftKeyConcatenation + " AS " + leftTempKeyAttributeName + ", "
            + leftAttributesConcatenationWithAlias + " FROM " + leftVariable.getVariableName() + " WHERE " + leftKeyConcatenation + " <> ''";
        final ProcessingResult pLeft = new DefaultCommandInterpreter(null, createLeftTempView, context).process();

        if (!(pLeft.getType() == ProcessingResult.ResultType.VIEW || pLeft.getType() == ProcessingResult.ResultType.TABLE)) {
            return new ProcessingResult(ProcessingResult.ResultType.FATAL_ERROR, "Trouble creating left hand table for exact match!");
        }
        context.getDatabase().createIndex(leftTempViewName, leftTempKeyAttributeName, leftTempViewName + "_" + leftTempKeyAttributeName + "_index");

        // create view containing all attributes + the concatenated combined key (right)
        final String rightTempViewName = matchTemporaryIdentifier + "_right_all_plus_key";
        temporaryTables.add(rightTempViewName);
        final String rightTempKeyAttributeName = rightVariable.getVariableName() + "_match_key";
        context.getDatabase().dropIfExistsViewOrTable(rightTempViewName);
        final String createRightTempView =
            "CREATE TABLE " + rightTempViewName + " AS SELECT " + rightKeyConcatenation + " AS " + rightTempKeyAttributeName + ", "
                + rightAttributesConcatenationWithAlias + " FROM " + rightVariable.getVariableName() + " WHERE " + rightKeyConcatenation + " <> ''";
        final ProcessingResult pRight = new DefaultCommandInterpreter(null, createRightTempView, context).process();
        if (!(pRight.getType() == ProcessingResult.ResultType.VIEW || pRight.getType() == ProcessingResult.ResultType.TABLE)) {
            return new ProcessingResult(ProcessingResult.ResultType.FATAL_ERROR, "Trouble creating right hand table for exact match!");
        }
        context.getDatabase().createIndex(rightTempViewName, rightTempKeyAttributeName, rightTempViewName + "_" + rightTempKeyAttributeName + "_index");

        // create inner join to see which ones are exactly matching
        final String leftAlias = matchTemporaryIdentifier + "_left_alias";
        final String rightAlias = matchTemporaryIdentifier + "_right_alias";

        final String innerJoin =
            "CREATE TABLE " + getExactMatchesTableName() + " AS SELECT " + leftAttributesConcatenation + ", " + rightAttributesConcatenation + ", " +
                leftTempKeyAttributeName + ", " + rightTempKeyAttributeName + " FROM " + leftTempViewName + " " + leftAlias + " INNER JOIN " + rightTempViewName
                + " " + rightAlias + " ON " + leftAlias + "." + leftTempKeyAttributeName + "=" + rightAlias + "." + rightTempKeyAttributeName;
        final ProcessingResult pJoin = new ScriptProcessor().processScript(getExactMatchesTableName() + ":=" + innerJoin, null, null);
        if (!(pJoin.getType() == ProcessingResult.ResultType.TABLE || pJoin.getType() == ProcessingResult.ResultType.VIEW)) {
            return new ProcessingResult(ProcessingResult.ResultType.FATAL_ERROR, "Trouble creating inner join for exact match!");
        }

        final String joinResultTable = pJoin.getResultSummary();
        context.getLog().log("Join Result in : " + joinResultTable);

        context.getLog().log("Exact matches: " + context.getDatabase().count(joinResultTable) + " of " + context.getDatabase().count(leftVariable.getTableName()));

        context.getDatabase().dropIfExistsViewOrTable(matchTemporaryIdentifier + "_reduced_left");
        context.getDatabase().dropIfExistsViewOrTable(matchTemporaryIdentifier + "_reduced_right");
        final String reducedLeftTableName = matchTemporaryIdentifier + "_reduced_left";
        temporaryTables.add(reducedLeftTableName);
        String reducedLeftSQL =
            "CREATE TABLE " + reducedLeftTableName + " AS SELECT " + leftAttributesConcatenationWithAlias + " FROM " + leftVariable.getTableName();
        if (!hungryLeft) {
            reducedLeftSQL += " WHERE " + leftKeyConcatenation + " NOT IN (SELECT " + leftTempKeyAttributeName + " FROM " + getExactMatchesTableName() + ")";
        }
        final ProcessingResult reducedLeftSet = new DefaultCommandInterpreter(null, reducedLeftSQL, context).process();
        final String reducedRightTableName = matchTemporaryIdentifier + "_reduced_right";
        temporaryTables.add(reducedRightTableName);
        String reducedRightSQL =
            "CREATE TABLE " + reducedRightTableName + " AS SELECT " + rightAttributesConcatenationWithAlias + " FROM " + rightVariable.getTableName();
        if (greedyLeft) {
            reducedRightSQL += " WHERE " + rightKeyConcatenation + " NOT IN (SELECT " + rightTempKeyAttributeName + " FROM " + getExactMatchesTableName() + ")";
        }
        final ProcessingResult reducedRightSet = new DefaultCommandInterpreter(null, reducedRightSQL, context).process();
        if (reducedLeftSet.getType() == ProcessingResult.ResultType.TABLE && reducedRightSet.getType() == ProcessingResult.ResultType.TABLE) {
            reducedLeftSetName = reducedLeftSet.getResultSummary();
            reducedRightSetName = reducedRightSet.getResultSummary();
        } else {
            reducedLeftSetName = null;
            reducedRightSetName = null;
            context.getLog().err("Error in creating reduced sets in exact matching!");
        }

        return new ProcessingResult(ProcessingResult.ResultType.VIEW, joinResultTable);
    }

    /**
     * Check if two records are equal, but without case-sensitive
     *
     * @param additionalAttributes list of attributes which will be added to the results table
     */
    private void findExactMatches(List<String> additionalAttributes)
    {
        for (int i = 0; i < matchArguments.getLeftAttributes().size(); i++) {
            final String leftName = matchArguments.getLeftAttributes().get(i);
            final String rightName = matchArguments.getRightAttributes().get(i);

            // if the have the same name X, the exact match flag will be called exact_X,
            // otherwise exact_X_Y
            String exactMatchName = "match_exact_" + leftName.trim();
            if (!leftName.trim().equalsIgnoreCase(rightName.trim())) {
                exactMatchName += "_" + rightName.trim();
            }

            additionalAttributes.add(exactMatchName);
            exactAttributeNameMap.put(leftTableAttrPrefix + leftName, exactMatchName);
        }
    }

    /**
     * Insert records to the database and clear buffer.
     */
    private void flushMatchBuffer()
    {
        context.getDatabase().insert(getFuzzyMatchesTableName(), matchBuffer);

        // empty buffer
        matchBuffer = new ArrayList<>();
    }

    /**
     * @return ProcessingResult of fuzzy matching
     */

    private ProcessingResult fuzzyMatch()
    {
        long lastRecordStartedTimestamp = System.currentTimeMillis();

        final Partitioning leftPartitioning = new Partitioning(context.getDatabase().count(reducedLeftSetName), PARTITION_SIZE);
        final Partitioning rightPartitioning = new Partitioning(context.getDatabase().count(reducedRightSetName), PARTITION_SIZE);

        context.getLog().log("Left  Partition with " + leftPartitioning.countElements() + " elements");
        context.getLog().log("Right Partition with " + rightPartitioning.countElements() + " elements");

        context.getLog().info("Left set will be divided into " + (leftPartitioning.countPartitions()) + " partitions to avoid memory problems.");
        context.getLog().info("Right set will be divided into " + (rightPartitioning.countPartitions()) + " partitions to avoid memory problems.");

        for (final Partition leftP : leftPartitioning) {
            // get left partition

            // process right partitions against this left one
            for (final Partition rightP : rightPartitioning) {

                // update performance calculation
                final long msecPerRightPartition = System.currentTimeMillis() - lastRecordStartedTimestamp;
                final long msecRemaining = msecPerRightPartition * (leftPartitioning.countPartitions() * rightPartitioning.countPartitions()
                    - leftP.getNumber() * rightPartitioning.countPartitions() - rightP.getNumber());
                final int seconds = (int) (msecRemaining / 1000) % 60;
                final int minutes = (int) ((msecRemaining / (1000 * 60)) % 60);
                final int hours = (int) ((msecRemaining / (1000 * 60 * 60)) % 24);

                final String message =
                    "Remaining " + hours + ":" + minutes + ":" + seconds + " (at " + (double) (msecPerRightPartition / 1000) + " sec per right partition)";

                lastRecordStartedTimestamp = System.currentTimeMillis();

                final String statusString =
                    "[" + (leftP.getFirstRecord() + 1 + "" + (leftP.getFirstRecord() + leftP.getLength())) + " of " + leftPartitioning.countElements() + "] ("
                        + (leftP.getNumber() + 1) + "/" + leftPartitioning.countPartitions() + ")" + " vs. " + "[" + (rightP.getFirstRecord() + 1 + "" + (
                        rightP.getFirstRecord() + rightP.getLength())) + " from " + rightPartitioning.countElements() + "] (" + (rightP.getNumber() + 1) + "/"
                        + rightPartitioning.countPartitions() + "). " + message;

                context.getLog().info(statusString);

                final List<Record> left = context.getDatabase().getAllRecordsFromTableOrView(reducedLeftSetName, leftP.getFirstRecord(), leftP.getLength(), null, null);
                final List<Record> right = context.getDatabase().getAllRecordsFromTableOrView(reducedRightSetName, rightP.getFirstRecord(), rightP.getLength(), null, null);

                if (null != left && null != right) {
                    match(left, right);
                }
            }
        }
        return new ProcessingResult(ProcessingResult.ResultType.TABLE, getFuzzyMatchesTableName());
    }

    private String getExactMatchesTableName()
    {
        return targetTableName + "_exact_matches";
    }

    private String getFuzzyMatchesTableName()
    {
        return targetTableName + "_fuzzy_matches";
    }

    private void init()
    {
        threshold = THRESHOLD;
        matchTemporaryIdentifier = targetTableName;
        initialized = prepareResultsTable();
    }

    /**
     * Prepare (calculate the values for different matching strategies) records for fuzzy matching table
     * and call a function that will take care of saving them to a right table.
     *
     * @param allLeft  all records from left table
     * @param allRight all records from right table
     */
    private void match(final List<Record> allLeft, final List<Record> allRight)
    {
        if (!initialized) {
            return;
        }

        for (final Record leftRecord : allLeft) {

            final MatchSet matches = new MatchSet();

            for (final Record rightRecord : allRight) {
                matchRightRecord(leftRecord, matches, rightRecord);
            }

            boolean hadExactMatches = false;
            for (final Match exactMatch : matches.getExactMatches()) {
                hadExactMatches = true;
                writeMatchTable(exactMatch);
            }

            if (!hadExactMatches) {
                if (suppressSecondBest) {
                    // write best, if any:
                    if (matches.getBestNonExactMatch() != null) {
                        writeMatchTable(matches.getBestNonExactMatch());
                    }
                } else {
                    // write all
                    for (final Match nonExactMatch : matches.getNonExactMatches(threshold)) {
                        // record as match (exact matches are all reported, inexact
                        // matches
                        writeMatchTable(nonExactMatch);
                    }
                }
            }
        }

        // write any residual matches out of buffer by flushing:
        if (matchBuffer != null) {
            flushMatchBuffer();
        }
    }

    /**
     * Uses different strategies to compare two records and calculate the match score
     *
     * @param leftRecord  record from the left table
     * @param matches     set of non exact matches
     * @param rightRecord record from the right table
     */
    private void matchRightRecord(Record leftRecord, MatchSet matches, Record rightRecord)
    {
        final Match thisMatch = new Match(leftRecord, rightRecord);
        matches.addMatch(thisMatch);

        // exact match
        boolean first = true;
        final StringBuilder leftCombinedKey = new StringBuilder();
        final StringBuilder rightCombinedKey = new StringBuilder();
        for (int i = 0; i < matchArguments.getLeftAttributes().size(); i++) {

            final String checkLeftAttribute = leftTableAttrPrefix + matchArguments.getLeftAttributes().get(i);

            // if same number of left and right attributes, test exact match:
            if (matchArguments.getLeftAttributes().size() == matchArguments.getRightAttributes().size()) {

                String againstRightAttribute = rightTableAttrPrefix + matchArguments.getRightAttributes().get(i);
                thisMatch.setPartialExactMatch(exactAttributeNameMap.get(checkLeftAttribute),
                    ((String) leftRecord.getValue(checkLeftAttribute).getValue()).trim()
                        .equals(((String) rightRecord.getValue(againstRightAttribute).getValue()).trim()));
            }

            if (first) {
                first = false;
            } else {
                leftCombinedKey.append("*");
            }

            leftCombinedKey.append(((String) leftRecord.getValue(checkLeftAttribute).getValue()).trim());
        }

        first = true;
        for (int i = 0; i < matchArguments.getRightAttributes().size(); i++) {
            final String againstRightAttribute = rightTableAttrPrefix + matchArguments.getRightAttributes().get(i);
            rightCombinedKey.append(((String) rightRecord.getValue(againstRightAttribute).getValue()).trim());
            rightCombinedKey.append("*");
            if (first) {
                first = false;
            } else {
                leftCombinedKey.append("*");
                rightCombinedKey.append("*");
            }
        }

        thisMatch.setLeftKey(leftCombinedKey.toString());
        thisMatch.setRightKey(rightCombinedKey.toString());

        if (!thisMatch.isExact()) {
            // check imprecise matches
            final JaroStrategy jaro = new JaroStrategy();
            final JaroWinklerStrategy jaroWinkler = new JaroWinklerStrategy();
            final DiceCoefficientStrategy diceCo = new DiceCoefficientStrategy();

            // left key
            final StringBuilder leftKey = new StringBuilder();
            first = true;
            for (String leftKeyComponent : matchArguments.getLeftAttributes()) {
                if (first) {
                    first = false;
                } else {
                    leftKey.append("*");
                }

                leftKey.append(leftRecord.getValue(leftTableAttrPrefix + leftKeyComponent).getValue());
            }

            // right key
            final StringBuilder rightKey = new StringBuilder();
            first = true;
            for (String rightKeyComponent : matchArguments.getRightAttributes()) {
                if (first) {
                    first = false;
                } else {
                    rightKey.append("*");
                }

                rightKey.append(rightRecord.getValue(rightTableAttrPrefix + rightKeyComponent).getValue());
            }

            thisMatch.setJaroScore(jaro.score(leftKey.toString(), rightKey.toString()));

            thisMatch.setJaroWinklerScore(jaroWinkler.score(leftKey.toString(), rightKey.toString()));

            thisMatch.setDiceScore(diceCo.score(leftKey.toString(), rightKey.toString()));

            // process WITH clauses
            for (final MatchOption matchOption : matchArguments.getOptions()) {

                final Hashtable<String, Object> arguments = matchOption.getArguments();
                    // LEGASTODETECT
                    if (matchOption.getType() == MatchOption.OPT_LEGASTODETECT) {
                        if(arguments == null) {
                            context.getLog().warn("LEGASTODETECT without arguments!");
                            return;
                        }

                        final Iterator<String> it = arguments.keySet().iterator();
                        final String firstSwapAttribute = it.next();
                        final String secondSwapAttribute = it.next();

                        // generate alternative left key, where the
                        // legasthenic keys are swapped:
                        final StringBuilder alternativeLeftKey = new StringBuilder();
                        first = true;
                        for (final String leftKeyComponent : matchArguments.getLeftAttributes()) {
                            if (first) {
                                first = false;
                            } else {
                                alternativeLeftKey.append("*");
                            }

                            if (leftKeyComponent.equals(firstSwapAttribute)) {
                                alternativeLeftKey.append(leftRecord.getValue(secondSwapAttribute).getValue());
                            } else if (leftKeyComponent.equals(secondSwapAttribute)) {
                                alternativeLeftKey.append(leftRecord.getValue(firstSwapAttribute).getValue());
                            } else {
                                alternativeLeftKey.append(leftRecord.getValue(leftKeyComponent).getValue());
                            }
                        }

                        if (alternativeLeftKey.toString().trim().equals(rightKey.toString().trim())) {
                            thisMatch.addLegasthenicMatch(this.matchOptionAttributeNameMap.get(matchOption));
                        }
                    }

                    // SUPPRESSSECONDBESTMATCHES
                    if (matchOption.getType() == MatchOption.OPT_SUPPRESSSECONDBEST) {
                        suppressSecondBest = true;
                    }

                    // THRESHOLD
                    if (matchOption.getType() == MatchOption.OPT_THRESHOLD) {
                        if(arguments == null) {
                            context.getLog().warn("THRESHOLD without arguments!");
                            return;
                        }

                        final Object thresholdObj = arguments.get("threshold");
                        if (null != thresholdObj) {
                            threshold = new Double(thresholdObj.toString());
                        }
                    }

            }
        }
    }

    /**
     * @param additionalAttributes list of attributes which will be added to the match results table
     * @param matchOption          object contains additional matching options e.g. THRESHOLD(0.9)
     */
    private void prepareLegastAttributes(List<String> additionalAttributes, MatchOption matchOption)
    {
        if (matchOption.getType() == MatchOption.OPT_LEGASTODETECT) {
            final StringBuilder legastResultAttributeName = new StringBuilder("swap_");
            boolean first = true;
            final Set<String> argumentKeys = matchOption.getArgumentKeys();
            if (null != argumentKeys) {
                for (String argumentKey : argumentKeys) {
                    if (first) {
                        first = false;
                    } else {
                        legastResultAttributeName.append("_");
                    }

                    legastResultAttributeName.append(argumentKey);
                }
            }
            legastResultAttributeName.append("_to_match");
            additionalAttributes.add(legastResultAttributeName.toString());
            matchOptionAttributeNameMap.put(matchOption, legastResultAttributeName.toString());
        }
    }

    /**
     * @param additionalAttributes list of attributes which will be added to the results table
     */
    private void prepareMatchKeys(List<String> additionalAttributes)
    {
        String leftKeyAttributeNameSource;
        String rightKeyAttributeNameSource;
        if (matchArguments.getLeftAttributes().size() > 1) {
            leftKeyAttributeNameTarget = leftVariable.getVariableName() + "_key";
            rightKeyAttributeNameTarget = rightVariable.getVariableName() + "_key";
            leftKeyAttributeNameSource = null;
            rightKeyAttributeNameSource = null;
        } else {
            leftKeyAttributeNameSource = matchArguments.getLeftAttributes().get(0);
            rightKeyAttributeNameSource = matchArguments.getRightAttributes().get(0);
            leftKeyAttributeNameTarget = leftVariable.getVariableName() + "_" + leftKeyAttributeNameSource;
            rightKeyAttributeNameTarget = rightVariable.getVariableName() + "_" + rightKeyAttributeNameSource;
        }
        final Hashtable<String, Integer> leftColumnNamesHash = context.getDatabase().getTableOrViewColumnNamesHash(leftVariable.getTableName());
        if (null != leftColumnNamesHash && ((leftKeyAttributeNameSource != null && leftColumnNamesHash.get(leftKeyAttributeNameSource) == null) || (
            leftKeyAttributeNameSource == null && leftColumnNamesHash.get("key") == null))) {
            additionalAttributes.add(leftKeyAttributeNameTarget);
        } else {
            context.getLog().warn("Overwriting existing attribute " + leftKeyAttributeNameTarget);
        }
        final Hashtable<String, Integer> rightColumnNamesHash = context.getDatabase().getTableOrViewColumnNamesHash(rightVariable.getTableName());
        if (null != rightColumnNamesHash && ((rightKeyAttributeNameSource != null && rightColumnNamesHash.get(rightKeyAttributeNameSource) == null) || (
            rightKeyAttributeNameSource == null && rightColumnNamesHash.get("key") == null))) {
            additionalAttributes.add(rightKeyAttributeNameTarget);
        } else {
            context.getLog().warn("Overwriting existing attribute " + rightKeyAttributeNameTarget);
        }
    }

    /**
     * Prepare the table contains fuzzy matching.
     *
     * @return true if results table was created
     */
    private boolean prepareResultsTable()
    {
        exactAttributeNameMap = new Hashtable<>();
        matchOptionAttributeNameMap = new Hashtable<>();

        /**
         * Create matching keys (if they are created based on more than one
         * component, then
         * there are additional; if the user indicates one specific attribute
         * set to be
         * used as match attributes, they are not additional (then they already
         * exist as normal attributes)
         */
        final List<String> additionalAttributes = new ArrayList<>();

        leftTableColumnNamesMatchRelevant = context.getDatabase().getSanitizedTableOrViewColumnNames(leftVariable.getTableName());
        removeNonRelevantAttributes(leftTableColumnNamesMatchRelevant, true);
        rightTableColumnNamesMatchRelevant = context.getDatabase().getSanitizedTableOrViewColumnNames(rightVariable.getTableName());
        removeNonRelevantAttributes(rightTableColumnNamesMatchRelevant, false);

        if (null == leftTableColumnNamesMatchRelevant || null == rightTableColumnNamesMatchRelevant) {
            context.getLog().err("Left or right column names are empty!");
            return false;
        }

        // create standard match attributes
        additionalAttributes.add("match_exact");
        additionalAttributes.add("match_dice");
        additionalAttributes.add("match_jaro");
        additionalAttributes.add("match_jarowinkler");

        // if same number of arguments on left and right side, track exact matches
        if (matchArguments.getLeftAttributes().size() == matchArguments.getRightAttributes().size()) {
            findExactMatches(additionalAttributes);
        }

        // additional match attributes depending on the options
        for (final MatchOption matchOption : matchArguments.getOptions()) {
            prepareLegastAttributes(additionalAttributes, matchOption);
        }

        if (matchArguments.getRightAttributes().size() == matchArguments.getLeftAttributes().size()) {
            prepareMatchKeys(additionalAttributes);
        }

        // create tables
        createMatchTable(getFuzzyMatchesTableName(), additionalAttributes);

        return true;
    }

    /**
     * Method remove attributes non relevant for match for given List of attribute names.
     *
     * @param tableColumnNames table attributes
     *
     * @return attributes non relevant for match
     */

    private List<String> removeNonRelevantAttributes(final List<String> tableColumnNames, final boolean left)
    {
        final Iterator<String> iterator = tableColumnNames.iterator();
        final List<String> nonRelevantAttributes = new ArrayList<>();
        final MatchOption displayLeftOption = matchArguments.getOption(MatchOption.OPT_DISPLAYLEFT);
        final MatchOption displayRightOption = matchArguments.getOption(MatchOption.OPT_DISPLAYRIGHT);
        while (iterator.hasNext()) {
            String columnName = iterator.next();

            // assume this is not relevant
            boolean isRelevant = false;

            // try to falsify above hypothesis by making isRelevant true
            isRelevant |= left && matchArguments.getLeftAttributes().contains(columnName);
            isRelevant |= !left && matchArguments.getRightAttributes().contains(columnName);
            isRelevant |= left && null != displayLeftOption && null != displayLeftOption.getArguments().get(columnName);
            isRelevant |= left && null != displayLeftOption && null != displayLeftOption.getArguments().get("*");
            isRelevant |= !left && null != displayRightOption && null != displayRightOption.getArguments().get(columnName);
            isRelevant |= !left && null != displayRightOption && null != displayRightOption.getArguments().get("*");

            if (!isRelevant) {
                nonRelevantAttributes.add(columnName);
                iterator.remove();
            }
        }
        return nonRelevantAttributes;
    }

    /**
     * Remove the tables which are not used after processing is finished and not contain any important information.
     */
    private void removeTemporaryTables()
    {
        for (String tableName : temporaryTables) {
            context.getDatabase().dropIfExistsViewOrTable(tableName);
        }
    }

    /**
     * Write the match records to match tables creating during whole process.
     *
     * @param match records
     */
    private void writeMatchTable(final Match match)
    {
        final Record record = new Record();

        for (final Value leftValue : match.getLeftRecord()) {
            final String newKey = context.getDatabase().sanitizeName(leftValue.getAttributeName());
            record.put(newKey, leftValue.getValue());
        }
        for (final Value rightValue : match.getRightRecord()) {
            final String newKey = context.getDatabase().sanitizeName(rightValue.getAttributeName());
            record.put(newKey, rightValue.getValue());
        }

        // match keys (if not there already)
        if (!record.hasAttribute(leftKeyAttributeNameTarget)) {
            record.put(leftKeyAttributeNameTarget, match.getLeftKey());
        }

        if (!record.hasAttribute(rightKeyAttributeNameTarget)) {
            record.put(rightKeyAttributeNameTarget, match.getRightKey());
        }

        // partial exact matches
        for (final String partialExactKey : match.getPartialExactKeys()) {
            record.put(partialExactKey, match.isPartialExactMatch(partialExactKey) ? "yes" : "no");
        }

        // inexact matches
        record.put("match_exact", match.isExact() ? "yes" : "no");
        record.put("match_jaro", match.getJaroScore());
        record.put("match_jarowinkler", match.getJaroWinklerScore());
        record.put("match_dice", match.getDiceScore());

        // legasthenic
        for (final MatchOption mo : matchArguments.getOptions()) {
            if (mo.getType() == MatchOption.OPT_LEGASTODETECT) {
                final String legaAttr = matchOptionAttributeNameMap.get(mo);
                if (match.getLegasthenicMatches().get(legaAttr) != null) {
                    // redundant but safer if decided to do the Boolean hash
                    // better in match in future (currently, we only have TRUE
                    // entries there)
                    if (match.getLegasthenicMatches().get(legaAttr)) {
                        record.put(legaAttr, "yes");
                    }
                } else {
                    record.put(legaAttr, "no");
                }
            }
        }

        // add record to buffer (init if necessary)
        if (matchBuffer == null) {
            matchBuffer = new ArrayList<>();
        }
        matchBuffer.add(record);

        // empty buffer from time to time
        if (matchBuffer.size() > MAX_MATCH_BUFFER_RECORDS) {
            flushMatchBuffer();
        }
    }
}


We are committed to delivering the highest quality custom jersey product available on the market. From eye-popping colors, to All-American sourcing, to maximum protection for your skin, here's how we do it.
You might say our jerseys are cut from the same cloth.
Our apparel is produced using a process called Dye Sublimation. Most pieces start as a single large piece of cloth that is then dyed using an ultra high temperature heat press. Smaller pieces — like sleeves, collars, fronts, & backs — are cut from that large piece, hemmed, and hand-sewn together to become the finished product. And because your design is dyed into the fabric itself, it will never crack, peel, or fade the way other screen-printed designs do.
Our durable polyester knits offer superior moisture-wicking and mesh paneling to keep you cool and dry no matter the weather. Our fabrics are also anti-microbial to keep you smelling fresh, no matter the catch, and provide +50 UV protection to keep you safe in the sun.
Every seam of our products is double stitched by hand, right here in Indiana, to ensure a jersey or hoodie that will never fall apart in the wash.


text:
Bulbophyllum verruciferum är en orkidéart som beskrevs av Rudolf Schlechter. Bulbophyllum verruciferum ingår i släktet Bulbophyllum och familjen orkidéer.

Underarter

Arten delas in i följande underarter:

 B. v. carinatisepalum
 B. v. verruciferum

Källor

Orkidéer
verruciferum

redpajama_set_name: RedPajamaWikipedia


Since ever, the human race had been curious about its planet composition and structure. The earliest signs of this process come back as far as to the Stone Age.
In 1930s Acad. Vladimir I. Vernadsky was the first scientist to suggest that Hydrogen had played a fundamental role in chemical processes taking place within our planet internals – and the entire Solar System as well.
In 1950s astronomer Fred Hoyle suggested that at the time of the Solar System formation, the matter was in the form of plasma. It formed a rotating disk having its own magnetic field.
In 1968 for the first time in history of science, the Soviet scientist Vladimir N. Larin determined the patterns of chemical elements' distribution in the Solar System.
Upon analyzing the results of chemical elements' distribution across the Solar system, Dr. Larin concluded that it had proved to have been dependant on their ionization potentials values. Therefore, the matter was spread around the Solar system based on its ability to pass through the magnetic field of the Proto-Sun. Based on this assumption, the elements with lower ionization potentials (IP) remained closer to the system center, while those with higher IP would have to be spread farther, without being caught by electric magnetic "screen".
It's quite remarkable that with the new concept development, the paradoxes of modern geology accumulated through centuries have been resolved. Dr. Larin published 5 books and dozens of articles describing the new hypothesis particulars. All scientific predictions made by Dr. Larin have been confirmed.
One of the most valuable consequences from Dr. Larin's concept is the suggestion that below the Earth crust and mantle, our planet is formed by Oxygen-free material and Si, Mg, and Fe-based alloys.
However, there are areas on Earth where the crust is very thin and the mantle material tongues a.k.a. diapirs approach the day surface very close.
In early 1970s, Dr. Larin's postulates have been enthusiastically supported by the Soviet astrophysicist Dr. Joseph S. Schklovsky, then Associate Member of the Soviet Academy of Science. He reviewed the summary of what Dr. Larin had done to that moment, and confirmed the concept compliance with basic laws of astronomy and physics.
Abnormal plasticity of metals saturated with Hydrogen under pressure had been studied at the Institute of Metals Physics (then city of Sverdlovsk, the Urals Division of the USSR Acad. Sci.). Samples for these tests were prepared at the Institute of Inorganic Chemistry USSR Acad. Sci. and the Institute of Solid State Physics USSR Acad. Sci. As a result of this work, the Soviet patent had been applied for and granted.
Seismic wave velocity in tested samples benchmarking have been done at the Institute of Earth Physics (Moscow, Russia) IPE USSR Acad. Sci.


text:
9/11/2021	September 11, 2021	 - 10/9/2021	October 9, 2021
September 11, 2021 @ 10:30 am - 12:00 pm
Art Detectives: The Quiet Place
Do you have a special place where you can enjoy the quiet? Arty Mouse will read The Quiet Place by author Sarah Stewart and illustrator David Small, a book about…
The Whole Picture: The Colonial Story of the Art in Our Museums & Why We Need to Talk about It by: Alice Procter If you think art history has to…
Transforming Art with Digital Technology
Ginny Ruffner is pursuing the challenge of making a new beauty through the process of personal reflection and asking questions. She will show her pursuit of this challenge through projects…
Ginny Ruffner: Tour & Reception, Members-Only
The KIA Board of Directors invites you to join them for a reality-bending presentation of Ginny Ruffner's complex fusion of fine glass blowing, augmented reality, and drawing. The event is…
September 18, 2021 @ 8:00 am - December 5, 2021 @ 5:00 pm
Ginny Ruffner: Reforestation of the Imagination
Ginny Ruffner: Reforestation of the Imagination is a unique installation that fuses fine glass blowing, augmented reality (AR), and drawing. For this special presentation, Ruffner and her collaborators developed an…
ARTbreak: Illustrating the Natural World
Olivia Mendoza creates illustrative work based on the natural world, focusing on the details of botanicals, insects, animal life and anatomy. She will be discussing what inspires her personal incentive…
Usher in new board members and hear directly from KIA senior staff and the board of directors. All current members are invited to attend. Be sure your mailing address is…
September 25, 2021 @ 8:00 am - January 2, 2022 @ 5:00 pm
Todd Gray: Crossing the Waters of Space, Time and History
Featuring the artist's signature style of found frames and stacked images from his private archive, Todd Gray: Crossing the Waters of Space, Time, and History considers the impacts of colonialism…
WomanUp & Celebrate Executive Director Belinda Tate
Michigan Woman Forward, a public statewide foundation devoted to the economic and personal well-being of Michigan women and girls, is honoring the KIA's Executive Director Belinda Tate as a 2021…
October 1, 2021 @ 8:00 am - October 31, 2021 @ 5:00 pm
Members Exchange
314 S Park St, Kalamazoo, MI
The Southwest Michigan Cultural Membership Exchange is a partnership with the Air Zoo, Binder Park Zoo, Gilmore Car Museum, Kalamazoo Nature Center, Kellogg Bird Sanctuary and Manor House and the…
October 5, 2021 @ 12:00 pm - 1:00 pm
ARTbreak: Visual Thinking Strategies
"What is going on in this picture? What do you see that makes you say that? What more can we find?" These three questions form the backbone of Visual Thinking…
October 9, 2021 @ 10:30 am - 12:00 pm
Art Detectives: Have You Ever Seen a Flower?
Have you ever seen a flower? I mean, really seen a flower? That's the question Arty Mouse will be asking the Art Detectives this month! Come to the KIA to…

redpajama_set_name: RedPajamaCommonCrawl


As the only indoor Paintball facility in the region, we utilizes special rubber balls called Reballs - NO MESS!! Come shoot your friends without the mess on Fridays from 4 - 9 pm. We offer healthy, positive adrenaline for the whole family. We play 4-on-4, rotating everyone in as fairly as possible, trying to keep experienced players together and inexperienced players together, so everyone has fun.


text:
Julia M Gossard
Julia M Gossard is Assistant Professor of History at Utah State University, specializing in early modern European and Atlantic history with an emphasis on gender, family, and childhood. She is a graduate of the University of Texas at Austin, and was a postdoctoral fellow with the Institute for Historical Studies before joining the faculty at Utah State. With funding from the American Historical Association, the Newberry Library, the Society for French Historical Studies, and the American Society of Eighteenth-Century Studies, Dr. Gossard wrote her first book, Coercing Children: State-Building and Social Reform in the Early Modern French World, which is under contract with McGill-Queen's University Press. Her articles on public history have appeared in Age of Revolutions Blog, Notches, and AHA Today's Teaching with #DigHist.
Episode 103: French Child Ambassadors in the East
Episode 96: Louis XIV's Absolutism and the "Affair of the Poisons"


text:
Current Mayor Bill de Blasio cannot run for a third term.
By Adam Shaw | Fox News
Fox News Flash top headlines for January 14
Fox News Flash top headlines are here. Check out what's clicking on Foxnews.com.
Former 2020 Democratic presidential hopeful Andrew Yang on Thursday launched his New York City mayoral campaign -- hoping to replace outgoing Bill de Blasio with an audacious pitch for a universal basic income as a headline policy.
"I'm running for mayor for a very simple reason -- I see a crisis and believe I can help," he said, citing the COVID crisis as well as high unemployment in the Big Apple.
ANDREW YANG ANNOUNCED NEW YORK CITY MAYORAL BID
Yang spoke in Morningside Heights on the Upper West Side of Manhattan after announcing his campaign on Wednesday evening.
"We need bold ideas and fresh ideas to revive our city," he said. "We need to look forward and adapt to economic challenges of today and the future. We also need a city government focused on competence and delivering for our people every day."
He called on the city to move away from political blame games: "When in reality, the people have been losing and it is tearing our city apart."
Yang could stake out a relatively moderate candidacy in a field of left-wing Democratic hopefuls. He described his platform as "a positive vision for New York City and a rational, progressive plan to implement it and make it a reality."
He is widely seen as an early frontrunner and has been surrounded by speculation and interest since he filed paperwork last month.
If his bid succeeds, he would replace the left-wing de Blasio, who cannot run for a third team. De Blasio has been dueling with Gov. Andrew Cuomo over the response to the COVID-19 pandemic.
NYC MAYORAL HOPEFUL ANDREW YANG FACES BLOWBACK AFTER COMPLAINING ABOUT CITY'S SMALL APARTMENTS
Hizzoner won plaudits from the left for the implementation of the universal pre-K program but has had his 2020 consumed with the battles of the pandemic and getting schools to reopen, as well as increased crime.
Yang, 46, was born in Schenectady, New York, and his parents are immigrants from Taiwan. He moved to the Big Apple when he was 21. In the 2020 primary, he touted his background in tech startup and gained a passionate following from supporters who became known as the "Yang Gang."
His universal basic income proved popular among Democrats, and it caught on with other candidates in the field -- reemerging amid questions of how to stimulate the economy in the COVID-era.
He has called for it again in NYC, calling it "the largest basic income program in the history of the country."
Yang's policy for New York City would begin by giving those classed as living in "extreme poverty" about $2,000 a year.
"This program can then be grown over time as it receives more funding from public and philanthropic organizations, with the vision of eventually ending poverty in New York City altogether," he says on his campaign website.
Illegal immigrants would be eligible for the program, while it would not replace current forms of welfare. He has separately proposed a People's Bank of New York City.
He is likely to face a packed roster of Democratic challengers ahead of the June Democratic primary. Other early mayoral candidates include New York City Comptroller Scott Stringer and Brooklyn Borough President Eric Adams.
Whoever wins the primary will likely be the favorite against any Republican challenger in the overwhelmingly Democratic city.
Yang took hits from primary rivals after he told The New York Times that he had decided to relocate because of cramped conditions in his two-bedroom apartment. Detractors pointed out that New York City residents have contended with the same scenario for months, often in apartments smaller than his. But Yang brushed off the criticism.
"Every New York parent has struggled with educating our children in a time of COVID. I've been proud to live, work and raise my kids in this city for 25 years," Yang said in response to the criticism. "After COVID shut down our public schools, we took our two kids, including my autistic son, to upstate New York to help him adapt to our new normal."
On the pandemic, he is prioritizing a push for New York City to reopen, noting the damage the lockdowns have done to the economy. He has called for reopening schools and businesses but has also emphasized reopening the "fun" side of the city.
"New York City needs to be the first major City to reopen, and that means reopening everything that makes us who we are," he says on his campaign website. "Our restaurants, our playhouses, our parks, our events - we've sacrificed for the common good, and we deserve to make New York City fun again."
He's also called for the "biggest post-COVID celebration" in the world and for to-go cocktails to be made a permanent fixture -- noting their popularity in lockdown New York -- as well as legalization of marijuana.
Fox News' Thomas Barrabi contributed to this report.
Adam Shaw is a reporter covering U.S. and European politics for Fox News. He can be reached at adam.shaw@foxnews.com.
Manchin says 14th Amendment ouster should be 'consideration' for Sens. Hawley, Cruz
Bill Maher defends Trump supporters: Let's not confuse '5,000' Capitol rioters with '74 million' voters
Critics dunk on Pennsylvania Lt. gov for claiming 'lies' about 2020 election 'not protected speech'


text:
(function () {
	'use strict';
	var fs;
	var path;
	var CoffeeScript;

	var	ECT = function (options) {
		if (!(this instanceof ECT)) {
			return new ECT(options);
		}

		if (options == null) {
			options = {};
		}

		this.options = {
			open : '<%',
			close : '%>',
			ext : '',
			cache : true,
			watch : false,
			root : ''
		};

		if (options.debugLines == null) {
			options.debugLines = true;
		}

		var
			ect = this,
			trimExp = /^[ \t]+|[ \t]+$/g,
			newlineExp = /\n/g,
			debugging = (
				options.debugLines ? (function (pre, debugMessage, post) {
					return '' + pre + '' + debugMessage + '' + post;
				}) : (function () {
					return '';
				})
			),
			cache = {},
			names = {},
			watchers = {},
			indentChars = { ':' : ':', '>' : '>' },
			escapeExp = /[&<>"]/,
			escapeAmpExp = /&/g,
			escapeLtExp = /</g,
			escapeGtExp = />/g,
			escapeQuotExp = /"/g,
			regExpEscape = function (str) {
				return String(str).replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
			},

			read = function (file) {
				if (Object.prototype.toString.call(ect.options.root) === '[object Object]') {
					var data = file.split('.').reduce(function (currentContext, key) { return currentContext[key]; }, ect.options.root);
					if (Object.prototype.toString.call(data) === '[object String]') {
						return data;
					} else {
						throw new Error ('Failed to load template ' + file);
					}
				} else {
					try {
						return fs.readFileSync(file, 'utf8');
					} catch (e) {
						throw new Error ('Failed to load template ' + file);
					}
				}
			},

			compile = function (template) {
				var
					lineNo = 1,
					bufferStack = [ '__ectOutput' ], bufferStackPointer = 0,
					buffer = bufferStack[bufferStackPointer] + ' = \'',
					matches = template.split(new RegExp(regExpEscape(ect.options.open) + '((?:.|[\r\n])+?)(?:' + regExpEscape(ect.options.close) + '|$)')),
					output, text, command, line,
					prefix, postfix, newline,
					indentChar, indentation = '', indent = false, indentStack = [], indentStackPointer = -1, baseIndent, lines, j;

				for (var i = 0; i < matches.length; i++) {
					text = matches[i];
					command = '';
					if (i % 2 === 1) {
						line = '__ectFileInfo.line = ' + lineNo;
						switch (text.charAt(0)) {
						case '=':
							prefix = '\'' + debugging(' + (', line, '\n\'\')') + ' + __ectTemplateContext.escape(';
							postfix = ') + \'';
							newline = '';
							text = text.substr(1);
							output = 'escaped';
							break;
						case '-':
							prefix = '\'' + debugging(' + (', line, '\n\'\')') + ' + ((';
							postfix = ') ? \'\') + \'';
							newline = '';
							text = text.substr(1);
							output = 'unescaped';
							break;
						default:
							prefix = '\'\n' + debugging('', line, '');
							postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'';
							newline = '\n';
							output = 'none';
						}
						text = text.replace(trimExp, '');

						command = text.split(/[^a-z]+/)[0];
						if ((indentChar = indentChars[text.charAt(text.length - 1)])) {
							text = text.replace(/:$/, '').replace(trimExp, '');
							if (indentChar === '>') {
								if (/[$a-z_][0-9a-z_$]*[^=]+(-|=)>/i.test(text.replace(/'.*'|".*"/, ''))) {
									indentStack.push('capture_output_' + output);
									indentStackPointer++;
								}
								bufferStack.push('__ectFunction' + bufferStackPointer);
								bufferStackPointer++;
								postfix = '\n' + bufferStack[bufferStackPointer] + ' = \'';
								command = 'function';
							}
							indentStack.push(command);
							indentStackPointer++;
							indent = true;
						}
						switch (command) {
						case 'include' :
							if (output === 'none') {
								prefix = '\'' + debugging(' + (', line, '\n\'\')') + ' + (';
								postfix = ') + \'';
							}
							buffer += prefix.replace(newlineExp, '\n' + indentation) + text + postfix.replace(newlineExp, '\n' + indentation);
							break;
						case 'block' :
							bufferStack.push('__ectTemplateContext.blocks[\'' + text.replace(/block\s+('|")([^'"]+)('|").*/, '$2') + '\']');
							bufferStackPointer++;
							prefix = '\'\n';
							postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'';
							text = 'if ' + text;
							buffer += prefix.replace(newlineExp, '\n' + indentation) + text;
							if (indent) {
								indentation += '  ';
								indent = false;
							}
							buffer += postfix.replace(newlineExp, '\n' + indentation);
							break;
						case 'content' :
							if (output === 'none') {
								prefix = '\'' + debugging(' + (', line, '\n\'\')') + ' + (';
								postfix = ') + \'';
							}
							if (text === 'content') {
								text = 'content()'
							}
							buffer += prefix.replace(newlineExp, '\n' + indentation) + text + postfix.replace(newlineExp, '\n' + indentation);
							break;
						case 'end' :
							prefix = '\'';
							switch (indentStack[indentStackPointer]) {
							case 'block' :
								bufferStack.pop();
								bufferStackPointer--;
								prefix = '\'';
								postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'';
								buffer += prefix.replace(newlineExp, '\n' + indentation);
								indentation = indentation.substr(2);
								buffer += postfix.replace(newlineExp, '\n' + indentation);
								break;
							case 'when' :
								postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'\'';
								buffer += prefix.replace(newlineExp, '\n' + indentation) + postfix.replace(newlineExp, '\n' + indentation);
								indentation = indentation.substr(2);
								break;
							case 'function' :
								prefix = '\'\n' + bufferStack[bufferStackPointer];
								buffer += prefix.replace(newlineExp, '\n' + indentation);
								indentation = indentation.substr(2);
								bufferStack.pop();
								bufferStackPointer--;
								postfix = '\n' + bufferStack[bufferStackPointer] + ' += \'';
								switch (indentStack[indentStackPointer - 1]) {
									case 'capture_output_escaped' :
										indentStack.pop();
										indentStackPointer--;
										buffer += ')';
										break;
									case 'capture_output_unescaped' :
										indentStack.pop();
										indentStackPointer--;
										buffer += ') ? \'\')';
										break;
									case 'capture_output_none' :
										indentStack.pop();
										indentStackPointer--;
										break;
								}
								buffer += postfix.replace(newlineExp, '\n' + indentation);
								break;
							case 'switch' :
								prefix = '\n' + debugging('', line, '');
							default :
								if (indentStack[indentStackPointer - 1] === 'switch') {
									postfix = '';
								}
								indentation = indentation.substr(2);
								buffer += prefix.replace(newlineExp, '\n' + indentation) + postfix.replace(newlineExp, '\n' + indentation);
							}
							indentStack.pop();
							indentStackPointer--;
							break;
						case 'else' :
							if (indentStack[indentStackPointer - 1] === 'switch') {
								prefix = '';
							} else {
								prefix = '\'';
							}
							buffer += prefix.replace(newlineExp, '\n' + indentation);
							if (indentStack[indentStackPointer - 1] === 'if' || indentStack[indentStackPointer - 1] === 'else' || indentStack[indentStackPointer - 1] === 'unless') {
								indentStack.splice(-2, 1);
								indentStackPointer--;
								indentation = indentation.substr(2);
							}
							buffer += (newline.length ? newline + indentation : '') + text;
							if (indent) {
								indentation += '  ';
								indent = false;
							}
							buffer += postfix.replace(newlineExp, '\n' + indentation);
							break;
						case 'switch' :
							buffer += prefix.replace(newlineExp, '\n' + indentation) + (newline.length ? newline + indentation : '') + text;
							if (indent) {
								indentation += '  ';
								indent = false;
							}
							break;
						case 'when' :
							buffer += (newline.length ? newline + indentation : '') + text;
							if (indent) {
								indentation += '  ';
								indent = false;
							}
							buffer += postfix.replace(newlineExp, '\n' + indentation);
							break;
						case 'extend' :
								text = '__ectExtended = true\n__ectParent = ' + text.replace(/extend\s+/, '');
						default :
							if (/\n/.test(text)) {
								lines = text.split(/\n/);
								buffer += prefix.replace(newlineExp, '\n' + indentation);
								for (j = 0; j < lines.length; j++) {
									if (/^\s*$/.test(lines[j])) {
										continue;
									}
									if (typeof baseIndent === 'undefined') {
										baseIndent = new RegExp('^' + lines[j].substr(0, lines[j].search(/[^\s]/)));
									}
									buffer += (newline.length ? newline + indentation : '') + lines[j].replace(baseIndent, '');
								}
								lines = undefined;
								baseIndent = undefined;
							} else {
								buffer += prefix.replace(newlineExp, '\n' + indentation) + (newline.length ? newline + indentation : '') + text;
							}
							if (indent) {
								indentation += '  ';
								indent = false;
							}
							buffer += postfix.replace(newlineExp, '\n' + indentation);
							break;
						}
					} else {
						if (indentStack[indentStackPointer] !== 'switch') {
							buffer += text.replace(/[\\']/g, '\\$&').replace(/\r/g, '').replace(newlineExp, '\\n').replace(/^\\n/, '');
						}
					}
					lineNo += text.split(newlineExp).length - 1;
				}
				buffer += '\'\nif not __ectExtended\n  return __ectOutput\nelse\n  __ectContainer = __ectTemplateContext.load __ectParent\n  __ectFileInfo.file = __ectContainer.file\n  __ectFileInfo.line = 1\n  __ectTemplateContext.childContent = __ectOutput\n  return __ectContainer.compiled.call(this, __ectTemplateContext, __ectFileInfo, include, content, block)';
				buffer = '__ectExtended = false\n' + buffer;

				return eval('(function __ectTemplate(__ectTemplateContext, __ectFileInfo, include, content, block) {\n' + CoffeeScript.compile(buffer, { bare : true }) + '});');
			};

		var TemplateContext = function (data) {
			this.blocks = {};
			this.data = data || {};
			this.childContent = '';
		};

		TemplateContext.prototype.escape = function (text) {
			if (text == null) {
				return '';
			}
			var result = text.toString();
			if (!escapeExp.test(result)) {
				return result;
			}
			return result.replace(escapeAmpExp, '&').replace(escapeLtExp, '<').replace(escapeGtExp, '>').replace(escapeQuotExp, '"');
		};

		TemplateContext.prototype.block = function (name) {
			if (!this.blocks[name]) { this.blocks[name] = ''; }
			return !this.blocks[name].length;
		};

		TemplateContext.prototype.content = function (block) {
			if (block && block.length) {
				if (!this.blocks[block]) { return ''; }
				return this.blocks[block];
			} else {
				return this.childContent;
			}
		};

		TemplateContext.prototype.load = function (template, layout) {
			var file, compiled, container, data;

			var nameAppend = '';
			if (layout && typeof layout === 'string') {
				nameAppend = '__ectExtendedLayout__' + layout;
			}

			if (ect.options.cache && !!nameAppend && cache[template + nameAppend]) {
				return cache[template + nameAppend];
			} else if (ect.options.cache && cache[template] && !nameAppend) {
				return cache[template];
			} else {
				var extExp = new RegExp(regExpEscape(ect.options.ext) + '$');
				if (Object.prototype.toString.call(ect.options.root) === '[object String]') {
					if (typeof process !== 'undefined' && process.platform === 'win32') {
						file = path.normalize((ect.options.root.length && template.charAt(0) !== '/' && template.charAt(0) !== '\\' && !/^[a-zA-Z]:/.test(template) ? (ect.options.root + '/') : '') + template.replace(extExp, '') + ect.options.ext);
					} else {
						file = path.normalize((ect.options.root.length && template.charAt(0) !== '/' ? (ect.options.root + '/') : '') + template.replace(extExp, '') + ect.options.ext);
					}
				} else {
					file = template;
				}

				data = read(file);
				if (data.substr(0, 24) === '(function __ectTemplate(') {
					try {
						compiled = eval(data);
					} catch (e) {
						e.message = e.message + ' in ' + file;
						throw e;
					}
				} else {
					if (nameAppend !== '') {
						data = ect.options.open + ' extend \'' + layout + '\'' + ect.options.close + '\n' + data;
					}
					try {
						compiled = compile(data);
					} catch (e) {
						e.message = e.message.replace(/ on line \d+/, '') + ' in ' + file;
						throw e;
					}
				}
				container = { file : file, compiled : compiled, source : '(' + compiled.toString() + ');', lastModified: new Date().toUTCString(), gzip : null };
				if (ect.options.cache) {
					cache[template + nameAppend] = container;
					if (!names[template]) {
						names[template] = [];
					}
					names[template].push(template + nameAppend);
				}
				if (ect.options.watch && typeof watchers[file] === 'undefined') {
					watchers[file] = fs.watch(file, { persistent: false }, function () {
						watchers[file].close();
						delete (watchers[file]);
						for (var i = names[template].length - 1; i >= 0; i--) {
							delete (cache[names[template][i]]);
						};
						names[template] = [];
					});
				}
				return container;
			}
		};

		TemplateContext.prototype.render = function (template, data) {
			var layout;
			if (this.data && (layout = this.data.layout)) {
				this.data.layout = false;
			}
			else if (data && (layout = data.layout)) {
				data.layout = false;
			}
			else {
				layout = undefined;
			}

			var that = this;
			var container = this.load(template, layout);
			var fileInfo = { file : container.file, line : 1 };

			try {
				return container.compiled.call(
					data || this.data,
					this,
					fileInfo,
					function() { return that.render.apply(that, arguments); },
					function() { return that.content.apply(that, arguments); },
					function() { return that.block.apply(that, arguments); }
				);
			} catch (e) {
				if (!/ in /.test(e.message)) {
					e.message = e.message + ' in ' + fileInfo.file + ' on line ' + fileInfo.line;
				}
				throw e;
			}
		};

		this.configure = function (options) {
			options = options || {};
			for (var option in options) {
				this.options[option] = options[option];
			}
		};

		this.compile = function (template) {
			var compiled;
			try {
				compiled = compile(template);
				return compiled;
			} catch (e) {
				e.message = e.message.replace(/ on line \d+/, '');
				throw e;
			}
		};

		this.render = function (template, data, callback) {
			var context;
			if (typeof arguments[arguments.length - 1] === 'function') {
				if (arguments.length === 2) {
					callback = data;
					data = {};
				}
				context = new TemplateContext(data);
				try {
					callback(undefined, context.render(template));
				} catch (e) {
					callback(e);
				}
			} else {
				context = new TemplateContext(data);
				return context.render(template);
			}
		};

		this.clearCache = function (template) {
			if (template) {
				delete (cache[template]);
			} else {
				cache = {};
			}
		};

		if (typeof module !== 'undefined' && module.exports) {
			this.compiler = function (options) {
				var zlib = require('zlib');
				options = options || {};
				options.root = options.root || '/';
				options.root = '/' + options.root.replace(/^\//, '');
				options.root = options.root.replace(/\/$/, '') + '/';
				var rootExp = new RegExp('^' + regExpEscape(options.root));
				return function (req, res, next) {
					if (req.method !== 'GET' && req.method !== 'HEAD') {
						return next();
					}
					if (!options.root || req.url.substr(0, options.root.length) === options.root) {
						var template = req.url.replace(rootExp, '');
						try {
							var context = new TemplateContext();
							var container = context.load(template, options.layout);
							res.setHeader('Content-Type', 'application/x-javascript; charset=utf-8');
							res.setHeader('Last-Modified', container.lastModified);
							if (options.gzip) {
								res.setHeader('Content-Encoding', 'gzip');
								if (container.gzip === null) {
									zlib.gzip(container.source, function (err, buffer) {
										if (!err) {
											container.gzip = buffer;
											res.end(container.gzip);
										} else {
											next(err);
										}
									});
								} else {
									res.end(container.gzip);
								}
							} else {
								res.setHeader('Content-Length', typeof Buffer !== 'undefined' ? Buffer.byteLength(container.source, 'utf8') : container.source.length);
								res.end(container.source);
							}
						} catch (e) {
							next(e);
						}
					} else {
						next();
					}
				}
			};
		}

		this.configure(options);
	};

	if (typeof module !== 'undefined' && module.exports) {
		fs = require('fs');
		path = require('path');

		if (true) {
			CoffeeScript = require('coffee-script');
			module.exports = ECT;
		}
	}
}());

redpajama_set_name: RedPajamaGithub


text:
"Tools of Titans" by Tim Ferris – A Book Review from a Sunflower Counseling MT therapist
At Sunflower Counseling Montana, located in Missoula, MT, we serve a variety clients. But they all have one thing in common. They want to progress in life. With this said, the brain loves to have goals! Mix in some endorphins and dopamine with these goals, and suddenly, we are on our way to becoming "happy".
So this week, in between therapy here at Sunflower Counseling Montana, I decided to read "Tools of Titans" by Tim Ferris. I'm going to tell you what I think are some of the best top 14 ideas in the first third of the book. Realize the book is 700 pages! Keep in mind that a lot of book reads like a "MacGyver" self-help book. It's filled with gadgets and technology and things you might laugh about while drinking coffee.
So as you read, take it with a grain of salt, and have fun with it!
TOOLS OF TITANS by Tim Ferriss
TOP 14 IDEAS part 1:
#1. Patterns of the successful: 80 percent of the "successful" Tim studied have some form of daily mindfulness or meditation practice.
#2. Playing with temperatures. Cyclist David Zabriskie, seven-time US National Time Trial Championship winner considers the sauna a more practical replacement for high-alititude simulation tents. Think 32 percent more endurance by using the sauna – says Dr. Rhonda Patrick. She also says it can increase growth hormone levels as well by going 4 times per week typically at roughly 160 to 170. More precisely, two 20 minute sauna sessions at 176 degrees Fahrenheit separated by a 30 minute cooling period elevated growth hormone levels two-fold over baseline. These effects persist for a couple of hours post-sauna. Timothy Ferris drinks ice-water and takes ice baths afterwords. But obviously he's aiming at the inflammation in the esophagus we can infer being a male as he is. Do you like these lists? I'm just listing it off for you. Cutting to the chase. Amelia Boone, 3 time finisher of the Death Race amongst other things, loves doing training runs in the rain and cold, as she knows her competition is probably opting out. This is an example of "rehearsing the worst-case scenario" to become more resilient." There's a whole section on Wim Hof – I'm really into Wim Hof as well – and make sure to look up him up on Youtube if you haven't yet. He has a great 10-course that will change your life.
#3. Male gymnasts don't have biceps the size of their waists from curls. This bulk comes largely from straight-arm work, especially Maltese work on the rings. Check out the Ring thing at Power Monkey firness or generic "Dream machine" – OMG where do I get this. I need to get those rings and enroll in gymnastics class! I don't care if it looks weird. Being weird is good, Chris Sacca says – he actually says it in this book.
#4. Page 22 goes over the basics of the ketogenic diet – which is a high fat diet that mimics fasting physiology. This is the diet where "your brain and body begin to use ketones (derived from stored or ingested fat) for energy instead of blood sugar (glucose) – to arrive at a state called ketosis. This is achieved through fasting, diet, exogenous ketones, or a combination. So how do you know you're in Ketosis? Tim says the most reliable way is to use a device called the Precision Xtra by Abbott. This can measure both glucose and blood levels of beta-hydroxybut-urate (BHB). Once you reach 0.5 millimolars – you can consider yourself lightly "in ketosis."
Note: Dr. Peter Attia, wears a Dexcom G5 continuous glucose monitor to track his glucose levels 24/7, which are displayed on his iphone. See page 61. I'm noticing a theme, by the way, a lot of these guys are obsessed with their insulin and glucose levels. You want to talk about adapting to the new age or technology, this is kind of extreme – for most people to do. "Oh don't mind me I'm just taking my blood. You guys can keep opening presents."
BUT – Timothy says he tends to feel increased mental clarity at 1mmol or higher!!! Your primary resource, Dr. Dominic "Dom" D'Agostino (Dag-o-steeno) for the ketogenic diet like meal plans is at ketogenic-diet-resource.com. Dom says "I like to promote mild to moderate ketosis for health and longevity, which is between 1 to 3 mmol."
Why consider Ketosis or supplemental ketones?
Fat Loss and body recomposition
Potent anti-cancer effects
Better use of oxygen (this is why elite cyclists are experimenting with keto).
And anti-inflammatory effects.
And when it comes to cancer, Timothy says exogenous ketones have been demonstrated to have a significant tumor-suppressing or shirnking effect, even in the presence of dietary carbohydrates. He adds, "if you think the ketogenic diet is for lunatics, exogenous ketones only require mixing a scoop in water and swigging it down." Patrick Arnold and Timothy say that if you are in ketosis, drinking exogenous ketones pre-and intra-workout can be a substitute for carbs.
The ketogenic diet is a whole world. But this is an introduction that just might save your life! So I recommend you look into this.
#5. FASTING Dr. Dominic "Dom" D'Agostino (Dag-o-steeno) Dom: "If you don't have any cancer and you do a therapeutic fast 1 to 3 times per year, you could purge any precancerous cells that may be living in your body." There is also evidence to suggest – that fasts of 3 days or longer can effectively "reboot" your immune system via stem cell-based regeneration. Dom suggests a 5-day fast 2 to 3 times per year. Tim says "Fasting doesn't need to make you miserable and weak. In fact, it can be quite the opposite effect." Timothy aims for a 3-day fast once per month and a 5-to-7 day fast once per quarter.
#6. Dom also says that fasting before chemotherapy is definitely something that should be implemented in oncology wards. He says "Fasting essentially slows (sometimes stops) rapidly dividing cells and triggers an 'energetic crisis' that makes cancer cells selectively vulnerable to chemo and radiation." There are many studies to support this claim.
#7. Charles Poliquin, one of the best known strength coaches in the world, says "The most important thing I've learned about nutrition is you need to deserve your carbs." I've been thinking a lot about this lately "deserving my carbs." Because I ate so much pumpkin pie at Christmas. They just gave me so much pumpkin pie I'm like, "Shouldn't you put that on a plate" and they're like, "No you can just eat the whole thing. Here's a tub of ice cream." Charles also says you need to be sub-10% fat. Put another way, you have to be able to see all your abs. Put another way, he says you have to have penis skin on your abs. He actually said that. On that note, men, it's also important you wake up with a boner, says Kelly Starrett, one of the best performance coaches in the world. Apparently the boner is an excellent indicator of sleep quality, hormonoal health, circadian rhythm timing, and more.
#8. For back pain, check out the Nayoya (Nay-o-ya) Acupressure Mat. There is a competitor called Bed of Nails on Amazon. But this roll out needle mat performs miracles for back pain.
#9. Visual overwriting: Jane McGonigal, who has a great talk on Ted about reality and why videogames are cool and can educate, says 10 minutes of Tetris before going to bed can crowd out anything replaying or looping in one's mind that will inhibit sleep. My wife is doing this right now. We're going to have to get a full report from her. It's also great for PTSD. So next time something traumatic happens to you reach for your tetris app on your phone. "Oh you just got mugged what are you doing?" "I'm playing Tetris, duh."
#10. Morning Routines – As soon as you wake up, make your bed because that makes you feel like you accomplished something no matter what no matter how bad your day goes you made your bed, meditate, and do 10 to 15 reps of something. I have weights sitting right outside my bedroom. And one of those mini-trampolines. Just prime yourself. Also, check out "The Morning Pages" by Julia Cameron.
#11. Meditation master Shinzen Young said that if he were allowed to teach only one focus technique and no other it would be this one: it's called Just Note Gone. This is where we train the mind to notice that something previously experienced is no more. For example, at the end of a breath, notice that the breath is over. Gone. As a sound fades away, notice when it's over. Gone. When this youtube video is done, just notice it, gone.
#12. Meditate on other people you want to be happy can help you to be more happy, and get you out of the normal meditation which is usually a very "me"-focused activity where you think about your "stuff" But thinking about other people and wishing them happiness – This loving-kindness drill Timothy Ferris says resolves at least 90% of the mental chatter.
#13. Timothy has an awesome slow-carb Diet Cheat Sheet which you should check out. (P.81) In short, it says to avoid starchy carbs, which means no bread or pasta or rice or potatoes or grains like quinoa, eat the same meals again over and over, don't drink your calories, with the exception being wine, don't eat fruit, and whenever possible measure your progress in body fat percentage, not total pounds. In place of the scale Timothy uses DEXA scans, a body metrix home ultrasound device, or calipers with a gym professional.
#14. Finally he says: Take one day off where you go nuts, on cheat day, and he says it's important not to hold back – which is a nice marker to remind yourself you're only giving up vices for 6 days out of the week!
I'm just going to say you have to get this book. It's trick after trick to help you adapt faster in this super fast moving age we're in. Check it out "Tools of Titans" by Tim Ferris.
By Kerry Heffelfinger|2021-05-25T04:51:46-07:00January 27th, 2021|Uncategorized|
Quit Smoking the Alan Carr Way – Missoula Therapists
Moving Forward in Winter Months – Missoula Therapists
Managing Emotional Eating with Alan Carr's Strategies – Missoula Therapists
Missoula Drug Abuse: A Closer Look
Mental Health Experts Talk Climate Change – Missoula Counselors


text:
High contrast A- A A+
Smog alerts
Protect your health
AQ modeling in near-real time
Replace boiler
Ecodesign solid fuel boilers and space heaters
Calculator of emissions and heating costs
Ecomanagers
Air quality plan
Anti-smog resolution
Effects of activities
LIFE project
Media about LIFE project
The first flight of a solar plane
Published by Kinga Stawiarz
On Wednesday, July 10 at the Polish Aviation Museum a presentation of an unmanned solar aircraft took place. The Malopolska Region was represented by Deputy Marshal Tomasz Urynowicz.
The project of an innovative, unmanned solar-powered aircraft was created by members of the AGH Solar Plane scientific circle from the AGH University of Science and Technology. Photovoltaic panels were mounted on the wings of the machine. The energy produced is stored in batteries enabling flight at night. The aircraft weighs about 5 kg, and the wingspan is 6 m.
The culmination of the project will be a machine flight along the eastern border of Poland as well as an entry in the international solar competition "TÜBİTAK International Unmanned Aerial Vehicle Competition" in Istanbul, Turkey.
The meeting began with the greeting of guests and project presentations. After the official part, an acrobatic model was presented. The event ended with a demonstrative solar flight.
☁ » News » The first flight of a solar plane
News about air protection activities in Małopolska
I hereby agree to the processing of my personal data provided in the newsletter. Personal data processing is related to the implementation of the project: "Implementation of the Air Quality Plan for the Malopolska Region - Malopolska in a healthy atmosphere" LIFE-IP MALOPOLSKA / LIFE14 IPE PL021, co-financed from the LIFE Programme of the European Union, hereinafter referred to as "LIFE project". The legal basis for the processing of personal data provided is Article 5 letter b) Regulation (EC) No 45/2001 of the European Parliament and of the Council of 18 December 2000 on the protection of individuals with regard to the processing of personal data by the Community institutions and bodies and on the free movement of such data (UE.L.2001.8.1) in conjunction with from Article 27 and 28 Regulation (EU) No 1293/2013 of the European Parliament and of the Council of 11 December 2013 on the establishment of a Programme for the Environment and Climate Action (LIFE) and repealing Regulation (EC) No 614/2007 (OJ 2013 L 31, p. UE.L.2013.347.185). The administrator of the personal data provided is the European Commission (unit ENV.E.4 - LIFE Enviroment, Rue du Bourget 1, B - 1140 Bruxelles, Belgique), which entrusted data for processing to the Beneficiary Coordinating the LIFE project - Malopolska Region with headquarters in Krakow, ul. Basztowa 22, 31-156 Kraków, address for correspondence: ul. Racławicka 56, 30-017 Kraków (represented by the Marshal of the Malopolska Region, who appointed a Data Protection Officer operating at the same local address and at the electronic address iodo@umwm.malopolska.pl) and Partners participating in the implementation of the LIFE project. The personal data provided will be processed solely for the purpose of implementing the LIFE project, in particular confirmation of eligibility of expenditure, provision of support, monitoring, evaluation, control, audit and reporting. Personal data may be provided only to entities implementing evaluation studies that carry out inspections and audits as part of the LIFE project at the request of the European Commission or the Beneficiary. Personal data will be kept for a period of up to 5 years counted from the date of payment of the final balance in the LIFE project, i.e. at least until the end of 2028. The subject of personal data has the right to: demand from the processors access to personal data, rectification, deletion or limitation of processing, opposition to processing, transfer of data, lodging a complaint to the European Data Protection Supervisor Rue Wiertz 60, B-1047 Bruxelles, Belgique).
LIFE Programme
Regional Fund EPWM
Stay up to date, subscribe to our newsletter
The LIFE Integrated Project LIFE-IP MALOPOLSKA / LIFE14 IPE PL 021 is implemented with the support of the LIFE Programme of the European Union.
Website has been co-financed by the Regional Fund for Environmental Protection and Water Management in Krakow.
© 2020 All rights reserved. Made by nFinity.pl
This site uses cookies to provide services at the highest level. Further use of the site means that you agree to their use.I agreePrivacy policy


In morning news, "Today" will be a stronger partner for WRAL than "CBS This Morning" – though the CBS morning news show, which has a stronger emphasis on news over entertainment and is anchored by North Carolina native Charlie Rose, has been making steady gains. ABC's "Good Morning America" is the top morning news show, nationally.
The evening news situation is similar. NBC and ABC are neck-and-neck in the ratings race – with ABC's David Muir recently pulling ahead of NBC's Lester Holt – while CBS lags in third place, with a newscast anchored by Scott Pelley.
In prime-time programming, NBC has made a big comeback in recent years, climbing from the cellar in Nielsen ratings to hold the top spot for the past two years. CBS and ABC tie for second place, just ahead of Fox.
According to a news release from Capitol Broadcasting, WRAL started out as an NBC affiliate in 1956 and switched to ABC in 1962. It became the local CBS affiliate in 1985. The station's owner, Capitol Broadcasting, also owns the local Fox affiliate, WRAZ.
When reached Friday night, Kristen Byrum, director of marketing at WNCN, said the station is excited about the change.
WNCN is owned by Media General. In that company's news release, president and CEO Vincent L. Sadusky said it looks forward to having the CBS affiliate in Raleigh. "We are particularly excited about the opportunities this brings to our station and the high-quality network programming that complements our strong local news and unique local content," he said.


text:
Man arrested after stabbing roommate in Grand Chute
Posted: Apr 25, 2017 / 10:40 AM CDT / Updated: Apr 25, 2017 / 10:40 AM CDT
A man was sent to the hospital being stabbed by his roommate, according to officials.
Police were sent to the 1500 block of Tri Park Way in Grand Chute for a disturbance at an apartment.
When they arrived, they found a 31-year-old man unconscious with multiple stab wounds. He was transported to the hospital for his injuries.
A preliminary investigation showed that the incident started over one roommate making noise while others were trying to sleep. Police say the dispute then turned physical between the victim and a 23-year-old man.
The 23-year-old was arrested and officials say they are seeking charges of recklessly endangering safety with a weapon and disorderly.
by Jacqui Lange / Jan 21, 2020
APPLETON, Wis. (WFRV) -- Each year the Red Smith banquet is held to raise money for local youth organizations and to honor those who have left a major impact on the world of sports.
One of the major awards of the evening is the Red Smith Award, given to a person who has excelled in sports from the state of Wisconsin. In 2020, the award was given to longtime MLB Umpire Gerry Davis.
by Calvin Lewis / Jan 21, 2020
GREEN BAY, Wis. (WFRV) - Craft breweries are a growing trend throughout Wisconsin and the doors of a new one are opening up right off Webster Avenue.
Zambaldi Beer is celebrating its grand opening this afternoon after month's of construction and year's of planning. Traveling down Webster Ave., you may have passed by the brewery and taproom throughout the year as it was under construction but the big pay off has finally arrived.
by Addy Bink / Jan 21, 2020
GRAND CHUTE, Wis. (WFRV) -- The crash along I-41 southbound in Grand Chute that caused traffic delays Tuesday morning has been cleared.
Officials were able to clear the incident within an hour, allowing traffic to return to normal.
Army veteran turns to fishing to cope with loss of leg and his son
MLK honored through community service at Lawrence University


The American business world moves at the speed of light and the same ease and smoothness is expected in all spheres of life by Americans. That is why when it comes to American auto transport, people want their vehicles moved at lightning fast paces. However, there is much more to the business of moving vehicles than just taking them physically from one location to another.
It Does Not Happen at the Speed of Light.
other customers who have booked the vehicle but have brought in their car late.
incomplete paperwork – this may cause delays especially when you have to get customs clearance.
accidents along the route which may cause the roads to get blocked.
You are Probably not Dealing with a Company but with an Agent.
Most often when you contact a car shipping company, you are probably getting in touch with a broker company who has a wide network of car shipping companies under their wings. Most of the car shipping companies will be small ones with regular routes and owning just a few vehicles. They will be dependent upon these broker firms to get them new orders. In the same way, when you call up these brokers, they will search their network and will find the company that is doing the route that you want to put you on to them.
You are Paying for Transportation Charges Regardless of the Place of Purchase.
You click a button and select the latest car online to make it yours. However, the problem arises when you want it transported to your hometown which, inconveniently, happens to be all the way across the country. So you become wise and hop over to the nearest showroom and buy the car. This way you are thinking that you are saving on transportation cost, right? Well, you are right in a way but there is one hidden cost that you are paying regardless of the fact that you are buying it near your own house or a thousand miles away.
The unknown factor is this.
New cars are being transported to their dealerships all over the country and they cannot be driven over there as then they would be considered used cars and not brand new. So the cost of transportation is actually paid by the customers when they buy the vehicle as destination charge. However, the actual transportation charge is not fully given in the destination charge but is spread to all the vehicles under a nationwide average so that no matter where you buy the car from, you still get to pay the transportation charges. So when you buy online, choose something nearer your hometown as you have to now pay again for your own transportation charges on top of the overall nationwide average that you are already paying for.
Choose the Company that Pays More to the Drivers.
This is a small but significant tip when you are dealing with American car shipping brokers. Let us say that two companies offer the same quote and that puts you in a dilemma. To make a clear educated decision, ask the companies for a breakup of the quote and then choose the one that pays the driver more. This will ensure that your vehicle is in better hands and you can be sure that your car will be delivered to you safely.
You can Save Money When You are not Particular About the Time.
Business is normally slow during winter months and so if you can schedule your move during then, you can save a few hundred. There may also be times when the transportation company will put you on the more expensive carrier simply because the cheaper one is already booked full. In such cases, you can take the time to wait till the cheaper one becomes available again to move your car.


George Villiers, 1st Duke of Buckingham (1592-1628), Courtier; favourite of James I. Sitter associated with 49 portraits.
Exiled Charles, Prince of Wales, holds negotiations in the Netherlands, with the Scottish Parliament to secure an alliance. Despite misgivings on both sides, and pressure from the Scots for Charles to sign the covenants, the treaty of Breda is agreed.
Oliver Cromwell defeats the Scots at the Battle of Dunbar.
Poet and politician, Andrew Marvell, composes his greatest political poem, Horatian Ode upon Cromwell's Return from Ireland. Marvell become Oliver Cromwell's unofficial poet laureate during the Protectorate.
William, The Prince of Orange, grandson of Charles I, is born assuming the title from the moment of birth. Forty years later, he would become William III of England.
General-at-Sea, Robert Blake is dispatched to Portugal to prevent attacks on Commonwealth merchant shipping from royalist, Prince Rupert, based in Lisbon.


Houston, Texas July 24, 2012 – Not just any managed IT services provider (MSP) can become a Microsoft partner. And only one MSP each year can be named Microsoft Partner of the Year. This year, that honor was bestowed upon Houston-based CITOC.
CITOC won the award by demonstrating dedication to and extensive knowledge of Microsoft products. The Partner of the Year award is just Microsoft's way of saying thank you. Besides selling Microsoft licenses to customers, CITOC grew the fastest and had the highest client retention and renewal rates among all of Microsoft's MSP partners.
"Our clients realize that we are committed to providing them with the right products to help them improve their businesses. Those products happen to be from Microsoft," said CITOC president BJ Farmer.
Because this is the first time that anyone on the CITOC team has worked for a company that's won the Microsoft Partner of the Year award, they're all bursting with pride over this accomplishment.
The award will remain on display at the local Microsoft store so that the sales team there can share in CITOC's success.
If you're a small-business owner in need of an award-winning MSP, call CITOC today and schedule a no-obligation consultation.
About CITOC: CITOC is a business technology consulting service founded in 1995 on the premise that Change Is The Only Constant (CITOC). We are known in Houston for our expert knowledge of automating manual processes, cloud services and rapid growth.
Visit http://citocws.wpengine.com or call 713.490.5000 to learn more about how CITOC can help your Houston business.


Trustees are considering the restructuring of business premise license fees to more accurately reflect the cost of commercial property inspections.
Under a proposal recommended by the Judiciary Committee, the cost of a general business premises license would be based on the square footage of a building.
A property of less than 2,000 square feet would pay $35. The fees would escalate incrementally to $475 for properties of 500,000 square feet, plus $75 for each additional 100,000 square feet.
The intent of the revised license fees is to more accurately reflect the cost of village inspections and regulation of commercial properties, said Village Atty. Richard Williams. The trustees are to vote on the measure April 19.
The issue came to light when several large retail outlets recently applied for business licenses.
For example, Menard's, a hardware and home improvement retailer that plans to open a 126,800-square-foot store in Barrington Square shopping center will pay only $65.
But under the proposed new fee structure, Menard's would have paid $400 for a general business premises license.