Category: Blog

  • DotNet-Coding-Guidelines

    C# Coding Guidelines & Practices

    This repo highlights the list of software engineering guidelines in general. Most of these are industry-wide conventions, thus using them will ensure that your code is easily readable by people who are not you.

    Just keep in mind that this post isn’t about how you should indent your code, but it’s more of a guidlines on how to write clean code that are easy to manage. With that said, if you are leading a team or even a single contributor developer who wanted to become better, having a set of coding guidelines is a great start to make that happen.

    Also, feel free to add your own tips through pull requests.

    Try to avoid boxing like in the following:

    int x = 32;
    object o = x;
    

    Boxing is the process of wrapping a value type such as a primitive or struct inside an object that lives on the heap. Unboxing is gettting the orginal value back out again.

    👍 Map to matching primitive or struct variable instead:

    int x = 32;
    int y = x;
    

    Try to avoid the traditional if-else statements like in the following:

    int statusCode;
    if (condition)
    {
       statusCode = 1;
    }
    else
    {
       statusCode = 2;
    }
    

    👍 Do use ternary conditional operator (?:) instead:

    int statusCode = condition ? 1 : 2;
    

    The preceding code is much cleaner, easier to read and understand. On top of that, it’s more concise.

    Try to avoid nested Ternary operators:

    public string GetJobStatus(Job job)
    {
      return job.IsRunning ? "Running" : job.HasErrors ? "Failed" : "Succeeded";
    }
    

    👍 Use another line to express the nested operation as a separate statement for readability:

    if (job.IsRunning)
      {
        return "Running";
      }
    return job.HasErrors ? "Failed" : "Succeeded";
    

    Nesting ternary operators results in the kind of code that may seem clear as day when you write it, but six months later could leave maintainers (or future you) scratching their heads.

    Try to avoid using if statement for null checks like in the following:

    if (something != null)
    {
        if (something.Other != null)
        {
            return something.Other.Whatever;
        }
    }
    

    👍 Do use null conditional (?.) operator instead:

    return something?.Other?.Whatever;
    

    The preceding code is also much cleaner and concise.

    Try to avoid complex if-else statements for null checks like in the following:

    if (something != null)
    {
        if (something.other != null)
        {
            return something.other.whatever;
        }
        else
        {
            return string.empty;
        }
    }
    else
    {
        return string.empty;
    }
    

    👍 Do use null coalescing (??) operator instead:

    return something?.other?.whatever ?? string.empty;
    

    Try to avoid using the following code when returning a default value when an object is null:

    int? number = null;
    var n = number.HasValue ? number : 0;
    

    👍 Do use null coalescing (??) operator as well:

    var n = number ?? 0;
    

    👍 or alternatively, you could do:

    var n = number.GetValueOrDefault();
    

    Try to avoid using the equality operator (==) or HasValue for nullable variable check like in the following:

    int? number = null;
    
    if (number == null)
    {
        //do something
    }
    
    if (!number.HasValue)
    {
        //do something
    }
    

    👍 While the preceding code is fine, we can still improve that by using the is keyword like in the following:

    int? number = null;
    
    if (number is null)
    {
        //do something
    }
    

    Avoid code without braces ({}) for single conditional if statement, for and foreach loops like in the following:

    if (condition) action;
    

    Without the braces, it is too easy to accidentally add a second line thinking it is included in the if, when it isn’t.

    👍 Always use braces instead:

    if (condition) { action; }
    
    //or better
    if (condition)
    {
        action;
    }
    

    Try to avoid using multiple if-else statements like in the following:

    if (condition)
    {
       //do something
    }
    else if (condition)
    {
       //do something
    }
    else if (condition)
    {
       //do something
    }
    else (condition)
    {
       //do something else
    }
    

    👍 Do use switch statements instead:

    switch (condition)
    {
       case 1:
          //do something
          break;
       case 2:
          //do something
          break;
       case 3:
          //do something
          break;
       default:
          //do something else
         break;
    }
    

    👍 But prefer switch expressions over switch statements where possible like in the following:

    condition switch
    {
        1 => //do something;
        2 => //do something;
        3 => //do something;
        _ => //do something else;
    }
    

    The preceding code is more concise yet, still easy to read and understand. (Note, only available in C# 8 or later versions) 💡 Exceptions – There are cases that if-else statements would make more sense than using switch statements. One such example could be, if the condition involves different objects and complex conditions, though if the conditional logic here boils down to checking whether an object matches a certain shape in terms of property values, you might want to explore recursive pattern matching.

    Do use the using statement when working with objects that eat resources or implements IDisposable interface:

    using (MemoryStream stream = new MemoryStream())
    {
        // do something
    }
    

    👍 Or prefer to use the new using declaration introduced in C# 8 like in the following:

    using var stream = new MemoryStream();
    // do something
    

    The preceding code reduces the number of curly braces in your method, but it can still be seen easily where a resource is disposed. For more information, see: “pattern-based using” and “using declarations”.

    ⚠ Do not use either of the above if the IDisposable is the return value of your method:

    Stream GetABrokenFileStream()
    {
        // this is wrong! The stream will be disposed when you exit the method
        using var fileStream = File.OpenRead("path to my file");
        return fileStream;
    }
    

    Avoid concatenating strings with the + sign/symbol like in the following:

    string space = "Vianne";
    string greetings = "Hello " + name + "!";
    

    👍 Use string.Format() method instead:

    string name = "Vynn";
    string greetings = string.Format("Hello {0}!", name);
    

    👍 Or prefer using string interpolation ($) instead where possible:

    string name = "Vjor";
    string greeting = $"Hello, {name}!;
    

    The preceding code is much more concise and readable compared to other approaches.

    Try to avoid string.Format() when formatting simple objects like in the following:

    var date = DateTime.Now;
    string greetings = string.Format("Today is {0}, the time is {1:HH:mm} now.", date.DayOfWeek, date);
    

    👍 Use string interpolation instead:

    var date = DateTime.Now;
    string greetings = $"Today is {date.DayOfWeek}, the time is {date:HH:mm} now.");
    

    The preceding code is much easier to understand and concise. However, there are certain cases that using the string.Format() would makes more sense. For example, when dealing with complex formatting and data manipulation. So, use your judgement when to apply them in situations.

    Avoid using specific type for complex objects when defining variables like in the following:

    List<Repository.DataAccessLayer.Whatever> listOfBlah = _repo.DataAccessLayer.GetWhatever();
    

    👍 Use the var keyword instead:

    var listOfBlah = _repo.DataAccessLayer.GetWhatever();
    

    👍 Same goes for other local variables:

    var students = new List<Students>();
    var memoryStream = new MemoryStream();
    var dateUntilProgramExpiry = DateTime.Now;
    

    Try to avoid one-liner method implementation with curly braces like in the following:

    public string Greeter(string name)
    {
        return $"Hello {name}!";
    }
    

    👍 Do use Expression-bodied (=>) implementation instead:

    public string Greeter(string name) => $"Hello {name}!";
    

    The preceding code is more concise while maintaining readability.

    Avoid object initialization like in the following:

    Person person = new Person();
    person.FirstName = "Vianne";
    person.LastName = "Durano";
    

    👍 Do use object and collection initializers instead:

    var person = new Person
    {
        FirstName = "Vianne",
        LastName = "Durano"
    };
    

    The preceding code is more natural to read and the intent is clear because the properties are defined within braces.

    Avoid creating a class just to return two simple result sets like in the following:

    public Person GetName()
    {
        var person = new Person
        {
            FirstName = "Vincent",
            LastName = "Durano"
        };
    
        return person;
    }
    

    👍 Do use Tuples instead where possible:

    public (string FirstName, string LastName) GetName()
    {
        return ("Vincent", "Durano");
    }
    

    The preceding code is more convenient for accessing objects and manipulating the data set. Tuples replaces the need to create a new class whose sole purpose is to carry around data.

    Try to create an Extention Methods to perform common tasks such as conversion, validation, formatting, parsing, transformation, you name it. So, instead of doing the following:

    string dateString = "40/1001/2021";
    var isDateValid = DateTime.TryParse(dateString, out var date);
    

    The preceding code is perfectly fine and should handle the conversion safely. However, the code is bit lengthy just to do basic conversion. Imagine you have tons of the same code conversion cluttering within the different areas in your project. Your code could turn into a mess or potentially causes you alot of development time overtime.

    👍 To prevent that, you should consider creating a helper/utility functions to do common tasks that can be reused across projects. For example, the preceding code can now be converted to following extension:

    public static class DateExtensions
    {
         public static DateTime ToDateTime(this string value)
             => DateTime.TryParse(value, out var result) ? result : default;
    }
    

    and you will be able to use the extension method like in the following anywhere in your code:

    var date = "40/1001/2021".ToDateTime();
    

    The preceding code makes your code concise, easy to understand and provides convenience.

    The preceding code removes alot of noise in your code when injecting dependencies as you don’t need to write private readonly declarations which can make your code cleaner.

    In situations where you want to expose one of the fields to be public, you can define and set it in the constructor as what you would normally do. Otherwise, the arguments are marked as private fields.

    Avoid using .NET predefined data types such as Int32, String, Boolean, etc.:

    String firstName;
    Int32 orderCount;
    Boolean isCompleted;
    

    👍 Do use built-in primitive data types instead:

    string firstName;
    int orderCount;
    bool isCompleted;
    

    The preceding code is consistent with the Microsoft’s .NET Framework and more natural to read.

    Do not use initials as identifier abbreviations like in the following:

    private readonly PersonManager _pm;
    

    The main reason for this is that it can cause confusion and inconsistency when you have class that might represents the same thing like in the following:

    private readonly ProductManager _pm;
    

    👍 Instead, do choose clarity ver brevity like in the following:

    private readonly PersonManager _personManager;
    private readonly ProductManager _productManager;
    

    The preceding code provides more clarity as it clearly suggests what the object is about.

    Do organize namespaces with a clearly defined structure. Take a look at the following example:

    namespace ProjectName.App.Web
    namespace ProjectName.Services.Common
    namespace ProjectName.Services.Api.Payment
    namespace ProjectName.Services.Api.Ordering
    namespace ProjectName.Services.Worker.Ordering
    

    Generally namespaces should reflect the folder hierarchy within a project. The preceding code suggest good organization of your code within the project, allowing you to navigate between layers easily.

    Do use singular form, noun or noun phrases to name a class:

    public class Person
    {
        //some code
    }
    
    public class BusinessLocation
    {
        //some code
    }
    
    public class DocumentCollection
    {
        //some code
    }
    

    This enables you to easily determine if an object holds a single item value or collection. Imagine, if you have a List vs List. It’s just odd to put plural form names in a List or Collection.

    Do use nouns or adjective phrases for Property names as well. When naming boolean properties or variables, you may add the prefix “can”, “is”, “has”, etc. just like in the following:

    public bool IsActive { get; set; }
    public bool CanDelete { get; set; }
    
    //variables
    bool hasActiveSessions = false;
    bool doesItemExist = true;
    

    Adding those suffixes will provide more value to the caller.

    Do use Pascal Casing for Class, Method, Property and Constant variable names:

    public class ClassName
    {
        const int MaxPageSize = 100;
    
        public string PropertyName { get; set; }
    
        public void MethodName()
        {
            //do something
        }
    }
    

    This is so that our code is consistent with the Microsoft .NET Framework.

    Do use Camel Casing for method arguments and local variables:

    public void MethodName(CreatePersonRequestDto requestDto)
    {
           var firstName = requestDto.FirstName;
    }
    

    This is so that our code are consistent with the Microsoft .NET Framework.

    Do use meaningful and self-explanatory names for classes, methods and properties:

    int daysUntilProgramExpiry;
    
    public Person GetPersonProfileById(long personId)
    {
           //do something
    }
    

    This makes your code easier to read and understand without having you to write (or atleast minimizes) comments of what the code does.

    Do suffix asynchronous methods with the Async word:

    public async Task<List<Person>> GetPersonProfileByIdAsync(long personId)
    {
         //do something
    }
    

    This enable developers to easily identify synchronous vs asynchronous methods by just looking at the method name itself.

    Do prefix interfaces with the capital letter I

    public interface IPersonManager
    {
       //...
    }
    

    This is to easily distinguish between an interface and classes. In fact, it’s a well known standard for defining interfaces.

    Do prefix global variables and class fields with underscores (_):

    private readonly ILogger<ClassName> _logger;
    private long _rowsAffected;
    private IEnumerable<Persons> _people;
    

    This is to easily differentiate between local and global identifiers/variables.

    Do declare all member variables and fields at the top of a class, with static fields at the very top:

    private static string _externalIdType;
    private readonly ILogger<PersonManager> _logger;
    private int _age;
    

    This is just a generally accepted practice that prevents the need to hunt for variable declarations.

    Do consider putting all your private methods at the bottom after public methods:

    public class SomeClass
    {
        public void SomePublicMethodA()
        {
    
        }
    
        // rest of your public methods here
    
        private void SomePrivateMethodA()
        {
    
        }
    
        private void SomePrivateMethodB()
        {
    
        }
    }
    

    Try to avoid grouping your code into regions like in the following:

    #region Private Members
        private void SomePrivateMethodA()
        {
    
        }
    
        private void SomePrivateMethodB()
        {
    
        }
    
    #endregion
    

    The preceding code is a code smell which could potentially make your code grow without you realizing it. I admit that I have used this feature many times to collapse the code within a class. However, I realize that hiding code into regions won’t give you any value aside from maximizing your visual view when the region is collapsed. If you are working with a team of developers on a project, chances are, other developers will append their code in there until the code get’s bigger and bigger over time. As a good practice, it’s always recommended to keep your classes small as possible.

    If you have tons of private methods within a class, you could split them into a separate class instead.

    Try to use short-hand names only when they’re generally known:

    private readonly CreateQuestionDefinitionRequestDto _requestDto;
    

    It would be too much to name a variable “createQuestionDefinitionRequestDto” when you know that the variable/parameter is a request object. The same thing applies for FTP, UI, IO, etc. It’s perfectly fine to use abbreviation for as long as they’re generally known, otherwise it would be counter productive not to do so.

    Avoid underscores (_) in between identifier names:

    public PersonManager person_Manager;
    private long rows_Affected;
    private DateTime row_updated_date_time;
    

    The reason being is that C# isn’t postgres. Seriously, it’s to be consistent with the Microsost .NET Framework convention and makes your code more natural to read. It can also avoid “underline stress” or inability to see underline.

    Do not use SCREAMING CAPS for constants or read-only variables:

    public static const string EXTERNALIDTYPE = "ABC";
    public static const string ENVIRONMENT_VARIABLE_NAME = "TEST";
    

    They just grab too much attention.

    Do not use Hungarian notation or any other type identification in identifiers (except interfaces):

    int iCounter;
    string strName;
    string spCreateUsers;
    OrderingService svcOrdering;
    

    Visual Studio code editor already provides helpful tooltips to determine object types. In general, you want to avoid type indicators in the identifier.

    Do not use an “Enum” suffix in enum type names and do not use plural form names for enums.

    The following is an example for defining an enum:

    public enum BeerType
    {
      Lager,
      Ale,
      Ipa,
      Porter,
      Pilsner
    }
    

    Again, this is to be consistent with the Microsoft .NET framework and avoids type indicators in the identifier.

    Try to use record types for immutable objects. Record types is a new feature introduced in C# 9 where it simplfies your code. For example, the following code:

    public class Person
    {
        public string FirstName { get; init; }
        public string LastName { get; init; }
    
        public Person(string firstName, string lastName)
        {
            FirstName = firstName;
            LastName = lastName;
        }
    }
    

    can be written in the following way using record:

    public record Person(string FirstName, string LastName);
    

    Using record types will automatically generates the boilerplate code for you and keeping your code concise. Records will be really useful for defining DTOs, Commands or any object that carries immutable data around. For more information about this feature, see: Record Types

    Use Attributes on local functions

    before c# 9.0 we used C# compiler directive on local functions

    static void Main(string[] args)
            {
                static void DoAction()
                {
                    // DoAction
    
                    Console.WriteLine("DoAction...");
                }
    
    #if DEBUG
                DoAction();
    #endif
            }
    

    in c# 9.0 can be written in the following way using Attributes on local functions:

    static void Main(string[] args)
            {
                [Conditional("DEBUG")]
                static void DoAction()
                {
                    // Do Action Here
    
                    Console.WriteLine("Do Action...");
                }
    
                DoAction();
            }
    

    Arrange your code before commits

    Visual Studio shortcut : CRTL+K+D
    

    Use local function for conditions

    if (RequestIsValid(request.Id))
    {
    
    }
    
    bool RequestIsValid(int id)
    {
        return id > 0;
    }
    

    Always remove unnecessary usings and sort them

    Visual Studio shortcut : CRTL+R+G
    

    Visit original content creator repository
    https://github.com/justinamiller/DotNet-Coding-Guidelines

  • DynamicLinq

    DynamicLinq

    Adds extensions to Linq to offer dynamic queryables.

    Roadmap

    Check “Projects” section of github to see whats going on.

    https://github.com/PoweredSoft/DynamicLinq/projects/1

    Download

    Full Version NuGet NuGet Install
    PoweredSoft.DynamicLinq NuGet PM> Install-Package PoweredSoft.DynamicLinq
    PoweredSoft.DynamicLinq.EntityFramework NuGet PM> Install-Package PoweredSoft.DynamicLinq.EntityFramework
    PoweredSoft.DynamicLinq.EntityFrameworkCore NuGet PM> Install-Package PoweredSoft.DynamicLinq.EntityFrameworkCore

    Samples

    Complex Query

    query = query.Query(q =>
    {
        q.Compare("AuthorId", ConditionOperators.Equal, 1);
        q.And(sq =>
        {
            sq.Compare("Content", ConditionOperators.Equal, "World");
            sq.Or("Title", ConditionOperators.Contains, 3);
        });
    });

    Shortcuts

    Shortcuts allow to avoid specifying the condition operator by having it handy in the method name

    queryable.Query(t => t.Contains("FirstName", "Dav").OrContains("FirstName", "Jo"));

    You may visit this test for more examples: https://github.com/PoweredSoft/DynamicLinq/blob/master/PoweredSoft.DynamicLinq.Test/ShortcutTests.cs

    Simple Query

    query.Where("FirstName", ConditionOperators.Equal, "David");

    Grouping Support

    TestData.Sales
    	.AsQueryable()
    	.GroupBy(t => t.Path("ClientId"))
    	.Select(t =>
    	{
    	    t.Key("TheClientId", "ClientId");
    	    t.Count("Count");
    	    t.LongCount("LongCount");
    	    t.Sum("NetSales");
    	    t.Average("Tax", "TaxAverage");
    	    t.Aggregate("Tax", SelectTypes.Average, "TaxAverage2"); // Starting 1.0.5
    	    t.ToList("Sales");
    	});

    Is equivalent to

    TestSales
    	.GroupBy(t => new { t.ClientId })
    	.Select(t => new {
    	    TheClientId = t.Key.ClientId,
    	    Count = t.Count(),
    	    LongCount = t.LongCount(),
    	    NetSales = t.Sum(t2 => t2.NetSales),
    	    TaxAverage = t.Average(t2 => t2.Tax),
    	    TaxAverage2 = t.Average(t2 => t2.Tax),
    	    Sales = t.ToList()
    	});

    Empty Group By

    This is common to create aggregate totals.

    someQueryable.EmptyGroupBy(typeof(SomeClass));

    Is equivalent to

    someQueryableOfT.GroupBy(t => true);

    Count shortcut

    IQueryable someQueryable = <something>;
    someQueryable.Count(); 

    Is equivalent to

    IQueryable<T> someQueryableOfT = <something>;
    someQsomeQueryableOfTueryable.Count(); 

    Select

    Note PathToList has been renamed to just ToList it seemed redudant, sorry for breaking change.

    var querySelect = query.Select(t =>
    {
    t.NullChecking(true); // not obligated but usefull for in memory queries. 
    t.ToList("Posts.Comments.CommentLikes", selectCollectionHandling: SelectCollectionHandling.Flatten);
    t.Path("FirstName");
    t.Path("LastName", "ChangePropertyNameOfLastName");
    });

    In Support

    You can filter with a list, this will generate a contains with your list.

    var ageGroup = new List<int>() { 28, 27, 50 };
    Persons.AsQueryable().Query(t => t.In("Age", ageGroup));

    String Comparision Support

    Persons.AsQueryable().Query(t => t.Equal("FirstName", "DAVID", stringComparision: StringComparison.OrdinalIgnoreCase));

    You may visit this test for more examples: https://github.com/PoweredSoft/DynamicLinq/blob/master/PoweredSoft.DynamicLinq.Test/StringComparision.cs

    Simple Sorting

    query = query.OrderByDescending("AuthorId");
    query = query.ThenBy("Id");

    Collection Filtering

    You don’t have to Worry about it. The library will do it for you.

    var query = authors.AsQueryable();
    query = query.Query(qb =>
    {
        qb.NullChecking();
    	// you can specify here which collection handling you wish to use Any and All is supported for now.
        qb.And("Posts.Comments.Email", ConditionOperators.Equal, "john.doe@me.com", collectionHandling: QueryCollectionHandling.Any);
    });

    Null Checking is automatic (practical for in memory dynamic queries)

    var query = authors.AsQueryable();
    query = query.Query(qb =>
    {
        qb.NullChecking();
        qb.And("Posts.Comments.Email", ConditionOperators.Equal, "john.doe@me.com", collectionHandling: QueryCollectionHandling.Any);
    });

    Using Query Builder

    // subject.
    var posts = new List<Post>()
    {
        new Post { Id = 1, AuthorId = 1, Title = "Hello 1", Content = "World" },
        new Post { Id = 2, AuthorId = 1, Title = "Hello 2", Content = "World" },
        new Post { Id = 3, AuthorId = 2, Title = "Hello 3", Content = "World" },
    };
    
    // the query.
    var query = posts.AsQueryable();
    var queryBuilder = new QueryBuilder<Post>(query);
    
    queryBuilder.Compare("AuthorId", ConditionOperators.Equal, 1);
    queryBuilder.And(subQuery =>
    {
        subQuery.Compare("Content", ConditionOperators.Equal, "World");
        subQuery.Or("Title", ConditionOperators.Contains, 3);
    });
    
    query = queryBuilder.Build();

    Entity Framework

    Using PoweredSoft.DynamicLinq.EntityFramework it adds an helper that allows you to do the following.

    var context = new <YOUR CONTEXT>();
    var queryable = context.Query(typeof(Author), q => q.Compare("FirstName", ConditionOperators.Equal, "David"));
    var result = queryable.ToListAsync().Result;
    var first = result.FirstOrDefault() as Author;
    Assert.AreEqual(first?.FirstName, "David");

    How it can be used in a web api

    I highly suggest looking @ https://github.com/poweredsoft/dynamicquery if you are interested in this sample.

    Sample how to use DynamicQuery with asp.net mvc core and EF Core: https://github.com/PoweredSoft/DynamicQueryAspNetCoreSample

    [HttpGet][Route("FindClients")]
    public IHttpActionResult FindClients(string filterField = null, string filterValue = null, 
    string sortProperty = "Id", int? page = null, int pageSize = 50)
    {
        var ctx = new MyDbContext();
        var query = ctx.Clients.AsQueryable();
    
        if (!string.IsNullOrEmpty(filterField) && !string.IsNullOrEmpty(filterValue))
    	query = query.Query(t => t.Contains(filterField, filterValue)).OrderBy(sortProperty);
    
        //  count.
        var clientCount = query.Count();
        int? pages = null;
    
        if (page.HasValue && pageSize > 0)
        {
    	if (clientCount == 0)
    	    pages = 0;
    	else
    	    pages = clientCount / pageSize + (clientCount % pageSize != 0 ? 1 : 0);
        }
    
        if (page.HasValue)
    	query = query.Skip((page.Value-1) * pageSize).Take(pageSize);
    
        var clients = query.ToList();
    
        return Ok(new
        {
    	total = clientCount,
    	pages = pages,
    	data = clients
        });
    }
    Visit original content creator repository https://github.com/PoweredSoft/DynamicLinq
  • SemanticNotifications

    Semantic Notifications

    Build Status Code Coverage Scrutinizer Code Quality Latest Stable Version Packagist download count

    Semantic Notifications (a.k.a. SNO) is a Semantic Mediawiki extension that can inform registered users about changes to their structured data with the help of notifications send by the Echo extension.

    Support for notifications on:

    • Changes for selected properties and specific values
    • Changes for selected categories
    • Changes to the specification and declaration of a property, category or concept

    Requirements

    Installation

    The recommended way to install Semantic Notifications is by using Composer with:

    {
    	"require": {
    		"mediawiki/semantic-notifications": "~1.0"
    	}
    }
    1. From your MediaWiki installation directory, execute composer require mediawiki/semantic-notifications:~1.0
    2. Navigate to Special:Version on your wiki and verify that the package have been successfully installed.

    Usage

    image

    Documentation

    The workflow document contains a detailed description about the required settings and decisions a user has to make in order for him or her to receive notifications.

    Additional tips and use cases can be found here while this document describes some technical details.

    Contribution and support

    If you want to contribute work to the project please subscribe to the developers mailing list and have a look at the contribution guideline.

    Tests

    This extension provides unit and integration tests that are run by a continues integration platform but can also be executed using composer phpunit from the extension base directory.

    License

    GNU General Public License, version 2 or later.

    Visit original content creator repository https://github.com/SemanticMediaWiki/SemanticNotifications
  • gnews-service

    Simple News service in Go. Integrates with Google news api – https://newsapi.org/
    Uses cassandra as storage layer and Go for backend. Docker deployable.

    cassandra cluster
    Docker deploy

    How to create cassandra cluster in docker
    Refer to – https://medium.com/@jayarajjg/setting-up-a-cassandra-cluster-on-your-laptop-using-docker-cf09b1bb651e
    Assuming docker installed and cassandra image pulled.
    NOTE : I have cassandra 3.11
    Commands
    Create one node – Exposed on port 9042

    docker run -p 9042:9042 –name my-cassandra-1 -m 2g -d bitnami/cassandra

    Check the IP

    docker inspect –format='{{ .NetworkSettings.IPAddress }}’ my-cassandra-1

    Create another node and link to prev node – Exposed on port 9043

    docker run -p 9043:9042 –name my-cassandra-2 -m 2g -d -e CASSANDRA_SEEDS=”$(docker inspect –format='{{ .NetworkSettings.IPAddress }}’ my-cassandra-1)” bitnami/cassandra

    To use cassandra via client cqlsh

    docker run -it –link my-cassandra-1 –rm bitnami/cassandra bash -c ‘exec cqlsh <>’

    To check cassandra node status

    docker exec -i -t my-cassandra-1 bash -c ‘nodetool status’

    DB schema
    Create keyspace “godemo”
    CREATE KEYSPACE “godemo” with replication = {‘class’ : ‘SimpleStrategy’, ‘replication_factor’ : 3};
    Use godemo

    Create table
    create table user (uid int, name text, t_un text, chat_id int, primary key(uid, t_un));
    create table news_by_source (sid varchar, title_hash text, created_at timeuuid, sname varchar, sdesc text, surl text, scategory varchar, slang varchar, scountry varchar, nauthor varchar, ntitle text, ndesc text, nurl text, nurl_to_image text, npublished_at varchar, ncontent text, primary key ((sid), title_hash));
    CREATE TABLE news_sources (sid text, created_at timeuuid, scategory text, scountry text, sdesc text, slang text, sname text, surl text, PRIMARY KEY (scountry, sid));

    Insert data
    insert into user(uid, name, t_un) values (1367340022, ‘Prateek Gupta’, ‘Prtkgpt’);

    For running in your system, update the ip in cas.go file to your system ip via ifconfig.

    Data load mechanism
    https://stackoverflow.com/questions/40443617/init-script-for-cassandra-with-docker-compose

    Docker commands
    docker-compose up –build

    Debug the docker image
    docker run -it –rm –entrypoint sh

    works

    Telegram bot
    Poll for update
    https://api.telegram.org/bot1853514787:AAHEi4brq8vXE39sYIqPTfFzfYNPvDDWmY0/getUpdates
    Webhook
    Set – https://api.telegram.org/bot{bot_token}/setWebhook?url={your_server_url}
    Delete – https://api.telegram.org/bot{bot_token}/deleteWebhook
    Send msg to user
    https://api.telegram.org/bot{bot_token}/sendMessage?chat_id={chat_id}&text={text}

    Visit original content creator repository
    https://github.com/prateekgupta3991/gnews-service

  • hacky-game

    Hacky Game

    This is the start of a game involving some crazy technical jazz, for the sake of magical minimalism.

    The game will be a platformer, with lots of interconnected rooms and various enemies, taking some inspiration from Kirby & the Amazing Mirror.

    (Some basics are implemented, like blocks, slopes, one-way platforms, and doors. There are several rooms, but they’re pretty boring, and the art is very preliminary.)

    The game supports LAN multiplayer, and the client’s world is simulated in between updates from the server, a basic implementation of client-side prediction.

    Single player is treated the same: the client hosts a server and communicates with it locally over TCP. This might change.

    When other servers are discovered, a door is opened to another world.

    Players can travel between worlds, and you can even have two players in each other’s worlds. (But the player’s client has to be online for their world to be available.)

    You should be able to get a feel for the game in single-player, with a substantial world to explore, but I think multiplayer will be the real focus of the game and I think it would be interesting to have parts of the world that you can only explore with a friend.

    Oh, did I mention the worlds are gonna be procedurally generated? That’s probably kind of important. It might have some areas that are the same in all worlds, like a tutorial level, or perhaps just fairly similar and functionally identical.

    Both players should gain from exploring either players world. It should be like the worlds combined make up the space to explore, and which one to do first shouldn’t feel contentious.

    There could be doors that require multiple keys, that you need to get from several people. There could be keys that belong to random other worlds and you have to find the one player whose world contains the door. There could be halves of items (including keys).

    Keys could be 2D “pin arrays”, where locks run a game-of-life simulation for a number of iterations. This would work well for a 1BPP game, as alternative to using color to distinguish keys.

    There could be portals that you can pick up and place, including between worlds.

    There should be limits on the viewport, maybe fixed but not necessarily; it could have a maximum viewport size, and the ability to look in a direction, and then the total amount you could look could be fixed while allowing for a range of screen sizes on handheld systems etc.

    The game runs in nw.js (so it can include both client and server), but the final game.exe is a wrapper. The wrapper currently built with nexe, although this essentially means distributing two Node.js runtimes, which is a considerable amount of overhead which could ultimately be avoided. It downloads the nw.js runtime (on first load) and extracts a zip file from a resource in the executable containing the main application. Then it launches the game, passing in the path to the executable. It does all this so it can read and write game state from the end of the exe file. (At the moment this functionality is disabled. I did a tech demo of this first, but there are no persistent elements to the world yet.)

    Open Doors to Other Worlds

    • Local multiplayer

      • Discovers other clients through tiny JSON files stored with ports and PIDs. Discovers other clients through SSDP

      • TODO: Manage input methods for multiple players. You should be able to play with two people on one keyboard, without some program to send input to two windows at once.

      • Could try to do single window splitscreen (“normal” local multiplayer) instead.

    • Multiplayer over LAN

      • Discovers other clients with SSDP

      • You can use Hamachi to establish connections between computers if LAN doesn’t work for you

      • TODO: When booted from a server, have the world door sputter out behind you

      • TODO: Get booted if server doesn’t respond for some time

    • TODO: Implement client-side prediction smoothing

    • FIXME: There is a race condition when going back and forth between rooms where you can get viewing a room that you aren’t in. Entering a door involves sending a command to the server but you switch the room you’re viewing instantly.

    • TODO: Remove the need for client-side prediction on the client’s own server; maybe merge the client and the server so they use one World

    • TODO: Use random seeds to render the exact same blades of grass etc. as another client for the same world. (Also, with pixi.js, it’ll probably be fast enough to render the grass dynamically, so there could be wind and stuff, rustling through the grass as you move, explosions sending waves of air…)

    Install

    Final builds of the game will be standalone executables, but there’s not much of a point yet to trying to release builds.

    You’ll need Node.js. Clone the project and then, in a terminal/command prompt in the project’s directory, run:

    npm install ; cd game ; npm install ; cd ..
    

    Run

    After installing, you can run the game with:

    npm start
    

    On the first run, it’ll download the nw.js runtime.

    There are also scripts to run multiple instances of the game:

    npm run start-secondary
    npm run start-tertiary
    

    These only work on Windows, but I could make a CLI script that works cross-platform, and allows any number of instances, plus other options like --enable-logging.

    Build

    The game implements hackily saving game data directly to the executable binary, which is rather platform specific. This is only implemented for Windows so far, but it should be feasible on at least some other systems.

    On Windows:

    npm run build
    

    On other platforms, for now:

    npm run build-simple
    
    Visit original content creator repository https://github.com/1j01/hacky-game
  • echo-host-route

    Host Route Library

    A high-performance Echo middleware library for routing based on the host. This library facilitates the configuration of different routes and behaviors for distinct hostnames, enhancing the ability to host multi-tenant applications on a single server.

    go report card Go MIT license Go.Dev reference

    Installation

    Add the module to your project by running:

    go get github.com/YidiDev/echo-host-route

    Usage

    The following example demonstrates how to use the library to define various routes based on the host name. This helps in setting up multiple applications or APIs served from the same server, each with its specific routing configuration.

    Example

    package main
    
    import (
       "github.com/YidiDev/echo-host-route"
       "github.com/labstack/echo/v4"
       "github.com/labstack/echo/v4/middleware"
       "log"
       "net/http"
       "os"
    )
    
    // defineHost1Routes sets up the routes specific to host1.com.
    func defineHost1Routes(group *echo.Group) {
       // Route to handle request to root URL of host1, returns greeting message.
       group.GET("https://github.com/", func(c echo.Context) error {
          return c.String(http.StatusOK, "Hello from host1")
       })
       // Route to handle request to /hi URL of host1, returns a different greeting message.
       group.GET("/hi", func(c echo.Context) error {
          return c.String(http.StatusOK, "Hi from host1")
       })
    }
    
    // defineHost2Routes sets up the routes specific to host2.com.
    func defineHost2Routes(group *echo.Group) {
       // Route to handle request to root URL of host2, returns greeting message.
       group.GET("https://github.com/", func(c echo.Context) error {
          return c.String(http.StatusOK, "Hello from host2")
       })
       // Route to handle request to /hi URL of host2, includes log statement and returns a greeting message.
       group.GET("/hi", func(c echo.Context) error {
          log.Println("Important stuff")
          return c.String(http.StatusOK, "Hi from host2")
       })
    }
    
    // routeNotFoundSpecifier defines behavior for unspecified routes.
    func routeNotFoundSpecifier(_ string, group *echo.Group) error {
       // Route handler for unspecified routes, returns a not-found message.
       group.RouteNotFound("/*", func(c echo.Context) error {
          return c.String(http.StatusNotFound, "No known route")
       })
       return nil
    }
    
    // init function sets up logging output to standard output.
    func init() {
       log.SetOutput(os.Stdout)
    }
    
    // main function initializes the Echo instance and sets up host-based routing.
    func main() {
       e := echo.New()             // Create a new Echo instance.
       e.Use(middleware.Recover()) // Middleware to recover from panics.
    
       hostConfigs := []hostroute.HostConfig{
          {Host: "host1.com", Prefix: "1", RouterFactory: defineHost1Routes},
          {Host: "host2.com", Prefix: "2", RouterFactory: defineHost2Routes},
       }
    
       genericHosts := []string{"host3.com", "host4.com"}
    
       // Setup host-based routes and handle any errors during setup.
       err := hostroute.SetupHostBasedRoutes(e, hostConfigs, genericHosts, true, routeNotFoundSpecifier)
       if err != nil {
          log.Fatal(err) // Log fatal error if setup fails.
       }
    
       // Start the server on port 8080.
       e.Start(":8080")
    }

    Configuration Options

    HostConfig

    The HostConfig struct is used to define the configuration for a specific host:

    • Host: The hostname for which the configuration is defined.
    • Prefix: A prefix to use for routes specific to this host when accessed on a generic host.
    • RouterFactory: A function that sets up routing for this host, taking an *echo.Group instance to define its routes.

    Generic Hosts

    Generic hosts are hosts that will have access to all routes defined in all the host configs and any others defined on the default router. This is useful for:

    • Local Testing: to be able to access all routes without changing the host.
    • Consolidated Access: Handle routes from multiple applications on a single host. For example:
      • You have two applications hosted on one Go server: one at application1.example.com and the other at application2.example.com. However, you also want people to be able to access both applications by going to example.com/application1 or example.com/application2.

    Secure Against Unknown Hosts

    The secureAgainstUnknownHosts boolean flag controls how the middleware handles requests from unknown hosts:

    • true: Requests from unknown hosts will receive a 404 Not Found Response. This is useful for securing your application against unexpected or unauthorized hosts.
    • false: Requests from unknown hosts will be passed through the primary router. This is useful if you want to catch and handle such requests manually.

    Additional Host Config

    This param is optional and allows for unlimited inputs. Each input should be a func(*echo.Group) error. This is meant for specifying functions that SetupHostBasedRoutes should run on every host group after creating it. Common use cases of this are:

    • Configuring a RouteNotFound Handler.
    • Configuring Host Specific Middleware. This can be done in the HostConfig in the RouterFactory. Alternatively, it could be done here. This may be useful if you want to centralize a lot of the host-specific middleware.

    Handling Different Hosts

    1. Host-specific Routes: Routes are defined uniquely for each host using a specific RouterFactory. The HostConfig struct includes the hostname, path prefix, and a function to define routes for that host.

      hostConfigs := []hostroute.HostConfig{
          {Host: "host1.com", Prefix: "1", RouterFactory: defineHost1Routes},
          {Host: "host2.com", Prefix: "2", RouterFactory: defineHost2Routes},
      }
    2. Generic Hosts: Generic hosts allow for fallback to common routes defined in the primary router.

      genericHosts := []string{"host3.com", "host4.com"}
    3. Secure Against Unknown Hosts: Secure your application by handling unknown hosts, preventing them from accessing unintended routes.

      hostroute.SetupHostBasedRoutes(r, hostConfigs, genericHosts, true)

    Sister Project

    This project has a sister project for Gin framework users. If you are using Gin, check out the Echo Host Route Library for similar functionality.

    Contributing

    Contributions are always welcome! If you’re interested in contributing to the project, please take a look at our Contributing Guidelines file for guidelines on how to get started. We appreciate your help in improving the library!

    Visit original content creator repository https://github.com/YidiDev/echo-host-route
  • lumus-sql-builder

    Lumus sql builder

    About project

    Lumus SQL Builder is a Rust library that allows you to programmatically and intuitively construct complex SQL queries for simple projects. It supports a variety of SQL operations, including column selection, joins, WHERE clauses, grouping, sorting, and more.

    Features

    • Table creation
    • Data insertion
    • Data selection with support for DISTINCT, GROUP BY, ORDER BY, LIMIT, and OFFSET
    • A simple way to make WHERE clauses

    Example Usage

    Creating a Table

    use lumus_sql_builder::sqlite::{CreateTable, Column};
    
    fn main() {
        let create_table = CreateTable::new("employees", vec![
            Column::new("id").integer().primary_key().auto_increment(),
            Column::new("name").text().not_null(),
            Column::new("age").integer().not_null(),
            Column::new("department").text().default("'Undefined'"),
            Column::new("salary").real(),
            Column::new("hired_date").datetime(),
            Column::new("manager_id").integer()
        ]);
    
        println!("{}", create_table.build().unwrap());
    }

    Output

    CREATE TABLE employees (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        age INTEGER NOT NULL,
        department TEXT DEFAULT 'Undefined',
        salary REAL,
        hired_date DATETIME,
        manager_id INTEGER
    );

    Inserting Data

    use lumus_sql_builder::sqlite::Insert;
    
    fn main() {
        let insert = Insert::new("employees").values(vec![
            ("name", "John"),
            ("age", "30"),
            ("department", "IT"),
            ("salary", "5000.00"),
            ("hired_date", "2024-03-20"),
            ("manager_id", "1")
        ]);
    
        println!("{}", insert.build().unwrap());
    }

    Output

    INSERT INTO employees (name, age, department, salary, hired_date, manager_id) VALUES ('John', '30', 'IT', '5000.00', '2024-03-20', '1');

    Selecting Data

    use lumus_sql_builder::sqlite::{Select, Where};
    
    fn main() {
        let select = Select::new("employees")
            .columns("name, age, department")
            .condition(Where::from("age > 25").build())
            .order("age DESC")
            .limit(10);
    
        println!("{}", select.build().unwrap());
    }

    Output

    SELECT name, age, department FROM employees WHERE age > 25 ORDER BY age DESC LIMIT 10;

    Visit original content creator repository
    https://github.com/dayvsonspacca/lumus-sql-builder

  • ConvertCOCO

    ConvertCOCO

    Description

    This project is the toolbox to convert your own dataset to COCO dataset.

    Installation

    Please install the environment by anaconda

    conda install -c conda-forge opencv cython pylab matplotlib
    git clone https://github.com/cocodataset/cocoapi.git
    cd cocoapi/PythonAPI
    python setup.py install

    Usage

    Configuration

    Edit your settings.json to adapt your own dataset.

    envs  //Basic environment
     DataPath  //Your own dataset path
     ImgFmt  //Your own dataset image format
     IgnoreSize  //ignore the small region which the size is below than IgnoreSize
    category  //Your dataset category description
     id  //Category id
     name  //Category name
     supercategory  //Super Category. For example: For category: boy,girl,man,woman. Their super category is human.
    info  //Just modify it whatever you like

    Structure of dataset path

    <DataPath>
     gt+<category name1>
      image1.<ImgFmt>
      image2.<ImgFmt>
      image3.<ImgFmt>
     gt+<category name2>
      image1.<ImgFmt>
      image2.<ImgFmt>
      image3.<ImgFmt>
     gt+<category name3>
      image1.<ImgFmt>
      image2.<ImgFmt>
      image3.<ImgFmt>
     SourceIMG
      image1.<ImgFmt>
      image2.<ImgFmt>
      image3.<ImgFmt>  

    Generate gt.json

    Please run gt2json.py, if anything above is done.

    Visit original content creator repository
    https://github.com/MELSunny/ConvertCOCO

  • math-iter-special-pow

    About stdlib…

    We believe in a future in which the web is a preferred environment for numerical computation. To help realize this future, we’ve built stdlib. stdlib is a standard library, with an emphasis on numerical and scientific computation, written in JavaScript (and C) for execution in browsers and in Node.js.

    The library is fully decomposable, being architected in such a way that you can swap out and mix and match APIs and functionality to cater to your exact preferences and use cases.

    When you use stdlib, you can be absolutely certain that you are using the most thorough, rigorous, well-written, studied, documented, tested, measured, and high-quality code out there.

    To join us in bringing numerical computing to the web, get started by checking us out on GitHub, and please consider financially supporting stdlib. We greatly appreciate your continued support!

    iterPow

    NPM version Build Status Coverage Status

    Create an iterator which iteratively evaluates the exponential function.

    Installation

    npm install @stdlib/math-iter-special-pow

    Alternatively,

    • To load the package in a website via a script tag without installation and bundlers, use the ES Module available on the esm branch (see README).
    • If you are using Deno, visit the deno branch (see README for usage intructions).
    • For use in Observable, or in browser/node environments, use the Universal Module Definition (UMD) build available on the umd branch (see README).

    The branches.md file summarizes the available branches and displays a diagram illustrating their relationships.

    To view installation and usage instructions specific to each branch build, be sure to explicitly navigate to the respective README files on each branch, as linked to above.

    Usage

    var iterPow = require( '@stdlib/math-iter-special-pow' );

    iterPow( base, exponent )

    Returns an iterator which iteratively evaluates the exponential function.

    var array2iterator = require( '@stdlib/array-to-iterator' );
    
    var x = array2iterator( [ 2.0, 2.0, -1.0 ] );
    var y = array2iterator( [ 2.0, 6.0, -1.0 ] );
    
    var it = iterPow( x, y );
    // returns <Object>
    
    var r = it.next().value;
    // returns 4.0
    
    r = it.next().value;
    // returns 64.0
    
    r = it.next().value;
    // returns -1.0
    
    // ...

    The returned iterator protocol-compliant object has the following properties:

    • next: function which returns an iterator protocol-compliant object containing the next iterated value (if one exists) assigned to a value property and a done property having a boolean value indicating whether the iterator is finished.
    • return: function which closes an iterator and returns a single (optional) argument in an iterator protocol-compliant object.

    If provided a numeric value as an iterator argument, the value is broadcast as an infinite iterator which always returns the provided value.

    var array2iterator = require( '@stdlib/array-to-iterator' );
    
    var x = array2iterator( [ 2.0, 6.0 ] );
    
    var it = iterPow( x, 2.0 );
    // returns <Object>
    
    var v = it.next().value;
    // returns 4.0
    
    v = it.next().value;
    // returns 36.0
    
    var bool = it.next().done;
    // returns true

    Notes

    • If an iterated value is non-numeric (including NaN), the returned iterator returns NaN. If non-numeric iterated values are possible, you are advised to provide an iterator which type checks and handles non-numeric values accordingly.
    • The length of the returned iterator is equal to the length of the shortest provided iterator. In other words, the returned iterator ends once one of the provided iterators ends.
    • If an environment supports Symbol.iterator and a provided iterator is iterable, the returned iterator is iterable.

    Examples

    var uniform = require( '@stdlib/random-iter-uniform' );
    var iterPow = require( '@stdlib/math-iter-special-pow' );
    
    // Create seeded iterators for generating pseudorandom numbers:
    var x = uniform( 0.0, 2.0, {
        'seed': 1234,
        'iter': 10
    });
    
    var y = uniform( -2.0, 2.0, {
        'seed': 4567,
        'iter': 10
    });
    
    // Create an iterator which consumes the pseudorandom number iterators:
    var it = iterPow( x, y );
    
    // Perform manual iteration...
    var r;
    while ( true ) {
        r = it.next();
        if ( r.done ) {
            break;
        }
        console.log( r.value );
    }

    See Also


    Notice

    This package is part of stdlib, a standard library for JavaScript and Node.js, with an emphasis on numerical and scientific computing. The library provides a collection of robust, high performance libraries for mathematics, statistics, streams, utilities, and more.

    For more information on the project, filing bug reports and feature requests, and guidance on how to develop stdlib, see the main project repository.

    Community

    Chat


    License

    See LICENSE.

    Copyright

    Copyright © 2016-2025. The Stdlib Authors.

    Visit original content creator repository https://github.com/stdlib-js/math-iter-special-pow
  • ansible-role-oraclejdk

    ansible-role-oraclejdk

    An Ansible role to install Oracle JDK.

    Platform Platform Platform Platform Platform Platform Platform

    OracleJDK OracleJDK

    Summary

    This Ansible role installs Oracle JDK and Java Cryptography Extension (optional) on the target host. OpenJDK is not supported. It has been tested with Oracle JDK 8u144/8u151 and JDK 9u181/9.0.1 on the following Linux distributions.

    • Ubuntu 16.04
    • Debian 9
    • RHEL 7.4
    • CentOS 7.3
    • Fedora 26
    • SLE 12 SP2
    • openSUSE 42.2

    Dependencies

    Ansible >= 2.x (tested with 2.3.2.0 and 2.4.0.0)

    In addition this role requires the following packages to be installed on the target host.

    • tar – Always required to extract the JDK tar.gz archive
    • unzip – Only required if JCE for JDK8 should be installed

    Installation

    To use this role it must first get downloaded from Ansible Galaxy. To install the role execute the command below on your Ansible controle machine. For more information please refer to the official documentation.

    ansible-galaxy install frieder.oraclejdk

    The command above will always pull the latest version off of Galaxy. Another possibility is to pull the role from Github and define a specific release version to download. This allows for better control over which version of this role to be used. Create a requirements.yml and put the following content in it.

    ---
    - name: frieder.oraclejdk
      src: https://github.com/frieder/ansible-role-oraclejdk
      version: 2.0.0

    Next you can execute ansible-galaxy install -r ./requirements.yml --ignore-errors and it will download all dependencies defined in this list. --ignore-errors will make sure that the whole list is processed even when some dependencies are already downloaded. A nice overview of possible entries for requirements.yml can be found here.

    Role Variables

    All role variables are defined in defaults/main.yml. One can overwrite these values in the playbook (see examples at the bottom).

    Variable Default Description
    oraclejdk_license_accept false When installing a JDK this must be set to true otherwise the play will fail. Not required when removing a JDK.
    oraclejdk_state present Defines whether to add or remove a JDK from the target host. Possible values are [present,absent].
    oraclejdk_cleanup true Remove all temp files/folders (both local and remote) after installation. When set to true this will result in “changed” plays.
    oraclejdk_dl_dir /tmp/oraclejdk The folder (both local and remote) to which the archives get downloaded/copied/extracted.
    oraclejdk_home Depending on the value of oraclejdk_state this property takes different values. In case of present it will take a single string pointing to the desired location of JAVA_HOME. In case of absent it takes a list of former JDK locations that should now be removed. In this case provide a list with at least one entry.
    oraclejdk_profile_file /etc/profile.d/java.sh The file in which the role will set the JAVA_HOME and PATH export.
    oraclejdk_cookie Cookie:oraclelicense=accept-securebackup-cookie The cookie required for automated downloads from oracle.com. License check is done with a different variable.
    oraclejdk_url The URL of the JDK archive either at oracle.com or a local corporate repository (recommended).
    oraclejdk_url_user In case that simple HTTP auth is required one can provide a username here.
    oraclejdk_url_pass In case that simple HTTP auth is required one can provide a password here.
    oraclejdk_checksum The SHA256 checksum of the JDK archive. This is used to verify that the downloaded file is valid. To disable this check just provide an empty checksum value (oraclejdk_checksum: '').
    oraclejdk_sethome true When set to true it will update the global variable JAVA_HOME to point to the installation directory of the JDK and add the binaries to the PATH variable. Also have a look at the oraclejdk_profile_file variable.
    oraclejdk_alternative_upd true When set to true it will set the alternative for java (update-alternatives --config java) to the current JDK.
    oraclejdk_alternative_prio 1 The priority used for the update-alternatives command. The JDK with the highest priority wins.
    oraclejdk_alternative_items
    • jar
    • java
    • javac
    • jcmd
    • jconsole
    • jmap
    • jps
    • jstack
    • jstat
    • jstatd
    This property allows to define what kind of alternatives should be configured for the JDK.
    oraclejdk_jce_install false When set to true it will install and add the latest Java Cryptography Extension (JCE) to the JDK. Please note that with JDK9 the unlimited key strength is enabled by default and no additional action are required. For more information please refer to the security-dev mailinglist.
    oraclejdk_jce_name UnlimitedJCEPolicyJDK8 JDK8 only. The name of the folder inside the JCE archive.
    oraclejdk_jce_url JDK8 only. The URL of the JCE archive either at oracle.com or a local corporate repository (recommended).
    oraclejdk_jce_checksum JDK8 only. The SHA256 checksum of the JCE archive. To disable this check just provide an empty checksum value (oraclejdk_jce_checksum: '').

    Example Playbooks

    Following are some examples how to use this role in an Ansible playbook.

    JDK8 & JDK9 together, set home for JDK8, update alternatives for both JDKs with different priorities

    - hosts: jdk
      pre_tasks:
      - name: Install required packages (127.0.0.1)
        delegate_to: 127.0.0.1
        run_once: true
        package:
          name: '{{ item }}'
          state: present
        with_items:
        - tar
        - unzip
      roles:
      - role: frieder.oraclejdk
        oraclejdk_license_accept: true
        oraclejdk_home: /opt/java/jdk9.0.1
        oraclejdk_sethome: false
        oraclejdk_alternative_prio: 100
        oraclejdk_url: 'http://download.oracle.com/otn-pub/java/jdk/9.0.1+11/jdk-9.0.1_linux-x64_bin.tar.gz'
        oraclejdk_checksum: 'sha256:2cdaf0ff92d0829b510edd883a4ac8322c02f2fc1beae95d048b6716076bc014'
      - role: frieder.oraclejdk
        oraclejdk_license_accept: true
        oraclejdk_home: /opt/java/jdk8u151
        oraclejdk_alternative_prio: 200
        oraclejdk_url: 'http://download.oracle.com/otn-pub/java/jdk/8u151-b12/e758a0de34e24606bca991d704f6dcbf/jdk-8u151-linux-x64.tar.gz'
        oraclejdk_checksum: 'sha256:c78200ce409367b296ec39be4427f020e2c585470c4eed01021feada576f027f'
        oraclejdk_jce_install: true
        oraclejdk_jce_url: 'http://download.oracle.com/otn-pub/java/jce/8/jce_policy-8.zip'
        oraclejdk_jce_checksum: 'sha256:f3020a3922efd6626c2fff45695d527f34a8020e938a49292561f18ad1320b59'

    JDK8 w/ minimal configuration

    - hosts: jdk8
      roles:
      - role: frieder.oraclejdk
        oraclejdk_license_accept: true
        oraclejdk_home: /opt/java/jdk8_151
        oraclejdk_url: 'http://download.oracle.com/otn-pub/java/jdk/8u151-b12/e758a0de34e24606bca991d704f6dcbf/jdk-8u151-linux-x64.tar.gz'
        oraclejdk_checksum: 'sha256:c78200ce409367b296ec39be4427f020e2c585470c4eed01021feada576f027f'

    JDK8 w/ JCE

    - hosts: jdk8
      roles:
      - role: frieder.oraclejdk
        oraclejdk_license_accept: true
        oraclejdk_home: /opt/java/java-8-151
        oraclejdk_url: 'http://download.oracle.com/otn-pub/java/jdk/8u151-b12/e758a0de34e24606bca991d704f6dcbf/jdk-8u151-linux-x64.tar.gz'
        oraclejdk_checksum: 'sha256:c78200ce409367b296ec39be4427f020e2c585470c4eed01021feada576f027f'
        oraclejdk_jce_install: true
        oraclejdk_jce_url: 'http://download.oracle.com/otn-pub/java/jce/8/jce_policy-8.zip'
        oraclejdk_jce_checksum: 'sha256:f3020a3922efd6626c2fff45695d527f34a8020e938a49292561f18ad1320b59'

    JDK8 full config

    - hosts: jdk8
      roles:
      - role: frieder.oraclejdk
        oraclejdk_license_accept: true
        oraclejdk_cleanup: true
        oraclejdk_dl_dir: /tmp/java_download
        oraclejdk_home: /opt/java/java-8-151
        oraclejdk_sethome: true
        oraclejdk_alternative_upd: true
        oraclejdk_alternative_prio: 123
        oraclejdk_alternative_items:
        - jar
        - java
        - javac
        - jcmd
        - jconsole
        - jmap
        - jps
        - jstack
        - jstat
        - jstatd
        oraclejdk_profile_file: /etc/profile.d/java.sh
        oraclejdk_url: 'http://download.oracle.com/otn-pub/java/jdk/8u151-b12/e758a0de34e24606bca991d704f6dcbf/jdk-8u151-linux-x64.tar.gz'
        oraclejdk_checksum: 'sha256:c78200ce409367b296ec39be4427f020e2c585470c4eed01021feada576f027f'
        oraclejdk_jce_install: true
        oraclejdk_jce_url: 'http://download.oracle.com/otn-pub/java/jce/8/jce_policy-8.zip'
        oraclejdk_jce_checksum: 'sha256:f3020a3922efd6626c2fff45695d527f34a8020e938a49292561f18ad1320b59'

    JDK9

    - hosts: jdk9
      roles:
      - role: frieder.oraclejdk
        oraclejdk_license_accept: true
        oraclejdk_home: /opt/java/jdk9.0.1
        oraclejdk_url: 'http://download.oracle.com/otn-pub/java/jdk/9.0.1+11/jdk-9.0.1_linux-x64_bin.tar.gz'
        oraclejdk_checksum: 'sha256:2cdaf0ff92d0829b510edd883a4ac8322c02f2fc1beae95d048b6716076bc014'

    JDK9 w/o checksum check

    - hosts: - hosts: jdk9
      roles:
      - role: frieder.oraclejdk
        oraclejdk_license_accept: true
        oraclejdk_home: /opt/java/jdk9.0.1
        oraclejdk_url: 'http://download.oracle.com/otn-pub/java/jdk/9.0.1+11/jdk-9.0.1_linux-x64_bin.tar.gz'
        oraclejdk_checksum: ''

    JDK9 add new JDK, remove old JDKs

    - hosts: jdk9
      roles:
      - role: frieder.oraclejdk
        oraclejdk_license_accept: true
        oraclejdk_home: /opt/java/jdk9.0.1
        oraclejdk_url: 'http://download.oracle.com/otn-pub/java/jdk/9.0.1+11/jdk-9.0.1_linux-x64_bin.tar.gz'
        oraclejdk_checksum: ''
      - role: frieder.oraclejdk
        oraclejdk_state: absent
        oraclejdk_home: 
        - /opt/java/jdk9.0.1
        - /opt//opt/java/java-8-151
    Visit original content creator repository https://github.com/frieder/ansible-role-oraclejdk