Telerik Forums
UI for ASP.NET Core Forum
1 answer
127 views

I try to use the number format #.### that should display

7 as 7

7.123678 as 7.124

7.4 as 7.4

, however is not the case...

cells.Add()
.VerticalAlign(SpreadsheetVerticalAlign.Center)
.Format("#.###");
displays 7. for 7, is there a way to fix the Excel bug and remove the dot, when there are any decimal ?

 

public static void Main()
{
	string format = "#.###";
	Console.WriteLine("123.456789m as {0} is {1}", format, (123.456789m).ToString(format));
	Console.WriteLine("     123.4m as {0} is {1}", format, (123.4m).ToString(format));
	Console.WriteLine("        123 as {0} is {1}", format, (123m).ToString(format));
}

output:

123.456789m as #.### is 123.457
     123.4m as #.### is 123.4
        123 as #.### is 123

serge
Top achievements
Rank 2
Bronze
Iron
Iron
 updated question on 12 May 2021
1 answer
908 views

I have a list of Countries in my Grid, a country has a Code, that is unique. The Grid is in EditCell mode. 

I need to perform a check, if newly inserted Country Code is Unique. 

So, on the controller I have

[AcceptVerbs("GET", "POST")]
public IActionResult KeyExist(string key)
{
	if (_countryService.CodeExists(key))
	{
		return Json($"The Code '{key}' is already used, please try another one!");
	}

	return Json(true);
}

how should I bind the KeyExist method to the grid's validation?
serge
Top achievements
Rank 2
Bronze
Iron
Iron
 updated question on 12 May 2021
1 answer
476 views

I have a grid and I want to sum the number of true values in a boolean column. Is there a way to create a custom aggregate function to achieve this?

 

Brett

Aleksandar
Telerik team
 answered on 12 May 2021
1 answer
174 views

Hello,

Is it possible to have server filtering in Razor Net Core 3.1? We used the demo as our base and referred to the documentation for server filtering (https://docs.telerik.com/aspnet-core/html-helpers/scheduling/scheduler/server-filtering). However we cannot pass Data("getAdditionalData") and the Data("forgeryToken") at the same time. Does anyone know how we can go about doing this so we can filter the results on the database side? Without the forgeryToken in Data, the app does not trigger the Read method (OnPostMeetings_Read)

Any insight is appreciated.

Thank you!

Stoyan
Telerik team
 answered on 11 May 2021
1 answer
150 views

In asp.net core I would like to refresh a grid form combobox.

 

Here my code but not working

 

<div class="k-content">
    @(Html.Kendo().ComboBox()
              .Name("periods")
              .HtmlAttributes(new { style = "width:100%;" })
              .DataTextField("Description")
              .DataValueField("NoPeriod")
              .Placeholder("Choisir une période")
              .Filter(FilterType.Contains)
              .SelectedIndex(0)
              .DataSource(source =>
              {
                  source.Read(read =>
                  {
                      read.Action("PeriodList_Read", "TimeSheet");
                  });
              })
            .Events(e =>
            {
                e.Change("onAssigneeChange");
            })
        )
</div>

<div class="k-content">

    @(Html.Kendo().Grid<ProKontrolTimeSheet.Models.TimeSheetItemVIEW>()
        .Name("TimeSheetGrid")
        .Reorderable(reorder => reorder.Columns(true))
        .Mobile()
        .Columns(columns =>
        {
            //columns.Select().Width(50);
            columns.Bound(p => p.NoTimeSheet).HtmlAttributes(new { id = "NoTimeSheet", style = "display : none" });
            columns.Bound(p => p.Journee).Width(125).HtmlAttributes(new { style = "text-align:center" });
            columns.Bound(p => p.Debut);
            columns.Bound(p => p.Fin).Width(150).HtmlAttributes(new { style = "text-align:center" });
            columns.Bound(p => p.Contract).Width(150).HtmlAttributes(new { style = "text-align:center" });
            columns.Bound(p => p.Project).Width(150).HtmlAttributes(new { style = "text-align:center" });
            columns.Bound(p => p.Category).Width(150).HtmlAttributes(new { style = "text-align:center" });
            columns.Bound(p => p.Emplacement).Width(150).HtmlAttributes(new { style = "text-align:center" });

        })
        .Scrollable(s=> s.Virtual(true))
        .HtmlAttributes(new { style = "height:750px;"})
         .Sortable(sortable => sortable
          .AllowUnsort(true)
          .SortMode(GridSortMode.MultipleColumn)
          .ShowIndexes(true))
        .DataSource(dataSource => dataSource
            .Ajax()
            .GroupPaging(false)
            .PageSize(50)
            .Batch(true)
            .AutoSync(true)
            .ServerOperation(false)
            .Read(read => read.Action("TimeSheetPeriod_Read", "TimeSheet").Data("additionalInfo")
            )
         )
    )
</div>
<script>
    var NoPeriod = 0
    function onAssigneeChange(e) {
        NoPeriod = e.sender.value();
        $("#TimeSheetGrid").dataSource.Data("additionalInfo").read();
    }


    function additionalInfo() {
        return {
            PeriodId: NoPeriod
        }
    }
</script>
Mihaela
Telerik team
 answered on 11 May 2021
0 answers
235 views

Hi,

I am trying to Drag & Drop a data item from grid1 to grid2. The row should not be deleted in grid1.

After dropping the dataitem to grid2 I want to

  • call the Create method on the controller
  • check, if the operation is allowed  (there is a role / right model behind)
  • update my model, if allowed
  • rollback the change on the grid, if not allowed

I use TileLayout and kendoDraggable / kendoDropTarget.

On the frontend everything looks fine. But in the Create Method of the controller, I receive an empty model.

Any ideas, what I am doing wrong?

The model:

public class SignatureModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Img { get; set; }
    }

 

The controller:

public class LayerDefController : Controller
    {

        public ActionResult AllObjectTypes_Read([DataSourceRequest] DataSourceRequest request)
        {
            return Json(GetAllObjectTypes().ToDataSourceResult(request));
        }

        public ActionResult MyObjectTypes_Read([DataSourceRequest] DataSourceRequest request)
        {
            var all = GetAllObjectTypes();
            var my = all.Where(o => o.Id < 5);
            return Json(my.ToDataSourceResult(request));
        }

        public ActionResult MyObjectTypes_Update([DataSourceRequest] DataSourceRequest request)
        {
            var all = GetAllObjectTypes();
            var my = all.Where(o => o.Id < 5);
            return Json(my.ToDataSourceResult(request));
        }

         [HttpPost]
        public IActionResult MyObjectTypes_Create([DataSourceRequest] DataSourceRequest request, SignatureModel model)
        {
            // update model
            //_all.Add(model);
            return new StatusCodeResult(200);
        }

private IEnumerable<SignatureModel> GetAllObjectTypes()
        {
            var result = Enumerable.Range(0, 50).Select(i => new SignatureModel
            {
                Id = i,
                Name = "Signature " + i,

            });

            return result.ToList();
        }

   }

}

 

The cshtml:

<script id="sig-img-template" type="text/x-kendo-template">
    <div class='sig-img'
         style='background-image: url(@Url.Content("~/images/#: Id #.svg"));'></div>
    <div class='sig-title'>#: Name #</div>
</script>

<script id="my-sig-template" type="text/x-kendo-tmpl">
    <div class="signature">
        <img src="@Url.Content("~/images/")#:Id#.svg" alt="#:Name# image" />
        <h3>#:Name#</h3>
        <p>#:kendo.toString(Id, "c")#</p>
    </div>
</script>

<!-- container templates -->
<script id="all-sigtypes-template" type="text/x-kendo-template">
    <div id="all-sigs-container" style="height:100%;width:100%;">
        @(Html.Kendo().Grid<collact.admin.web.Models.SignatureModel>()
        .Name("AllSigsGrid")
        .Columns(columns => {
            columns.Bound(s => s.Id).Width(50).Title("ID");
            columns.Bound(s => s.Name).Width(200);
            columns.Bound(s => s.Id).ClientTemplateId("sig-img-template").Title("img");
        })
        .HtmlAttributes(new { style = "height: 90%;" })
        .Navigatable()
        .Sortable()
        .Groupable()
        .Filterable()
        .ToolBar(t => t.Search())
        .Scrollable()
        .Selectable(selectable => selectable
            .Mode(GridSelectionMode.Multiple))
        .PersistSelection(true)
        .Navigatable()
        .DataSource(dataSource => dataSource
            .Ajax()
            .Model(model => model.Id(p => p.Id))
            .Read(read => read.Action("AllObjectTypes_Read", "LayerDef"))
         )
        .ToClientTemplate()
    )
    </div>
</script>

<script id="my-sigtypes-template" type="text/x-kendo-template">
    <div id="my-sigs-container" style="height:100%;width:100%;">
    @(Html.Kendo().Grid<collact.admin.web.Models.SignatureModel>()
        .Name("MySigsGrid")
        .Columns(columns => {
            columns.Bound(s => s.Id).ClientTemplateId("my-sig-template").Title("img");
    })
         .HtmlAttributes(new { style = "height: 90%;" })
         .DataSource(dataSource => dataSource
         .Ajax()
         .Model(m => m.Id(s => s.Id))
         .Read(read => read.Action("MyObjectTypes_Read", "LayerDef"))
         .Create(c => c.Action("MyObjectTypes_Create", "LayerDef"))
         .Update(update => update.Action("MyObjectTypes_Update", "LayerDef"))
         .PageSize(15)
        )
        .Pageable()
        .Scrollable()
        .ToClientTemplate()
    )

    </div>
</script>

<div id="tilelayout"></div>
@(Html.Kendo().TileLayout()
        .Name("tilelayout")
        .Columns(5)
        .RowsHeight("500px")
        .ColumnsWidth("285px")
        .Containers(c => {
            c.Add().Header(h => h.Text("Alle verfügbaren Objekttypen")).BodyTemplateId("all-sigtypes-template").ColSpan(2).RowSpan(2);
            c.Add().Header(h => h.Text("Ausgewählte Objekttypen")).BodyTemplateId("my-sigtypes-template").ColSpan(1).RowSpan(2);
        })
        .Resizable()
    )


<script>
    $(document).ready(function () {
        var grid1 = $("#AllSigsGrid").data("kendoGrid");
        var grid2 = $("#MySigsGrid").data("kendoGrid");
        var dataSource1 = grid1.dataSource;
        var dataSource2 = grid2.dataSource;

        $(grid1.element).kendoDraggable({
            filter: "tr",
            hint: function (e) {
                var item = $('<div class="k-grid k-widget" style="background-color: DarkOrange; color: black;"><table><tbody><tr>' + e.html() + '</tr></tbody></table></div>');
                return item;
            },
            group: "gridGroup1",
        });

        try {

            grid2.wrapper.kendoDropTarget({
                drop: function (e) {
                    var dataItem = dataSource1.getByUid(e.draggable.currentTarget.data("uid"));

                    console.log("dataItem: " + dataItem + ", ID = " + dataItem.get("Id"));
                    grid2.dataSource.add(dataItem);

                    $.each(grid2.dataSource.data(), function () {
                        console.log(this.Id);
                    })

                    grid2.dataSource.sync();
                    grid2.refresh();
                },
                group: "gridGroup1",
            });
        } catch (err) {
            console.log(err);
        }
    });
</script>

<style>
    .sig-img {
        display: inline-block;
        width: 40px;
        height: 40px;
        background-size: 40px 44px;
        background-position: center center;
        vertical-align: middle;
        line-height: 41px;
        box-shadow: inset 0 0 1px #999, inset 0 0 10px rgba(0,0,0,.2);
    }

    .sig-title {
        display: inline-block;
        vertical-align: middle;
        line-height: 41px;
        padding-left: 10px;
    }


    .signature {
        float: left;
        position: relative;
        width: 111px;
        height: 60px;
        margin: 0 5px;
        padding: 0;
    }

    .signature img {
        width: 50px;
        height: 50px;
    }

    .signature h3 {
        margin: 0;
        padding: 3px 5px 0 0;
        max-width: 96px;
        overflow: hidden;
        line-height: 1.1em;
        font-size: .9em;
        font-weight: normal;
        text-transform: uppercase;
        color: #999;
    }

    .signature p {
        visibility: hidden;
    }

    .signature:hover p {
        visibility: visible;
        position: absolute;
        width: 110px;
        height: 110px;
        top: 0;
        margin: 0;
        padding: 0;
        line-height: 110px;
        vertical-align: middle;
        text-align: center;
        color: #fff;
        background-color: rgba(0,0,0,0.75);
        transition: background .2s linear, color .2s linear;
        -moz-transition: background .2s linear, color .2s linear;
        -webkit-transition: background .2s linear, color .2s linear;
        -o-transition: background .2s linear, color .2s linear;
    }

    .placeholder {
        border: 1px dashed #ccc;
        background-color: #fff;
        color: #333;
    }

    .hint {
        opacity: 0.4;
    }
</style>

 

The images are just numbered svg-files.

Can anybody help, please?

Best regards

Christine

Christine
Top achievements
Rank 2
Iron
 asked on 10 May 2021
1 answer
300 views

I have created a ViewComponet that contains a Kendo textbox.

		public async Task<IViewComponentResult> InvokeAsync(ModelExpression aspFor)
		{
			return View("MyView", new MyModel(){AspFor = aspFor ... });
		}

My AspFor when it gets to the view is an instance of a ModelExpression, but the Kendo controls are expecting a string for the "Expression()" method.

How do I bind this Kendo control to the instance of the ModelExpression?

The TextBoxFor isn't happy and attempting to convert the ModelExpression instance back to its string doesn't result in HTML that contains all of the proper attributes on it.

Thanks

-Cam

Mihaela
Telerik team
 answered on 10 May 2021
1 answer
4.3K+ views

I have the following Grid configuratrion


                    @(Html.Kendo()
        .Grid<CoucheSondageDTO>()
        .Name("CoucheSondages")
        .Columns(columns =>
        {
            columns.Bound(c => c.CoucheDescription).Width(190).ClientTemplate("<div style='background: #=CoucheCouleur#'>#=CoucheDescription#</div>"); ;
            columns.Bound(c => c.ToitTN).Width(120);
            columns.Bound(c => c.BaseTN).Width(120);
            columns.Bound(c => c.Description).Width(120);
            columns.Command(command => { command.Destroy(); }).Width(150);
        })

it gives me this:

 

Is there a way to color the ful row , or the whole cell content?

Ivan Zhekov
Telerik team
 answered on 05 May 2021
1 answer
327 views

The controller is definitely being hit and it is returning data in the format I was expecting. I have javascript in the "RequestEnd" and I am seeing data there. There are no errors or warnings (that pertain to the listview) in the browser's developer console. The pager shows up but says there are zero records. I have been tossing code at this for waaaaay too long.

Any suggestions? Please.....

 

Controller:

[HttpPost] [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public async Task<IActionResult> UserProfiles_Search([DataSourceRequest] DataSourceRequest request) { Logger.LogInformation("In UserProfiles_Search");

// dummy data var data = new List < UserProfile >(){ new UserProfile() { Title = "Mrs", FirstName = "Joanne", LastName = "Welch", EmailAddress = "joanne.welch@example.com", Id = Guid.Parse("3c7b201d-9744-4807-bd53-192251fb6e60") }, new UserProfile() { Title = "Miss", FirstName = "Florence", LastName = "Lawrence", EmailAddress = "florence.lawrence@example.com", Id = Guid.Parse("6691697e-faa5-41ec-89b0-b6a040be8d2d") }, new UserProfile() { Title = "Mrs", FirstName = "Stella", LastName = "Laurent", EmailAddress = "stella.laurent@example.com", Id = Guid.Parse("87cf6fef-0d9e-4fea-bbca-b48d9f478c61") }, new UserProfile() { Title = "Ms", FirstName = "Sharida", LastName = "Broeren", EmailAddress = "sharida.broeren@example.com", Id = Guid.Parse("d58fcf47-88ac-4753-8d08-3cbf0318c13d") }, new UserProfile() { Title = "Mr", FirstName = "William", LastName = "Liu", EmailAddress = "william.liu@example.com", Id = Guid.Parse("688fff10-e522-4267-a061-5553c627689e") }, new UserProfile() { Title = "Ms", FirstName = "Brielle", LastName = "Clark", EmailAddress = "brielle.clark@example.com", Id = Guid.Parse("00fa0fa0-494f-44e5-9bb2-5fbcea156eb7") }, new UserProfile() { Title = "Miss", FirstName = "تارا", LastName = "زارعی", EmailAddress = "tr.zraay@example.com", Id = Guid.Parse("3a7ddd17-33a3-489a-91b9-48055eefb55e") }, new UserProfile() { Title = "Mr", FirstName = "Necati", LastName = "Karadaş", EmailAddress = "necati.karadas@example.com", Id = Guid.Parse("33c54e50-7297-4af0-914c-484f182d0e52") }, new UserProfile() { Title = "Ms", FirstName = "Elizabeth", LastName = "Craig", EmailAddress = "elizabeth.craig@example.com", Id = Guid.Parse("6841bcec-6662-473e-9b1a-d5f533ab01d8") }, new UserProfile() { Title = "Mr", FirstName = "Karl", LastName = "Gordon", EmailAddress = "karl.gordon@example.com", Id = Guid.Parse("43ec6d51-5b3e-4e6d-ae78-4394234950b4") }, new UserProfile() { Title = "Mrs", FirstName = "Gretel", LastName = "Bender", EmailAddress = "gretel.bender@example.com", Id = Guid.Parse("54dab09c-1d6f-4544-aa23-0fb74f3f12c9") }, new UserProfile() { Title = "Mrs", FirstName = "Francelina", LastName = "Nunes", EmailAddress = "francelina.nunes@example.com", Id = Guid.Parse("3c62214b-c797-4cdb-9623-cbc51ec8a86f") }, new UserProfile() { Title = "Monsieur", FirstName = "Oskar", LastName = "Berger", EmailAddress = "oskar.berger@example.com", Id = Guid.Parse("4687147c-8630-4018-afb8-52cdb0e1937a") }, new UserProfile() { Title = "Miss", FirstName = "Emilie", LastName = "Carpentier", EmailAddress = "emilie.carpentier@example.com", Id = Guid.Parse("8b11fb43-93da-470c-bc1a-eddce87a3ecc") }, new UserProfile() { Title = "Mrs", FirstName = "Florence", LastName = "King", EmailAddress = "florence.king@example.com", Id = Guid.Parse("f203e0b7-ebe3-4a72-b82e-c910b9daa3fd") } }; var resultData = await data.ToDataSourceResultAsync(request); return Json(resultData); }

 

Index.cshtml

@using SaskPower.DSS.CSRTools.Models.Models
@using SaskPower.DSS.CSRTools.Models.ViewModels
@model ProfileSearchViewModel
@{
	Layout = "";
}
<html>
<head>
	<title>Test page</title>

	<link rel="stylesheet" href="~/lib/kendo/styles/kendo.common.min.css" />
	<link rel="stylesheet" href="~/lib/kendo/styles/kendo.bootstrap.min.css" />
	<link rel="stylesheet" href="~/lib/kendo/styles/kendo.bootstrap-v4.css" />

	<script language="javascript" type="text/ecmascript" src="~/lib/kendo/scripts/jquery.min.js"></script>
	<script language="javascript" type="text/ecmascript" src="~/lib/kendo/scripts/jszip.min.js"></script>
	<script language="javascript" type="text/ecmascript" src="~/lib/kendo/scripts/kendo.all.min.js"></script>
	<script language="javascript" type="text/ecmascript" src="~/lib/kendo/scripts/kendo.aspnetmvc.min.js"></script>
	<script language="javascript" type="text/ecmascript" src="~/lib/kendo/scripts/cultures/kendo.culture.en-CA.min.js"></script>
	<script language="javascript" type="text/ecmascript" src="~/lib/kendo/scripts/messages/kendo.messages.en-CA.min.js"></script>
	<script language="javascript" type="text/ecmascript" src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script>
</head>
<body>
	<script type="text/x-kendo-tmpl" id="userProfileSearchResultItem">
		<div class="userProfileSingleResult">
			<div class="name">#:firstName# #:lastName#</div>
			<div class="email">#:emailAddress#</div>
			<div class="id">#:id#</div>
		</div>
	</script>
	<div class="profile-search">
		<div class="result-count"></div>
		<div class="results">
			@(Html.Kendo().ListView<UserProfile>()
				.Name("userProfileSearchResults")
				.TagName("div")
				.ClientTemplateId("userProfileSearchResultItem")
				.DataSource(dataSource => dataSource
					.Ajax()
					.Model(m => m.Id(p => p.Id))
					.PageSize(25)
					.Read(read=>read.Action("UserProfiles_Search", "Home"))
					.ServerOperation(false)
					.Events(evt => evt
						.RequestEnd("userProfileRequestEnd")
					)
				)
				.AutoBind(true)
				.Pageable(pager => pager
				.ButtonCount(10)
				.Numeric(true)
				.Enabled(true)
			)
		)
</div>
	</div>
	<script type="text/javascript" language="javascript">
		function userProfileRequestEnd(event) {
			console.log("in userProfileRequestEnd");
			$(".profile-search .result-count").html("" + event.response.data.length + " profiles found");
		}
	</script>
</body>
</html>

 

Model:

	public class UserProfile
	{
		public Guid Id { get; set; }
		public string Title { get; set; }
		public string FirstName { get; set; }
		public string LastName { get; set; }
		public string EmailAddress { get; set; }
	}

 

Thanks

-Cam

A
Top achievements
Rank 1
Iron
 answered on 04 May 2021
1 answer
343 views

We are setting up a new razor page using ListView following this sample (https://docs.telerik.com/aspnet-core/html-helpers/data-management/listview/binding/razor-page), with onChange event and all is working as expected.

We wanted to incorporate Grouping as well (https://demos.telerik.com/aspnet-core/listview/grouping) bringing in the grouping jQuery, .AutoBind(false), template, and css. When selecting a card, it selects the outside group, not the individual cards. Does anyone know if grouping and selecting individual cards are supported in Razor? If so, can someone provide some insight?


    $(function () {
        var groupDetails = {
            field: 'RoomDescription',
            dir: 'desc',
            compare: function (a, b) {
                if (a.items.length === b.items.length) {
                    return 0;
                } else if (a.items.length > b.items.length) {
                    return 1;
                } else {
                    return -1;
                }
            }
        }
        var listView = $("#listview").data("kendoListView");
        //var listView = $("#listView").data().kendoListView;
        var dataSource = listView.dataSource;
        dataSource.group(groupDetails);
    });

@(Html.Kendo().ListView<spRoomAvailabilityResult>()
    .Name("listview")
    .TagName("div")
    .ClientTemplateId("template")
    .Selectable(ListViewSelectionMode.Single)
    .Events(events => events.Change("onChange").DataBound("onDataBound"))
    .AutoBind(false)
    .DataSource(ds => ds
        .Ajax()
        .Model(model => {
            model.Id(p => p.ROOMID);
        })
        .Read(read => read.Url("/MyWebPage?handler=Read").Data("forgeryToken"))
    )
)

<script>
    function forgeryToken() {
        return kendo.antiForgeryTokens();
    }

    $(document).ready(function () {
        var listView = $("#listview").data("kendoListView");

        $(".k-add-button").click(function (e) {
            listView.add();
            e.preventDefault();
        });
    });
</script>
<script>
    function onChange(arg) {

        var selected = $.map(this.select(), function (item) {
            return $(item).text();
        });

        alert(selected);
    }
</script>


<script type="text/x-kendo-template" id="template">
    <div class="k-listview-item">
        <h4 class="k-group-title">#= data.value #</h4>
        <div class="cards">
            # for (var i = 0; i < data.items.length; i++) { #
            <div class="k-card" style="width: 15em; margin:2%">
            <div class="k-card-body">
                    <h4 class="k-card-title">#= data.items[i].ROOMNUMBER #</h4>
                    <h5 class="k-card-subtitle">Capacity: #= data.items[i].CAPACITY #</h5>
                </div>
            </div>
            # } #
        </div>
    </div>
</script>
Any insight would be appreciated. Thank you!

Tsvetomir
Telerik team
 answered on 04 May 2021
Narrow your results
Selected tags
Tags
+? more
Top users last month
Will
Top achievements
Rank 2
Iron
Motti
Top achievements
Rank 1
Iron
Hester
Top achievements
Rank 1
Iron
Bob
Top achievements
Rank 3
Iron
Iron
Veteran
Thomas
Top achievements
Rank 2
Iron
Want to show your ninja superpower to fellow developers?
Top users last month
Will
Top achievements
Rank 2
Iron
Motti
Top achievements
Rank 1
Iron
Hester
Top achievements
Rank 1
Iron
Bob
Top achievements
Rank 3
Iron
Iron
Veteran
Thomas
Top achievements
Rank 2
Iron
Want to show your ninja superpower to fellow developers?
Want to show your ninja superpower to fellow developers?