Friday, 3 May 2019

Powershell - Appending folder to path

The following Powershell function can be used to append a folder to the path for a user at the command line.

function AppendPath($filePath) {
 $path = [Environment]::GetEnvironmentVariable("Path")
 $path += ";" + $filePath
 [Environment]::SetEnvironmentVariable("Path", $path)
 Write-Host $path 
}

To call this function, just run the Powershell command:
AppendPath "c:\temp"
You can add this file into your $profile file as a function for easy availability. Run . $profile to reload your $profile file. This will append the folder "c:\temp" to your environment variable PATH. To view your environment variable PATH just enter:
echo $env:path
It is not required, but you can also use Chocolatey's refreshenv script to force update the environment variable if it is still not updating.

Thursday, 2 May 2019

Regenerating precompiled views in Entity Framework

This article will present a solution to regenerate precompiled views in Entity Framework. Precompiled views can have a dramatic effect on the startup time of your DbContext / ObjectContext, especially the time to execute the first query against the database. First off, the following class can generate these precompiled views:

using System;
using System.Collections.Generic;
using System.Data.Entity.Core.Mapping;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;

namespace PrecompiledViewGenerator
{
    /// <summary>
    /// Capable of generating pre compiled views that EF can use for quicker startup time when application domains starts.
    /// </summary>
    /// <typeparam name="TDbContext"></typeparam>
    /// <param name="dbContext"></param>
    /// <remarks>See https://github.com/ErikEJ/EntityFramework6PowerTools/tree/community/src/PowerTools Github page for the source code of EF Power tools.</remarks>
    /// <returns>A string containing the precompiled views that can be written to file or database for later use to gain optimized startup speeds of EF in application domains.</returns>
    public class EntityFrameworkPrecompiledViewGenerator
    {
        /// <summary>
        /// Generates pre compiled views from a db context. Uses EF Powertools runtime T4 template (.tt file) for precompiled view generation of views for EF 6 ObjectContext for C#.
        /// </summary>
        /// <typeparam name="TDbContext"></typeparam>
        /// <param name="dbContext"></param>
        /// <param name="viewContainerSuffix">The suffix to apply in the generated file containing the precompiled views</param>
        /// <remarks>See https://github.com/ErikEJ/EntityFramework6PowerTools/tree/community/src/PowerTools Github page for the source code of EF Power tools.</remarks>
        /// <returns>A string containing the precompiled views that can be written to file or database for later use to gain optimized startup speeds of EF in application domains.</returns>
        public string GeneratePrecompiledViews<TDbContext>(TDbContext dbContext, string viewContainerSuffix) where TDbContext : IObjectContextAdapter
        {
            if (string.IsNullOrEmpty(viewContainerSuffix))
                throw new ArgumentNullException(nameof(viewContainerSuffix));
            var objectContext = (dbContext as IObjectContextAdapter)?.ObjectContext; 
            if (objectContext == null)
                throw new ArgumentNullException(nameof(dbContext));
            var viewGenerator = new CSharpViewGenerator();
            var mappingCollection = (StorageMappingItemCollection) objectContext.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace);
            if (mappingCollection == null)
                throw new ArgumentNullException(nameof(dbContext));
            var listOfEdmSchemaErrors = new List<EdmSchemaError>();
            var views = mappingCollection.GenerateViews(listOfEdmSchemaErrors);
            listOfEdmSchemaErrors.ForEach(error =>
            {
                if (error.Severity == EdmSchemaErrorSeverity.Error)
                    throw new ArgumentOutOfRangeException($"An error occurred while trying to generate views for {dbContext.GetType().Name}. The error was: {error.ToString()}");
            });
            viewGenerator.ContextTypeName = dbContext.GetType().FullName;
            viewGenerator.MappingHashValue = mappingCollection.ComputeMappingHashValue();
            viewGenerator.ViewContainerSuffix = viewContainerSuffix;
            viewGenerator.Views = views;
            string precompiledViews = viewGenerator.TransformText();
            return precompiledViews;
        }
    }
}



The following runtime text template (.T4) is used to generate the precompiled views:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System.Data.Entity.Infrastructure.MappingViews;

[assembly: DbMappingViewCacheTypeAttribute(
    typeof(<#= ContextTypeName #>),
    typeof(Edm_EntityMappingGeneratedViews.ViewsForBaseEntitySets<#= ContextTypeName #>))]

namespace Edm_EntityMappingGeneratedViews
{
    using System;
    using System.CodeDom.Compiler;
    using System.Data.Entity.Core.Metadata.Edm;

    /// <summary>
    /// Implements a mapping view cache.
    /// </summary>
    [GeneratedCode("Entity Framework 6 Power Tools", "0.9.2.0")]
    internal sealed class ViewsForBaseEntitySets<#= ViewContainerSuffix #> : DbMappingViewCache
    {
        /// <summary>
        /// Gets a hash value computed over the mapping closure.
        /// </summary>
        public override string MappingHashValue
        {
            get { return "<#= MappingHashValue #>"; }
        }

        /// <summary>
        /// Gets a view corresponding to the specified extent.
        /// </summary>
        /// <param name="extent">The extent.</param>
        /// <returns>The mapping view, or null if the extent is not associated with a mapping view.</returns>
        public override DbMappingView GetView(EntitySetBase extent)
        {
            if (extent == null)
            {
                throw new ArgumentNullException("extent");
            }

            var extentName = extent.EntityContainer.Name + "." + extent.Name;
<#
    var index = 0;
    foreach (var view in Views)
    {
#>

            if (extentName == "<#= view.Key.EntityContainer.Name + "." + view.Key.Name #>")
            {
                return GetView<#= index #>();
            }
<#
        index++;
    }
#>

            return null;
        }
<#
    index = 0;
    foreach (var view in Views)
    {
#>

        /// <summary>
        /// Gets the view for <#= view.Key.EntityContainer.Name + "." + view.Key.Name #>.
        /// </summary>
        /// <returns>The mapping view.</returns>
        private static DbMappingView GetView<#= index #>()
        {
            return new DbMappingView(@"<#= view.Value.EntitySql #>");
        }
<#
        index++;
    }
#>
    }
}
<#+
    public string ContextTypeName { get; set; }
 public string ViewContainerSuffix { get; set; }
    public string MappingHashValue { get; set; }
    public dynamic Views { get; set; }
#>

This T4 file is compiled into the class CSharpViewGenerator. Our DbContext can now check the mapping hash value of the loaded precompiled views file in your assembly and compute in again to quickly assert if the database is in sync with the precompiled views. The following code can establish both a check that the precompiled views are in sync and run code that will regenerate the precompiled views file of which the developer can then copy from Notepad and into the precompiled view file again. Not perhaps an elegant solution, but it lets the developer easily check and keep the precompiled views file updated and in sync. And you do not need to install the EF Powertools extension either, as I use the .tt file and much of the source code from there which is part of the "Generate views" command anywyays! Sample DbContext is then:
using System;
using System.Data.Entity;
using System.Data.Entity.Core;
using System.Data.Entity.Core.Mapping;
using System.Data.Entity.Core.Metadata.Edm;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using Edm_EntityMappingGeneratedViews;

using PrecompiledViewGenerator;

namespace SomeAcme.SomeRegistry.Data
{
    public class SomeDatabaseMigrationsFactory : DatabaseMigrationsFactory<SomeDatabase>
    {
    }

    public class SomeDatabase : SomeDatabaseBaseClass
    {
        public DbSet<SomeEntity> SomeEntity { get; set; }

        public SomeDatabase(ISomeDependency dep)
            : base(dep)
        {
            var someEntityPrecompiledViewsMapping = new ViewsForBaseEntitySetsSomeEntityDatabase();
            var mappingCollection = (StorageMappingItemCollection)ObjectContext.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace);
            string mappingHashValue =  mappingCollection.ComputeMappingHashValue();
            if (SomeEntityPrecompiledViewsMapping.MappingHashValue != mappingHashValue)
            {
                var precompiledViewGenerator = new EntityFrameworkPrecompiledViewGenerator();
                string precompiledViewsContents = precompiledViewGenerator.GeneratePrecompiledViews(this, this.GetType().Name);
                string viewFileForMainDb = "SomeEntityDatabase.Views.cs";
                string temporaryPrecompiledViewFile = Path.Combine(Path.GetTempPath(), viewFileForMainDb);
                try
                {
                    File.WriteAllText(temporaryPrecompiledViewFile, precompiledViewsContents);
                    Process.Start("c:\\windows\\notepad.exe", temporaryPrecompiledViewFile);
                }
                catch (Exception err)
                {
                    throw new Exception("An error occured while trying to regenerate precompiled views for EF since the database changed. Error is: " + err);
                }
                throw new EntityCommandCompilationException($"The precompiled views file is not in sync with the database any longer. Replace the file {viewFileForMainDb} with the generated new contents!");
            }
        }
    }
}

The overall execution of code is the following:
  • In the DbContext constructor - check that the computed mapping hash value matches to that of the of the CSSpace storagemapping collection that your precompiled views file contains (MappingHashValue)
  • If the hash values do not agree, it is necessary to regenerate the pre compiled views file again. The contents are generated and written to a temporary file.
  • Notepad or similar is launched telling the developer to replace the pre compiled views file contents with this new contents.
  • An EntityCommandCompilationException is thrown as this is the same type of exception that is thrown if the precompiled views file does not agree
  • Developer replaces the contents and rebuilds the solution
  • The next time the startup time of EF should be reduced significantly again and work, since our DbContext and precomplied views are in sync again
Below is a sample of an exception thrown when my DbContext was not in sync with the precompiled views file:


System.Data.Entity.Core.EntityCommandCompilationException

System.Data.Entity.Core.EntityCommandCompilationException
  HResult=0x8013193B
  Message=An error occurred while preparing the command definition. See the inner exception for details.
  Source=EntityFramework
  StackTrace:
   at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition..ctor(DbProviderFactory storeProviderFactory, DbCommandTree commandTree, DbInterceptionContext interceptionContext, IDbDependencyResolver resolver, BridgeDataReaderFactory bridgeDataReaderFactory, ColumnMapFactory columnMapFactory)
   at System.Data.Entity.Core.EntityClient.Internal.EntityProviderServices.CreateDbCommandDefinition(DbProviderManifest providerManifest, DbCommandTree commandTree, DbInterceptionContext interceptionContext)
   at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlanFactory.CreateCommandDefinition(ObjectContext context, DbQueryCommandTree tree)
   at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlanFactory.Prepare(ObjectContext context, DbQueryCommandTree tree, Type elementType, MergeOption mergeOption, Boolean streaming, Span span, IEnumerable`1 compiledQueryParameters, AliasGenerator aliasGenerator)
   at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()
   at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
   at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
   at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
   atProgram.cs:line 164

Inner Exception 1:
MappingException: The current model no longer matches the model used to pre-generate the mapping views, as indicated by the ViewsForBaseEntitySetsabf8c33ac61e42fc601fe7446b41eaf48c7577efe6d6e17ccccc2b434793c28e.MappingHashValue property. Pre-generated mapping views must be either regenerated using the current model or removed if mapping views generated at runtime should be used instead. See http://go.microsoft.com/fwlink/?LinkId=318050 for more information on Entity Framework mapping views.

 

Tuesday, 30 April 2019

Finding databases with biggest tables in SQL Server

I created a T-SQL script today for use with SQL Server that will list the tables that have most rows for SQL Server, able to loop through all databases.

DECLARE @currentDB AS VARCHAR(100)
DECLARE @mrsdb_sqlscript AS NVARCHAR(500)
DECLARE db_cursor CURSOR FOR 
SELECT name from sys.databases where state_desc <> 'offline' and name not in ('master', 'tempdb', 'model', 'msdb') order by name 
DROP TABLE IF EXISTS #largestTables 
CREATE TABLE #largestTables (
 DatabaseName VARCHAR(100),
 SchemaName VARCHAR(200), 
 TableName VARCHAR(200), 
 TotalRowCount INT 
)

OPEN db_cursor 
FETCH NEXT from db_cursor into @currentDB 

WHILE @@FETCH_STATUS = 0 
BEGIN
 SET @mrsdb_sqlscript = N'INSERT INTO #largestTables 
  SELECT ''' + @currentDB + ''' , SCHEMA_NAME(schema_id) AS [SchemaName],
 [Tables].name AS [TableName],
 SUM([Partitions].[rows]) AS [TotalRowCount]
 FROM ' + @currentDB + '.sys.tables AS [Tables]
 JOIN ' + @currentDB + '.sys.partitions AS [Partitions]
 ON [Tables].[object_id] = [Partitions].[object_id]
 AND [Partitions].index_id IN ( 0, 1 )
 GROUP BY SCHEMA_NAME(schema_id), [Tables].name';

 PRINT 'Looking for largest table in the following DB: ' + @currentDB 
 exec sp_executesql @mrsdb_sqlscript 

 FETCH NEXT FROM db_cursor into @currentDB
END

CLOSE db_cursor 
DEALLOCATE db_cursor 

SELECT TOP 100 * FROM #largestTables 
ORDER BY TotalRowCount DESC, Schemaname ASC


The SQL script above will use a temporary table variable and database cursor and loop through all databases, executing a SQL script that will insert data into a temporary table variable and after the cursor has looped through its dataset, the result in the temporary table variable is presented to the DBA monitoring. Use it to spot where you have much data in your databases of the data base server you are working with!

Friday, 29 March 2019

Quickly search your Git log using wildcards and shell function

Imagine you got a Git repository with a long history - equivalent to log - and you want find a changeset with a comment containing a word or some words and you want to get the commit SHA to quickly cherry pick that commit to your target branch. This is easier using Azure Devops or some tool, but how to quickly search the log. First we define a search log shell function inside our git config file .gitconfig :

searchlog = "!f() { git --no-pager log --color-words --all --decorate --graph -i --grep \"$1\";  }; f"

Now we can search the log quickly using a wildcard:
git searchlog "visning.*av.*nåtidslinje.*"
We separate our search words with the .* regex syntax and we can search our git log for multiple keywords quickly and get a nice presentation of commits with commit messages matching our log. And now we have a quick way to find our Git commits through the log and the command line to overcome our needly in the haystack scenario.

Monday, 25 March 2019

Importing datetime columns from Excel into SPSS

I have been working with SPSS and Excel import the latest days. The following Python script written in SPSS will import your Excel datetime columns properly.

* Encoding: UTF-8.
begin program.
import spss
print "Variable count: " + str(spss.GetVariableCount())
previousVar=""
for ind in range(spss.GetVariableCount()): #Loop through variable indices
    if (ind < 0): 
     previousVar = spss.GetVariableName(ind-1) #get variable name of previous column
    varNam = spss.GetVariableName(ind) #Look up each variable name
    
    recognizedDateColumns = ('date', 'lastupdate')
    if any(s in varNam.lower() for s in recognizedDateColumns): 
     print "Variable contains Dato: " + varNam
     adjustedVariable = varNam + "_Justert"
     spss.Submit("COMPUTE " + adjustedVariable + " = DATE.MDY(1,1,1900) +( (" + varNam  + " - 2) * 24 * 60 * 60).")
     spss.Submit("FORMATS " + adjustedVariable + "(DATETIME22).")
     spss.Submit("RENAME VARIABLES (" + varNam + "=" + adjustedVariable + ") (" + adjustedVariable + "= " + varNam + ").")
     spss.Submit("ADD FILES FILE = * /KEEP=PasientGUID to " + previousVar + " " + varNam + " ALL.")
     spss.Submit("EXECUTE.")
     spss.Submit("DELETE VARIABLES " + adjustedVariable + ".")
     spss.Submit("EXECUTE.")   
end program.






Note that in my example I use the convention that a date column in my dataset contains 'date' or 'lastupdate'.

Tuesday, 26 February 2019

Powershell - starting and stopping multiple app pools

The following powershell script defines some functions in Powershell that can start up or stop all iis app pools on a server. It can be handy when you want to test out concurrency issues and switch off all IIS app pools and start up again.

Function fnStartApplicationPool([string]$appPoolName){
Import-Module WebAdministration 
 if ((Get-WebAppPoolState $appPoolName).Value -ne 'Started') {
  Write-Host 'IIS app pool ' $appPoolName ' is not started. Starting.' 
  Start-WebAppPool -Name $appPoolName 
  Write-Host 'IIS app pool ' $appPoolName 'started' 
 }
}

Function fnStartAllApplicationPools() {
Import-Module WebAdministration  
 Write-Host "Starting all app pools" 
 $appPools = (Get-ChildItem IIS:\AppPools)

foreach ($appPool in $appPools) { 
  & fnStartApplicationPool -appPoolName $appPool.Name
}
}

#fnStartAllApplicationPools #start all applications pools


Function fnStopApplicationPool([string]$poolname) {
Import-Module WebAdministration 
 if ((Get-WebAppPoolState $appPoolName).Value -ne 'Stopped') {
  Stop-WebAppPool -Name $appPoolName 
 }
}

Function fnStopAllApplicationPools(){
Import-Module WebAdministration  
 Write-Host "Starting all app pools" 
 $appPools = (Get-ChildItem IIS:\AppPools)

foreach ($appPool in $appPools) { 
  & fnStopApplicationPool-appPoolName $appPool.Name
}  

}

#fnStopAllApplicationPools #start all applications pools


Saturday, 23 February 2019

Serializing a data contract with xml declaration and indented formatting

This code will serialize your object graph and also do xml indentation and adding an xml declaration at the top, using DataContractSerializer.



public static string SerializeObjectIndented(T dataContract, bool omitXmlDeclaration = false) where T : class
{
 using (var output = new StringWriter())
 {
  using (var writer = new XmlTextWriter(output) { Formatting = Formatting.Indented })
  {
   if (!omitXmlDeclaration)
    writer.WriteStartDocument();
   var serializer = new System.Runtime.Serialization.DataContractSerializer(typeof(T));
   serializer.WriteObject(writer, dataContract);
   
   return output.GetStringBuilder().ToString();
  }
 }
}

To use it, just pass in your object and get an xml back!

Saturday, 5 January 2019

Debugging Create React App javascript and tests in Visual Studio Code

This is a handy collection of configurations for debugging your Create React App javscript code (launching Chrome) and also tests generated with Create React App (CRA). Note that the last one does not work probably if you have ejected the CRA. Here is the .vscode/launch.json file:

{
 // Use IntelliSense to learn about possible attributes.
 // Hover to view descriptions of existing attributes.
 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
 "version": "0.2.0",
 "configurations": [
  {
   "name": "Chrome debug 3000",
   "type": "chrome",
   "request": "launch",
   "url": "https://localhost:3000",
   "webRoot": "${workspaceRoot}/src"
  },
  {
   "name": "Debug CRA Tests",
   "type": "node",
   "request": "launch",
   "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/react-scripts",
   "args": [
    "test",
    "--runInBand",
    "--no-cache"
   ],
   "cwd": "${workspaceRoot}",
   "protocol": "inspector",
   "console": "integratedTerminal",
   "internalConsoleOptions": "neverOpen"
  }
 ]
}

Friday, 28 December 2018

Debugging http Node.js server requests and responses from shell

Here is a cool tip to inspect Node.js running an http process / server. First off, we start a simple http server in Node.js like this:

const http = require('http');

const server = http.createServer((req, res) => {
    res.end("

Why hello world!

\n"); }); server.listen(4242, () => { console.log("Server is running..."); });
This sets up a http server in Node.js. The http module is built-in in Node.js, we only have to require it (import in ES6). Now, just enter the following (I use Windows Subsystem for Linux - WSL in this case) in your shell to export NODE_DEBUG environment variable: export NODE_DEBUG=http We can now see requests and responses in our Node.js server! (Image below uses Wsl-Terminal as our terminal against WSL).

Sunday, 23 December 2018

Canceling Promise in Javascript

Canceling Promise in Js is a often sough after functionality, that can be provided by wrapping the Promise async function and provide canceling abilities. This will in functionality be similar to what we can do in C# with a CancellationTokenSource using in System.Threading.Task objects. We can invoke asynchronous function in Js with Promise, but if the user navigates away from a View or Page in for example React Native component, clicking a button to go to another Component, we must tidy up already started Promise operations such as fetch and here is the code to achieve that. First off, we define and export a makeCancelable method to be able to cancel a Promise.

/**
 * Wraps a promise into a cancelable promise, allowing it to be canceled. Useful in scenarios such as navigating away from a view or page and a fetch is already started.
 * @param {Promise}   promise           Promise object to cancel.
 * @return {Object with wrapped promise and a cancel function}
 */
export const makeCancelable = (promise) => {
    let hasCanceled = false;

    const wrappedPromise = new Promise((resolve, reject) => {
        promise.then(value => hasCanceled ? reject({ isCanceled: true }) : resolve(value),
            error => hasCanceled ? reject({ isCanceled: true }) : reject(error)
        );
    });

    return {
        promise: wrappedPromise,
        cancel() {
            hasCanceled: true;
        }
    };

};

The promise is wrapped with additional logic to check a boolean flag in a variable hasCanceled that either rejects the Promise if it is canceled or resolves the Promise (fullfils the async operation). Returned is an object in Js with the Promise itself in a primise attribute and the function cancel() which sets the boolean flag hasCanceled to true, effectively rejecting the Promise and rejecting it. Example usage below:

'use strict';

import React, { Component } from 'react';
import { TextInput, Text, View, StyleSheet, Image, TouchableHighlight, ActivityIndicator, FlatList, AsyncStorage } from 'react-native';
import AuthService from './AuthService';
import { makeCancelable } from './Util';

const styles = StyleSheet.create({
    container: {
        backgroundColor: '#F5FCFF',
        flex: 1,
        paddingTop: 40,
        alignItems: 'center'
    },
    heading: {
        fontSize: 30,
        fontWeight: '100',
        marginTop: 20
    },
    input: {
        height: 50,
        marginTop: 10,
        padding: 4,
        margin: 2,
        alignSelf: 'stretch',
        fontSize: 18,
        borderWidth: 1,
        borderColor: '#48bbec'
    },
    button: {
        height: 50,
        backgroundColor: '#48bbec',
        alignSelf: 'stretch',
        marginTop: 10,
        justifyContent: 'center'
    },
    buttonText: {
        fontSize: 22,
        color: '#FFF',
        alignSelf: 'center'
    },
    error: {
        fontWeight: '300',
        fontSize: 20,
        color: 'red',
        paddingTop: 10
    }
});

const cancelableSearchRepositoriesPromiseFetch = makeCancelable(fetch('https://api.github.com/search/repositories?q=react'));

class LoginForm extends Component {

    constructor(props) {
        super(props);

        this.state = {
            showProgress: false,
            username: '',
            password: '',
            repos: [],
            badCredentials: false,
            unknownError: false,
        };


    }

    onLoginPressed() {
        this.setState({ showProgress: true });

        var reposFound = [];

        var authService = new AuthService();

        authService.login({
            username: this.state.username, password: this.state.password
        }, (results) => {
            this.setState(Object.assign({ showProgress: false }, results));

            if (this.state.success && this.props.onLogin) {
                this.props.onLogin();
            }

        });




        cancelableSearchRepositoriesPromiseFetch.promise.then((response) => { return response.json(); })
            .then((results) => {
                results.items.forEach(item => {
                    reposFound.push(item);
                });
                this.setState({ repos: reposFound, showProgress: false });
            });
    }

    componentWillMount() {
        this._retrieveLastCredentials();
        cancelableSearchRepositoriesPromiseFetch.cancel();
    }

    _retrieveLastCredentials = async () => {

        var lastusername = await AsyncStorage.getItem("GithubDemo:LastUsername");
        var lastpassword = await AsyncStorage.getItem("GithubDemo:LastPassword");
        this.setState({ username: lastusername, password: lastpassword });
    }

    _saveLastUsername = async (username) => {
        if (username != null) {
            await AsyncStorage.setItem("GithubDemo:LastUsername", username);
        }
    }

    _savePassword = async (password) => {
        if (password != null) {
            await AsyncStorage.setItem("GithubDemo:LastPassword", password);
        }
    }

    componentWillUnmount() {

    }

    render() {


        var errorCtrl = <View />;

        if (!this.state.success && this.state.badCredentials) {
            errorCtrl = <Text color='#FF0000' style={styles.error}>That username and password combination did not work</Text>
        }

        if (!this.state.success && this.state.unknownError) {
            errorCtrl = <Text color='#FF0000' style={styles.error}>Unexpected error while logging in. Try again later</Text>
        }

        return (
            <View style={styles.container}>
                <Image style={{ width: 66, height: 55 }} source={require('./assets/Octocat.png')} />
                <Text style={styles.heading}>Github browser</Text>
                <TextInput value={this.state.username} onChangeText={(text) => { this._saveLastUsername(text); this.setState({ username: text }); }} style={styles.input} placeholder='Github username' />
                <TextInput value={this.state.password} textContentType={'password'} multiline={false} secureTextEntry={true} onChangeText={(text) => { this._savePassword(text); this.setState({ password: text }); }} style={styles.input} placeholder='Github password' />
                <TouchableHighlight style={styles.button} onPress={this.onLoginPressed.bind(this)}>
                    <Text style={styles.buttonText}>Log in</Text>
                </TouchableHighlight>
                {errorCtrl}
                <ActivityIndicator animating={this.state.showProgress} size={"large"} />
                <FlatList keyExtractor={item => item.id} data={this.state.repos} renderItem={({ item }) => <Text>{item.full_name}</Text>} />

            </View>
        );

    }


}

export default LoginForm; 


Thursday, 20 December 2018

React native - Checkboxes and date pickers for IoS

This article will look at checkboxes and date pickers for IoS apps in React Native. For checkboxes, we use the built-in Switch control. For Date pickers we use the built-in DatePickerIOS control.
This is the basic JS / JSX to get you started! Note the use of a basic state variable to keep track of the chosenDate. The onDateChange callback uses an arrow inline function to update the state variable. We also set the minimum and maximum datetime allowed and some othern nice props of the control! App.js

import React from 'react';
import { StyleSheet, Text, View, DatePickerIOS, Switch } from 'react-native';

export default class App extends React.Component {

  constructor(props){
    super(props);
    this.state = { chosenDate : new Date(), isDatePickerVisible: false };

    this.setDate = this.setDate.bind(this);
  }

  setDate(newDate){
    this.setState({chosenDate: newDate })
  }


  render() {
    return (
      <View style={styles.container}>
 
        <Switch onValueChange={(val) => this.setState({ isDatePickerVisible : val })} value={this.state.isDatePickerVisible} ios_backgroundColor={"aliceblue"} trackColor={true} />
        <Text style={{ display: this.state.isDatePickerVisible ? "none" : "flex"}}>Choose datetime..</Text>
          
        <View style={{ display: this.state.isDatePickerVisible ? "flex" : "none" }}>
         <DatePickerIOS locale="no" mode={"datetime"} minuteInterval={10} minimumDate={new Date(2018,11,1)} maximumDate={new Date(2018,11,31)}
          style={{ borderWidth: 1, borderColor: 'gray'}} onDateChange={this.setDate} date={this.state.chosenDate} />
         <Text>{this.state.chosenDate.toLocaleDateString() + " " + this.state.chosenDate.toLocaleTimeString()}</Text>
        </View>
  
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
  },
});





React Native apps with Expo - Radio buttons

This article will present how you can add Radio buttons into your React Native app. I am using Expo to build the React Native app and Visual Studio code as the editor and IDE. You can run this app by downloading the Expo app from App Store and run the following sample by opening the Camera on your mobile and scan the QR code. This will launch Expo app and run the app. WidgetDemos - React Native app with radio buttons demo First off, you can install Expo using npm and the following command: npm install expo-cli --global You can initialize a project using these two commands: expo init MyRadioButtonProject cd MyRadioButtonProject expo start Expo's website contains good documentation here: We can use the built in React Native control SegmentedControlIOS from React native and the following code:

import React, { Component } from 'react';
import { StyleSheet, Text, View, SegmentedControlIOS } from 'react-native';

export default class Widget extends Component {

    constructor(props) {
        super(props);

    this.state = {
            selectedMoreFruitIndex: 0,
        };

    }

    setMoreFruitIndex(event) {
        this.setState({ selectedMoreFruitIndex: event.nativeEvent.selectedSegmentIndex })
    };

   render(){

   return (
            <View>

                <SegmentedControlIOS
                    values={['banana', 'apple']}
                    selectedIndex={this.state.selectedMoreFruitIndex}
                    onChange={(event) => this.setMoreFruitIndex(event)}
                />

                
            </View >
        );

  };

..


The SegmentControlIOS is simple to get started with, but it is not so easy to set up with compound objects, it only supports a string array. Hence, you cannot specify a label and a value to each radio button item. Instead use the SegmentedControls from the 'react-native-radio-buttons' package. We import this npm package using: npm install react-native-radio-buttons --save The npm package has got a home and documentation here: https://www.npmjs.com/package/react-native-radio-buttons First off, we define an array of fruit objects and put these into a state variable (array of objects) inside the constructor

 constructor(props) { 
..
 let moreFruits = [{ label: 'Strawberry', value: 'Strawberry' },
        { label: 'Melon', value: 'Melon' },
        { label: 'Pineapple', value: 'Pineapple' },
        { label: 'Grapes', value: 'Grapes' },
        ];

        this.state = {
            selectedFruit: 'Pick your favorite fruit',
            selectedMoreFruitIndex: 0,
            selectedMoreFruit: null,
            moreFruits: moreFruits
        } 

.. }
We use the SegmentedControls by importing at the top and defining it inside the View returned in the render method:

import RadioButtons, { SegmentedControls } from 'react-native-radio-buttons'; //RadioButtons not needed in this example

//..inside views of render

  <SegmentedControls
                    options={this.state.moreFruits}
                    direction='row'
                    onSelection={option => this.setSelectedOption(option)}
                    selectedOption={this.state.selectedMoreFruit}
                    extractText={(option) => option.label}
                ></SegmentedControls>

The method setSelectedOption and more can be read in the code listing below of Widget.js. I include also App.js below, the starting component: Widget.js
import React, { Component } from 'react';
import { StyleSheet, Text, View, TextInput, Button, RadioGroup, TouchableWithoutFeedback, SegmentedControlIOS } from 'react-native';
import { Dropdown } from 'react-native-material-dropdown';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import RadioButtons, { SegmentedControls } from 'react-native-radio-buttons';

export default class Widget extends Component {

    constructor(props) {
        super(props);


        let moreFruits = [{ label: 'Strawberry', value: 'Strawberry' },
        { label: 'Melon', value: 'Melon' },
        { label: 'Pineapple', value: 'Pineapple' },
        { label: 'Grapes', value: 'Grapes' },
        ];

        this.state = {
            selectedFruit: 'Pick your favorite fruit',
            reasonFruit: '',
            isFruitButtonClicked: 'no',
            selectedMoreFruitIndex: 0,
            moreFruits: moreFruits
        }
    }

    setSelectedOption(selectedOption) {
        var selectedMoreFruit = this.state.moreFruits.find(item => item.label == selectedOption.label);
        this.setState({ selectedMoreFruit: selectedMoreFruit })
    }

    renderOption(option, selected, onSelect, index) {
        const style = selected ? { backgroundColor: 'blue' } : { backgroundColor: 'red' };

        return (
            <TouchableWithoutFeedback onPress={onSelect} key={index}>
                <Text style={style}>{option.label}</Text>
            </TouchableWithoutFeedback>
        );
    }

    renderContainer(optionNodes) {
        return <View>optionNodes</View>;
    }

    setMoreFruitIndex(event) {
        this.setState({ selectedMoreFruitIndex: event.nativeEvent.selectedSegmentIndex })
    }


    render() {
        let data = [
            { label: 'Banana', value: 'Banana' },
            { label: 'Apple', value: 'Apple' },
            { label: 'Kiwi', value: 'Kiwi' }

        ];

        return (
            <View>

                <SegmentedControlIOS
                    values={['one', 'two']}
                    selectedIndex={this.state.selectedMoreFruitIndex}
                    onChange={(event) => this.setMoreFruitIndex(event)}
                />

                <Text>Selected option of react-native-radio-buttons: {this.state.selectedMoreFruit ? this.state.selectedMoreFruit.value : 'no fruit'}</Text>

                <SegmentedControls
                    options={this.state.moreFruits}
                    direction='row'
                    onSelection={option => this.setSelectedOption(option)}
                    selectedOption={this.state.selectedMoreFruit}
                    extractText={(option) => option.label}
                ></SegmentedControls>

                <Text style={{ fontWeight: 'bold' }}>Select favorite fruit then</Text>
                <Dropdown onChangeText={(val) => this.setState({ selectedFruit: val })} style={{ backgroundColor: 'aliceblue' }} data={data} />
                <Text>You selected: {this.state.selectedFruit}</Text>
                <Text></Text>


                <Text>Reason for fruit choice: {this.state.reasonFruit}</Text>
                <TextInput onChangeText={(val) => this.setState({ reasonFruit: val })} style={{ borderColor: 'black', borderRadius: 4, borderWidth: 1, backgroundColor: 'aliceblue' }} value={this.state.reasonFruit}></TextInput>

                <Text></Text>




                {/* <Button color="#841584" accessibilityLabel="Click this button!" onPress={(val) => this.setState({ isFruitButtonClicked: 'yes' })} title="Fruit button" />
                <Text>Is Fruit button clicked: {this.state.isFruitButtonClicked}</Text> */}

            </View >
        );
    }

    sayHello(val) {
        this.setState({ selectedFruit: 'You selected: ' + val })
    }


}

App.js

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Widget from './Widget'
import { Col, Row, Grid } from 'react-native-easy-grid';

export default class App extends React.Component {
  render() {
    return (
      // Try setting `alignItems` to 'flex-start'
      // Try setting `justifyContent` to `flex-end`.
      // Try setting `flexDirection` to `row`.
      <View style={{
        flex: 1,
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'stretch',
      }}>
        <View style={{ width: '80%', height: 50 }}>
          <Text style={{ fontSize: 18, flexWrap: 'wrap' }} >Welcome to the React Native apps demo!</Text>
        </View>
        <View style={{ height: 150 }}>
          <Widget />
        </View>
        <View style={{ height: 100 }} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    flexDirection: 'column',
    backgroundColor: '#fff',
    alignItems: 'stretch'
  },
});


Lastly, remember to set the selected object in the correct manner, using the find method for example on the state variable. This to ensure we are pointing at the right selected object in the SegmentedControls control.

   setSelectedOption(selectedOption) {
        var selectedMoreFruit = this.state.moreFruits.find(item => item.label == selectedOption.label);
        this.setState({ selectedMoreFruit: selectedMoreFruit })
    }

Thursday, 22 November 2018

Displaying branch history in Git

I desired to have an easy branch log today. The following alias commands makes this easier. These go under the [alias] section in the .gitconfig file you are using in your repository.

latest = "!f() { echo "Latest \"${1:-11}\" commits accross all branches:"; git log  --abbrev-commit --date=relative --branches --all --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset%n' -n ${1:-11};  } ; f"
logbranch = "!f() { echo "Latest \"${1:-11}\" commits in current branch against master:"; git log master..${1:git branch}  --abbrev-commit --date=relative  --pretty=format:'%C(yellow)%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(white blue bold)<%an>%Creset%n' -n ${1:-11};  } ; f"

git logbranch will display only the latest commit for the specified branch or defaulting to the current branch, defaulting to last 11 commits using a shell function. Note that we compare against the master branch. And we get the following sample output: