In this document, we will create a sample phonebook application based on ASP.NET Zero step by step. After all steps, we will have a multi-tenant, localized, authorized, configurable, testable... appliaction.
We're creating and downloading the solution named "Acme.PhoneBook" as described in Getting Started document. After opening solution in Visual Studio, we see an NLayered solution that consists of six projects:
Also, run database migrations, create the database and login to the application as described in Getting Started document. After all completed and logged in to the application, we see a dashboard as shown below:
Logout from the application for now. We will make our application single-tenant (we will convert it to multi-tenant later). So, we open PhoneBookCoreModule class and disable multi-tenancy as shown below:
[DependsOn(typeof(AbpZeroCoreModule))]
public class PhoneBookCoreModule : AbpModule
{
public override void PreInitialize()
{
//Enable this line to create a multi-tenant application.
//Configuration.MultiTenancy.IsEnabled = true;
}
}
Let's begin from UI and create a new page named "Phone book".
MpaNavigationProvider class defines menus in the application. When we change this class, menus are automatically changed. Open this class and create new menu item as shown below (You can add it right after the dashboard menu item).
.AddItem(new MenuItemDefinition(
PageNames.App.Tenant.PhoneBook,
L("PhoneBook"),
url: "Mpa/PhoneBook",
icon: "glyphicon glyphicon-book"
)
)
Every menu item must have a unique name to identify this menu item. Menu names are defined in PageNames class as constants. We add a new constant: "PhoneBook".
A menu item should also have a localizable shown name. It's used to display menu item on the page. L("PhoneBook") is localized name of our new menu. L method is a helper method gets a localization key and simply returns a LocalizableString object (see MpaNavigationProvider class).
Localization strings are defined in XML files in .Core project as shown below:
Open PhoneBook.xml (the default, English localization dictionary) and add the following line:
<text name="PhoneBook" value="Phone book" />
If we don't define "PhoneBook"s value for other localization dictionaries, default value is shown in all languages. We can define it also for Turkish in PhoneBook-tr.xml file:
<text name="PhoneBook" value="Telefon rehberi" />
url can be a URL (it's URL of an MVC Action here) that will be redirected when we click the menu item.
Lastly, icon is the shown menu icon for new menu item. It can be a css class. We can use Glyphicon, Font-Awesome or another css font library here.
See navigation document for more information on menu definitions.
After creating the menu item, we can create an empty page.
Creating the PhoneBookController under Areas/Mpa/Controllers folder in the Web project:
public class PhoneBookController : PhoneBookControllerBase
{
public ActionResult Index()
{
return View();
}
}
We inherited from PhoneBookControllerBase (will be YourProjectNameControllerBase for your projects) instead of MVC's standard Controller class. While it will work if we derive from the standard Controller, PhoneBookControllerBase provides very useful base properties and methods. So, always inherit from this class unless it has a disadvantage for your case.
Creating an empty view, Index.cshtml under Areas/Mpa/Views/PhoneBook folder:
@using Acme.PhoneBook.Web.Navigation
@{
ViewBag.CurrentPageName = PageNames.App.Tenant.PhoneBook;
}

@L("PhoneBook")

PHONE BOOK CONTENT COMES HERE!

We set ViewBag.CurrentPageName to the current page's name to automatically highlight the related menu item when this page is active. Now, it's time to run application and see the new phone book page:
Menu item display name and page title are localized. Try to change UI language to see difference.
We define entities in .Core (domain) project. We can define a Person entity (mapped to PbPersons table in database) to represent a person in phone book as shown below:
[Table("PbPersons")]
public class Person : FullAuditedEntity
{
public const int MaxNameLength = 32;
public const int MaxSurnameLength = 32;
public const int MaxEmailAddressLength = 255;
[Required]
[MaxLength(MaxNameLength)]
public virtual string Name { get; set; }
[Required]
[MaxLength(MaxSurnameLength)]
public virtual string Surname { get; set; }
[MaxLength(MaxEmailAddressLength)]
public virtual string EmailAddress { get; set; }
}
Person's primary key type is int (as default). It inherits FullAuditedEntity that contains creation, modification and deletion audit properties. It's also soft-delete. When we delete a person, it's not deleted by database but marked as deleted (see entity and data filters documentations for more information). We created consts for MaxLength properties. This is a good practice since we will use same values later.
We add a DbSet property for Person entity to PhoneBookDbContext class defined in .EntityFramework project.
public class PhoneBookDbContext : AbpZeroDbContext<Tenant, Role, User>
{
public virtual IDbSet<Person> Persons { get; set; }
//...other entities
public PhoneBookDbContext()
: base("Default")
{
}
//...other codes
}
We use EntityFramework Code-First migrations to migrate database schema. Since we added Person entitiy, our DbContext model is changed. So, we should create a new migration to create the new table in the database.
After opening Package Manager Console and selecting .EntityFramework as default project, we write the following command:
This command will add a migration class named "Added_Persons_Table" as shown below:
public partial class Added_Persons_Table : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.PbPersons",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(nullable: false, maxLength: 32),
Surname = c.String(nullable: false, maxLength: 32),
EmailAddress = c.String(maxLength: 255),
IsDeleted = c.Boolean(nullable: false),
DeleterUserId = c.Long(),
DeletionTime = c.DateTime(),
LastModificationTime = c.DateTime(),
LastModifierUserId = c.Long(),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
},
annotations: new Dictionary<string, object>
{
{ "DynamicFilter_Person_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
})
.PrimaryKey(t => t.Id);
}
public override void Down()
{
DropTable("dbo.PbPersons",
removedAnnotations: new Dictionary<string, object>
{
{ "DynamicFilter_Person_SoftDelete", "EntityFramework.DynamicFilters.DynamicFilterDefinition" },
});
}
}
We don't have to know so much about format and rules of this file. But, it's suggested to have a basic understanding of migrations. In the same Package Manager Console, we write "Update-Database" command in order to apply the new migration to database. After updating, we can see that PbPersons table is added to database.
But this new table is empty. We can use EntityFramework's Seed method to add some initial data to database. In ASP.NET Zero, there are some classes to fill initial data for users and settings:
So, we can add a seperated class to fill some people to database as shown below:
public class InitialPeopleCreator
{
private readonly PhoneBookDbContext _context;
public InitialPeopleCreator(PhoneBookDbContext context)
{
_context = context;
}
public void Create()
{
var douglas = _context.Persons.FirstOrDefault(p => p.EmailAddress == "douglas.adams@fortytwo.com");
if (douglas == null)
{
_context.Persons.Add(
new Person
{
Name = "Douglas",
Surname = "Adams",
EmailAddress =<EMAIL_ADDRESS>});
}
var asimov = _context.Persons.FirstOrDefault(p => p.EmailAddress == "isaac.asimov@foundation.org");
if (asimov == null)
{
_context.Persons.Add(
new Person
{
Name = "Isaac",
Surname = "Asimov",
EmailAddress =<EMAIL_ADDRESS>});
}
}
}
These type of default data is good since we can also use these data in unit tests. Surely, we should be careful about seed data since this code will always be executed after each Update-Database command (See EntityFramework documentations to know more about seed data). This class is created and called in DefaultTenantBuilder class, and it's called from EntityFramework's Configuration class. This is not so important, just for a good code organization (see source codes).
We execute Update-Database command again. This command runs seed and adds two people to PbPersons table:
An Application Service is used from client (presentation layer) to perform operations (use cases) in the application.
Application services are located in .Application project. We create first application service to get people from server. We're creating an interface to define the person application service:
public interface IPersonAppService : IApplicationService
{
ListResultDto<PersonListDto> GetPeople(GetPeopleInput input);
}
An application service method gets/returns DTOs. ListResultDto is a pre-build helper DTO to return a list of another DTO. GetPeopleInput is a DTO to pass request parameters to GetPeople method. So, GetPeopleIntput and PersonListDto are defined as shown below:
public class GetPeopleInput
{
public string Filter { get; set; }
}
[AutoMapFrom(typeof(Person))]
public class PersonListDto : FullAuditedEntityDto
{
public string Name { get; set; }
public string Surname { get; set; }
public string EmailAddress { get; set; }
}
AutoMapFrom attribute is used to configure AutoMapper to create mapping from Person to PersonListDto. FullAuditedEntityDto used to inherit audit properties automatically. See application service and DTO documentations for more information.
After defining interface, we can implement it as shown below:
public class PersonAppService : PhoneBookAppServiceBase, IPersonAppService
{
private readonly IRepository<Person> _personRepository;
public PersonAppService(IRepository<Person> personRepository)
{
_personRepository = personRepository;
}
public ListResultDto<PersonListDto> GetPeople(GetPeopleInput input)
{
var persons = _personRepository
.GetAll()
.WhereIf(
!input.Filter.IsNullOrEmpty(),
p => p.Name.Contains(input.Filter) ||
p.Surname.Contains(input.Filter) ||
p.EmailAddress.Contains(input.Filter)
)
.OrderBy(p => p.Name)
.ThenBy(p => p.Surname)
.ToList();
return new ListResultDto<PersonListDto>(persons.MapTo<List<PersonListDto>>());
}
}
We're injecting person repository (it's automatically created by ABP) and using it to filter and get people from database.
WhereIf is an extension method here (defined in Abp.Linq.Extensions namespace). It performs Where condition, only if filter is not null or empty. IsNullOrEmpty is also an extension method (defined in Abp.Extensions namespace). ABP has many similar shortcut extension methods. MapTo method automatically converts list of Person entities to list of PersonListDto entities using AutoMapper library.
We don't manually open database connection or start/commit transactions manually. It's automatically done with ABP framework's Unit Of Work system. See UOW documentation for more.
We don't handle exceptions manually (using a try-catch block). Because ABP framework automatically handles all exceptions on the web layer and returns appropriate error messages to the client. It then handles errors on the client and shows needed error information to the user. See exception handling document for more.
You can skip this section if you don't interest in automated testing.
By writing unit test, we can test PersonAppService.GetPeople method without creating a user interface that calls it and shows people on the screen.
We write unit test in .Tests project in the solution. Let's create first test to verify getting people without any filter:
public class PersonAppService_Tests : AppTestBase
{
private readonly IPersonAppService _personAppService;
public PersonAppService_Tests()
{
_personAppService = Resolve<IPersonAppService>();
}
[Fact]
public void Should_Get_All_People_Without_Any_Filter()
{
//Act
var persons = _personAppService.GetPeople(new GetPeopleInput());
//Assert
persons.Items.Count.ShouldBe(2);
}
}
We derived test class from AppTestBase. AppTestBase class initializes all system, creates an in-memory fake database, seeds initial data (that we created before) to database and logins to application as admin. So, this is actually an integration test since it tests all server-side codes from entitiy framework mapping to application services, validation and authorization.
In constructor, we get (resolve) an IPersonAppService from dependency injection container. It creates the PersonAppService class with all dependencies. Then we can use it in test methods.
Since we're using xUnit, we add Fact attribute to each test method. In the test method, we called GetPeople method and checked if there are two people in the returned list as we know that there were 2 people in initial database.
Let's run the all unit tests in Test Explorer and see if it works:
As you see, it worked successfully. Now, we know that PersonAppService works properly without any filter. Let's add a new unit test to get filtered people:
[Fact]
public void Should_Get_People_With_Filter()
{
//Act
var persons = _personAppService.GetPeople(
new GetPeopleInput
{
Filter = "adams"
});
//Assert
persons.Items.Count.ShouldBe(1);
persons.Items[0].Name.ShouldBe("Douglas");
persons.Items[0].Surname.ShouldBe("Adams");
}
Again, since we know initial database, we can check returned results easily. Here, initial test data is important. When we change initial data, our test may fail even if our services are correct. So, it's better to write unit tests independent of initial data as much as possible. We could check incoming data to see if every people contains "adams" in his/her name, surname or email. Thus, if we add new people to initial data, our tests remain working.
There are many techniques on unit testing, I kept it simple here. But ASP.NET Zero template makes very easy to write unit and integration tests by base classes and pre-build test codes.
Now, lets run and login to the application again, open Chrome Developer Console (or similar tools in other browsers) and write the following command:
This command performs an AJAX call to PersonAppService.GetPeople method. We can see the request if we open Network tab:
As we see, an AJAX request made and people are got successfully.
So, how this happen? How we could call to a C# class method (notice that it's not an MVC Controller or Web API Controller, just a plain C# class) from javascript like calling a javascript method? This is provided by ASP.NET Boilerplate. See dynamic web api layer documentation for more information. You can always call application services from console to debug or see returned JSON structure.
We can also check Audit Logs to see the request. Open AbpAuditLogs table in PhoneBook database to see the call information:
There are some other fields not shown here. So, we see that User with Id=2 called GetPeople method of the PersonAppService in recorded time with the shown parameters and it' executed in 134 ms.
It's time to open PhoneBookController and get people to show on the view:
public class PhoneBookController : PhoneBookControllerBase
{
private readonly IPersonAppService _personAppService;
public PhoneBookController(IPersonAppService personAppService)
{
_personAppService = personAppService;
}
public ActionResult Index(GetPeopleInput input)
{
var output = _personAppService.GetPeople(input);
var model = new IndexViewModel(output);
return View(model);
}
}
We inject IPersonAppService and call it's GetPeople method (which is created and tested before) to get list of people. Then we created a ViewModel object and passes to the view. Let's see the IndexViewModel class:
[AutoMapFrom(typeof (ListResultDto<PersonListDto>))] public class IndexViewModel : ListResultDto<PersonListDto> { public IndexViewModel(ListResultDto<PersonListDto> output) { output.MapTo(this); } }
Here, we're extending output of PersonAppService.GetPeople method's output. Getting the output from constructor and map to this object. We declared AutoMapFrom attribute to be able to make mapping.
We created an Application Service (PersonAppService) and used it from the Controller. Instead, we could access Repository directly from Controller and completely discard the application service. ASP.NET Zero does not enforce any architecture here. In ASP.NET Zero, we use the application layer (application services and DTOs) both from SPA and MPA. Therefore, we implemented it independent from ASP.NET MVC. This makes application layer re-usable from different presentation layers. But if you will only develop ASP.NET MVC, you can implement application logic inside controllers and access to the repositories from controllers. This may simplify your architecture and development model.
If you decide to develop application services and use them in controllers then you can use application service's output as your view model. We did not prefer it and wrapped output by a dedicated ViewModel (IndexViewModel here) since we think that we may add some additional properties/methods for our view model. Again, it's your choice of implementation.
We show people on the page is most basic form. See the changed view below:
...
@model Acme.PhoneBook.Web.Areas.Mpa.Models.PhoneBook.IndexViewModel
...

@L("AllPeople")

@foreach (var person in Model.Items)
{

@person.Name @person.Surname

@person.EmailAddress

}

...
We declared the @model and used a foreach loop to render people. See the result:
We successfully retrieved list of people from database to the page.
We normally use a javascript based rich table/grid library to show tabular data, instead of manually rendering data like that. For example, we used jTable library to show users on the Users page of ASP.NET Zero. Always use such components since they make things much more easier and provides a much better user experience.
We did not use a table component here, because we want to show basics of MVC instead of going details of a 3rd party library.
Next step is to create a modal to add a new item to phone book.
We first define CreatePerson method in IPersonAppService interface:
Task CreatePerson(CreatePersonInput input);
Then we create CreatePersonInput DTO that defines parameters of the method:
[AutoMapTo(typeof(Person))]
public class CreatePersonInput
{
[Required]
[MaxLength(Person.MaxNameLength)]
public string Name { get; set; }
[Required]
[MaxLength(Person.MaxSurnameLength)]
public string Surname { get; set; }
[EmailAddress]
[MaxLength(Person.MaxEmailAddressLength)]
public string EmailAddress { get; set; }
}
CreatePersonInput is mapped to Person entity (we will use mapping below). All properties are decorated by data annotation attributes to provide automatic validation. Notice that we use same consts defined in Person entity for MaxLength properties.
Here, the implementation of CreatePerson method:
public async Task CreatePerson(CreatePersonInput input)
{
var person = input.MapTo<Person>();
await _personRepository.InsertAsync(person);
}
A Person entity is created by mapping given input, then inserted to database. We used async/await pattern here. All methods in ASP.NET Zero startup project is async. It's adviced to use async/await wherever possible.
You can skip this section if you don't interest in automated testing.
We can create a unit test method to test CreatePerson method as shown below:
[Fact]
public async Task Should_Create_Person_With_Valid_Arguments()
{
//Act
await _personAppService.CreatePerson(
new CreatePersonInput
{
Name = "John",
Surname = "Nash",
EmailAddress =<EMAIL_ADDRESS>});
//Assert
UsingDbContext(
context =>
{
var john = context.Persons.FirstOrDefault(p => p.EmailAddress == "john.nash@abeautifulmind.com");
john.ShouldNotBe(null);
john.Name.ShouldBe("John");
});
}
Test method also written using async/await pattern since calling method is async. We called CreatePerson method, then checked if given person is in the database. UsingDbContext method is a helper method of AppTestBase class (which we inherited this unit test class from). It's used to easily get a reference to DbContext and use it directly to perform database operations.
This method successfully works since all required fields are supplied. Let's try to create a test for invalid arguments:
[Fact]
public async Task Should_Not_Create_Person_With_Invalid_Arguments()
{
//Act and Assert
await Assert.ThrowsAsync<AbpValidationException>(
async () =>
{
await _personAppService.CreatePerson(
new CreatePersonInput
{
Name = "John"
});
});
}
We did not set Surname property of CreatePersonInput despite of it's required. So, it throws AbpValidationException automatically. Also, we can not send null to CreatePerson method since validation system also checks it. This test calls CreatePerson with invalid arguments and asserts that it thows AbpValidationException. See validation document for more information.
We will create a Bootstrap Modal to create a new person. First of all, you can create modal and save as you already know and like. But ASP.NET Zero has some helper scripts to make it easier if you use it. We will use them here.
We can copy cshtml and js files from Areas/Mpa/Views/Common/Modals/Empty folder as a base for a new modal.
Copied and modifined the view code as shown below (_CreatePersonModal.cshtml):
@using Acme.PhoneBook.People
@using Acme.PhoneBook.Web.Areas.Mpa.Models.Common.Modals
@Html.Partial("~/Areas/Mpa/Views/Common/Modals/_ModalHeader.cshtml", new ModalHeaderViewModel(L("CreateNewPerson")))

<form role="form" novalidate class="form-validation">

<input class="form-control" type="text" name="Name" required<EMAIL_ADDRESS>@L("Name")

<input type="text" name="Surname" class="form-control" required<EMAIL_ADDRESS>@L("Surname")

<input type="email" name="EmailAddress" class="form-control"<EMAIL_ADDRESS>@L("EmailAddress")

</form>

@Html.Partial("~/Areas/Mpa/Views/Common/Modals/_ModalFooterWithSaveAndCancel.cshtml")
Modal header and footer code comes from the template. We just changed inside of modal-body.
We have a form with three input (name, surname and email address). We're using Person entity's const values in view to set same maxlength to input controls.
Also, copied the modal js and modified as shown below (_CreatePersonModal.js):
(function($) {
app.modals.CreatePersonModal = function () {
var _modalManager;
this.init = function(modalManager) {
_modalManager = modalManager;
//Initialize your modal here...
};
this.save = function () {
//Save your modal here...
};
};
})(jQuery);
Just named the modal as 'CreatePersonModal'. We will fill the javascript code later.
We need to put a "Create new person" button to the 'people list page' and write some javascript code to open the modal when clicked to the button.
So, changing the Index.cshtml view header as shown below:
@using Abp.Web.Mvc.Extensions
@using Acme.PhoneBook.Web.Navigation
@model Acme.PhoneBook.Web.Areas.Mpa.Models.PhoneBook.IndexViewModel
@{
ViewBag.CurrentPageName = PageNames.App.Tenant.PhoneBook;
}
@section Scripts
{
@Html.IncludeScript("~/Areas/Mpa/Views/PhoneBook/_CreatePersonModal.js")
@Html.IncludeScript("~/Areas/Mpa/Views/PhoneBook/Index.js")
}

@L("PhoneBook")

<button id="CreateNewPersonButton" class="btn btn-primary blue"> @L("CreateNewPerson")</button>

We included modal's javascript (_CreatePersonModal.js) and a Index.js file which is defined as shown below:
(function () {
$(function () {
var _createPersonModal = new app.ModalManager({
viewUrl: abp.appPath + 'Mpa/PhoneBook/CreatePersonModal',
scriptUrl: abp.appPath + 'Areas/Mpa/Views/PhoneBook/_CreatePersonModal.js',
modalClass: 'CreatePersonModal'
});
$('#CreateNewPersonButton').click(function(e) {
e.preventDefault();
_createPersonModal.open();
});
});
})();
ModalManager is a predefined modal helper javascript class of ASP.NET Zero. It accepts a viewUrl (which is actually an MVC action to load the view), a scriptUrl (javascript file of the modal) and a modalClass (which is set when we define the modal above).
ModalManager's open method loads view and javascript (if needed) and opens the modal.
Lastly, we should create the MVC action defined as Mpa/PhoneBook/CreatePersonModal. So, open the PhoneBookController again and add the following action:
public PartialViewResult CreatePersonModal()
{
return PartialView("_CreatePersonModal");
}
Now, we can run the application and open the modal by clicking the 'Create New Person' button:
Finally, we can save the person when user clicks the the save button. We implement it in the _CreatePersonModal.js file:
(function($) {
app.modals.CreatePersonModal = function () {
var _modalManager;
var _personService = abp.services.app.person;
var _$form = null;
this.init = function(modalManager) {
_modalManager = modalManager;
_$form = _modalManager.getModal().find('form');
_$form.validate();
};
this.save = function () {
if (!_$form.valid()) {
return;
}
var person = _$form.serializeFormToObject();
_modalManager.setBusy(true);
_personService.createPerson(person).done(function () {
_modalManager.close();
location.reload();
}).always(function () {
_modalManager.setBusy(false);
});
};
};
})(jQuery);
In the init function, we got a reference to the form and enable validation.
In the save method, we first validate the form. Then we convert the form to a javascript object (since server waits for JSON). Then we use PersonAppService's createPerson method to save the person. setBusy method automatically disables save and cancel buttons. In the done method, we simple reloaded the page to show new user in the page (In a real application, we could add new person to the page dynamically using jQuery)
Notice that; We used PersonAppService's createPerson method directly from javascript. This is possible by ABP's Dynamic Web API layer.
At this point, anyone can enter phone book page since no authorization defined. We will define two permission:
Go to AppAuthorizationProvider class and add a new permission as shown below:
pages.CreateChildPermission(AppPermissions.Pages_Tenant_PhoneBook, L("PhoneBook"), multiTenancySides: MultiTenancySides.Tenant);
A permission should have a unique name. We define permission names as constant strings in AppPermissions class. It's a simple constant string:
public const string Pages_Tenant_PhoneBook = "Pages.Tenant.PhoneBook";
Unique name of this permission is "Pages.Tenant.PhoneBook". While you can set any string (as long as it's unique), it's suggested this convention. A permission can have a localizable display name: "PhoneBook" here. (see "Adding a New Page" section for more about localization, since it's very similar). Lastly, we set that this is a tenant level permission.
AbpAuthorize attribute can be used as class level or method level to protect an application service or service method from unauthorized users. Since all server side code is located in PersonAppService class, we can declare a class level attribute as shown below:
[AbpAuthorize(AppPermissions.Pages_Tenant_PhoneBook)]
public class PersonAppService : PhoneBookAppServiceBase, IPersonAppService
{
//...
}
Now, let's try to enter Phone Book page by clicking the menu item:
We get an error message. This exception is thrown when any method of PersonAppService is called without required permission.
This secures the service, but we should also hide the Phone book menu item. It's easy, open MpaNavigationProvider and add requiredPermissionName as shown below:
new MenuItemDefinition(
PageNames.App.Tenant.PhoneBook,
L("PhoneBook"),
url: "tenant.phonebook",
icon: "glyphicon glyphicon-book",
requiredPermissionName: AppPermissions.Pages_Tenant_PhoneBook
)
So, how we can enter the page now? Simple, go to Role Management page and edit admin role:
We see that a new permission named "Phone book" added to permissions tab. So, we can check it and save the role. After saving, we need to refresh the whole page to refresh permissions for the current user. We could also grant this permission for a specific user (see development guide document for details about roles and users).
Now, we can enter the Phone book page again.
While a permission for a page is useful and probably needed always, we may need to define additional permissions to perform some specific actions on a page, like creating a new person.
Defining a permission is similar:
var phoneBook = pages.CreateChildPermission(AppPermissions.Pages_Tenant_PhoneBook, L("PhoneBook"), multiTenancySides: MultiTenancySides.Tenant);
phoneBook.CreateChildPermission(AppPermissions.Pages_Tenant_PhoneBook_CreatePerson, L("CreateNewPerson"), multiTenancySides: MultiTenancySides.Tenant);
First permission was defined before. In the second line, we are creating a child permission of first one.
This time, we're declaring AbpAuthorize attribute just for CreatePerson method:
[AbpAuthorize(AppPermissions.Pages_Tenant_PhoneBook_CreatePerson)]
public async Task CreatePerson(CreatePersonInput input)
{
//...
}
If we run the application and try to create a person, we get an authorization error after clicking the save button. But, it's good to completely hide Create New Person button if we don't have the permission. It's very simple:
Open the index.cshtml razor view and use IsGranted method:
@if (IsGranted(AppPermissions.Pages_Tenant_PhoneBook_CreatePerson))
{
<button id="CreateNewPersonButton" class="btn btn-primary blue"> @L("CreateNewPerson")</button>
}
In this way, the "Create New Person" button does not rendered in server and user can not see this button.
To see the button again, we can go to role or user manager and grant related permission as shown below:
As shown above, Create new person permission is a child permission of the Phone book.
We added Authorize attrbiutes to PersonAppService. This prevents unauthorized calls to this service. But unauthorized clients still can call actions of PhoneBookController actions. Since PhoneBookController uses PersonAppService, they will get authorization exception and can not use the service. But we can also secure MVC Controllers. This is suggested since some MVC actions may not use application services. Also, it's better to prevent unauthorized attemps at the very beginning.
We use AbpMvcAuthorize attribute for MVC Controllers as shown below:
[AbpMvcAuthorize(AppPermissions.Pages_Tenant_PhoneBook)]
public class PhoneBookController : PhoneBookControllerBase
{
...
[AbpMvcAuthorize(AppPermissions.Pages_Tenant_PhoneBook_CreatePerson)]
public PartialViewResult CreatePersonModal()
{
...
}
...
}
See authorization documentation for more information on authorization.
Let's add a delete button in people list as shown below:
We're starting from UI in this case.
We're changing index.cshtml view to add a button (related part is shown here):

@foreach (var person in Model.Items)
{
<a href="javascript:;" class="list-group-item"<EMAIL_ADDRESS>

@person.Name @person.Surname
@if (IsGranted(AppPermissions.Pages_Tenant_PhoneBook_DeletePerson))
{
<button title="@L("Delete")" class="btn btn-circle btn-icon-only red delete-person" href="javascript:;">

</button>
}

@person.EmailAddress

}

Surely, we defined 'delete person' permission as like before.
We're using a LESS style here to take button right. Created a file named index.less and added following lines:
#AllPeopleList {
.list-group-item-heading {
button.delete-person {
float: right;
}
}
}
And add the sytle to your Index.cshtml page (we added compiled and minified version to the page):
@section Styles
{
@Html.IncludeStyle("~/Areas/Mpa/Views/PhoneBook/Index.min.css")
}
Now, adding code to delete person (to Index.js):
var _personService = abp.services.app.person;
$('#AllPeopleList button.delete-person').click(function (e) {
e.preventDefault();
var $listItem = $(this).closest('.list-group-item');
var personId = $listItem.attr('data-person-id');
abp.message.confirm(
app.localize('AreYouSureToDeleteThePerson'),
function(isConfirmed) {
if (isConfirmed) {
_personService.deletePerson({
id: personId
}).done(function () {
abp.notify.info(app.localize('SuccessfullyDeleted'));
$listItem.remove();
});
}
}
);
});
It first shows a confirmation message when we click the delete button:
If we click Yes, it simply calls deletePerson method of PersonAppService and shows a notification if operation succeed. Also, removes the person from the page using jQuery's remove function.
First, adding a new method definition to IPersonAppService interface as always:
Task DeletePerson(EntityDto input);
IdInput is a shortcut of ABP if we only get an id value. Implementation (in PersonAppService) is very simple:
[AbpAuthorize(AppPermissions.Pages_Tenant_PhoneBook_DeletePerson)]
public async Task DeletePerson(EntityDto input)
{
await _personRepository.DeleteAsync(input.Id);
}
We also authorized deleting a person as did before for creating a person.
Now, we will implement search functionality of GetPeople method. UI is shown below:
We added a search input to filter people (showing the related part of the code):

@L("AllPeople") (@Model.Items.Count)

<form action="@Url.Action("Index")" method="GET">

<input id="FilterPeopleText" name="Filter"<EMAIL_ADDRESS>class="form-control" placeholder="@L("SearchWithThreeDot")" type="text">

<button id="FilterPeopleButton" class="btn default" type="submit"></button>

</form>

...

And added Filter property to the IndexViewModel:
[AutoMapFrom(typeof (ListResultDto<PersonListDto>))]
public class IndexViewModel : ListResultDto<PersonListDto>
{
public string Filter { get; set; }
public IndexViewModel(ListResultDto<PersonListDto> output, string filter = null)
{
output.MapTo(this);
Filter = filter;
}
}
Lastly, changed PhoneBookController's Index action to pass the filter to the IndexViewModel:
public ActionResult Index(GetPeopleInput input)
{
var output = _personAppService.GetPeople(input);
var model = new IndexViewModel(output, input.Filter);
return View(model);
}
That's all, It works! (Notice that; PersonAppService.GetPeople method was already using the input.Filter as we implemented it before).
Until now, we did not even mention about phone numbers. It's time to extend our domain to support multiple phone numbers for a person.
Let's start by creating a new Entity, Phone in .Core project:
[Table("PbPhones")]
public class Phone : CreationAuditedEntity<long>
{
public const int MaxNumberLength = 16;
[ForeignKey("PersonId")]
public virtual Person Person { get; set; }
public virtual int PersonId { get; set; }
[Required]
public virtual PhoneType Type { get; set; }
[Required]
[MaxLength(MaxNumberLength)]
public virtual string Number { get; set; }
}
Phone entities are stored in PbPhones table. It's primary key is long and inherits creation auditing properties. It has a reference to Person entity which owns the phone number.
We added a Phones collection to the People:
[Table("PbPersons")]
public class Person : FullAuditedEntity
{
//...other properties
public virtual ICollection<Phone> Phones { get; set; }
}
We have a PhoneType enum as shown below:
public enum PhoneType : byte
{
Mobile,
Home,
Business
}
Lastly, we're also adding a DbSet property for Phone to our DbContext:
public virtual IDbSet<Phone> Phones { get; set; }
Our entity model has changed, so we need to add a new migration:
This will create a new code based migration file to create PbPhones table:
public partial class Added_Phone : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.PbPhones",
c => new
{
Id = c.Long(nullable: false, identity: true),
PersonId = c.Int(nullable: false),
Type = c.Byte(nullable: false),
Number = c.String(nullable: false, maxLength: 16),
CreationTime = c.DateTime(nullable: false),
CreatorUserId = c.Long(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.PbPersons", t => t.PersonId, cascadeDelete: true)
.Index(t => t.PersonId);
}
public override void Down()
{
DropForeignKey("dbo.PbPhones", "PersonId", "dbo.PbPersons");
DropIndex("dbo.PbPhones", new[] { "PersonId" });
DropTable("dbo.PbPhones");
}
}
Before updating database, we can go to database seed code and add example phone numbers for example people:
public class InitialPeopleAndPhoneCreator
{
//...
public void Create()
{
var douglas = _context.Persons.FirstOrDefault(p => p.EmailAddress == "douglas.adams@fortytwo.net");
if (douglas == null)
{
_context.Persons.Add(
new Person
{
Name = "Douglas",
Surname = "Adams",
EmailAddress =<EMAIL_ADDRESS>Phones = new List<Phone>
{
new Phone {Type = PhoneType.Home, Number = "1112242"},
new Phone {Type = PhoneType.Mobile, Number = "2223342"}
}
});
}
var asimov = _context.Persons.FirstOrDefault(p => p.EmailAddress == "isaac.asimov@foundation.org");
if (asimov == null)
{
_context.Persons.Add(
new Person
{
Name = "Isaac",
Surname = "Asimov",
EmailAddress =<EMAIL_ADDRESS>Phones = new List<Phone>
{
new Phone {Type = PhoneType.Home, Number = "8889977"}
}
});
}
}
}
We added two phone number to Douglas, one phone number to Isaac. But if we run Update-Database now, phones are not inserted since this seed code checks if people exists, and does not insert if it's already exists. What's solution? Since we haven't deployed yet, we can delete database (or at lease truncate people table) and re-create it. I do it.
Now, we are running Update-Database command in Package Manager Console to re-create database and seed it. You can check database to see PbPhones table and rows.
We're changing PersonAppService.GetPeople method to include phone numbers of people into return value.
First, we're changing PersonListDto to contain a list of phones:
[AutoMapFrom(typeof(Person))]
public class PersonListDto : FullAuditedEntityDto
{
public string Name { get; set; }
public string Surname { get; set; }
public string EmailAddress { get; set; }
public Collection<PhoneInPersonListDto> Phones { get; set; }
}
[AutoMapFrom(typeof(Phone))]
public class PhoneInPersonListDto : CreationAuditedEntityDto<long>
{
public PhoneType Type { get; set; }
public string Number { get; set; }
}
So, added also a DTO to transfer phone numbers and mapped from Phone entity. Now, we can change GetPeople method to get Phones from database:
public ListResultDto<PersonListDto> GetPeople(GetPeopleInput input)
{
var persons = _personRepository
.GetAll()
.Include(p => p.Phones)
.WhereIf(
!input.Filter.IsNullOrEmpty(),
p => p.Name.Contains(input.Filter) ||
p.Surname.Contains(input.Filter) ||
p.EmailAddress.Contains(input.Filter)
)
.OrderBy(p => p.Name)
.ThenBy(p => p.Surname)
.ToList();
return new ListResultDto<PersonListDto>(persons.MapTo<List<PersonListDto>>());
}
We only added Include extension method to the query. Rest of the codes remains same. Furthermore, it would work without adding this, but much slower (since it will lazy load phone numbers for every person seperately).
We are adding two more methods to IPersonAppService interface as shown below:
Task DeletePhone(EntityDto<long> input);
Task<PhoneInPersonListDto> AddPhone(AddPhoneInput input);
We could create a new, seperated IPhoneAppService. It's your choice. But, we can consider Person as an aggregate and add phone related methods here. AddPhoneInput DTO is shown below:
[AutoMapTo(typeof(Phone))]
public class AddPhoneInput
{
[Range(1, int.MaxValue)]
public int PersonId { get; set; }
[Required]
public PhoneType Type { get; set; }
[Required]
[MaxLength(Phone.MaxNumberLength)]
public string Number { get; set; }
}
Now, we can implement these methods:
public async Task DeletePhone(EntityDto<long> input)
{
await _phoneRepository.DeleteAsync(input.Id);
}
public async Task<PhoneInPersonListDto> AddPhone([FromBody]AddPhoneInput input)
{
var person = _personRepository.Get(input.PersonId);
var phone = input.MapTo<Phone>();
person.Phones.Add(phone);
await CurrentUnitOfWork.SaveChangesAsync();
return phone.MapTo<PhoneInPersonListDto>();
}
(Note: We injected IRepository<Phone, long> in the constructor and set to _personRepository field)
DeletePhone method is simple. It only deletes phone with given id.
AddPhone method gets the person from database and add new phone to person.Phones collection. Then is save changes. Saving changes causes inserting new added phone to database and get it's Id. Because, we are returning a DTO that contains newly created phone informations including Id. So, it should be assigned before mapping in the last line. (Notice that; normally it's not needed to call CurrentUnitOfWork.SaveChangesAsync. It's automatically called at the end of the method. We called it in the method since we need to save entity and get it's Id immediately. See UOW document for more.)
There may be different approaches for AddPhone method. You can directly work with a phone repository to insert new phone. They all have different pros and cons. It's your choice.
Final UI is shown below:
When we click the green edit icon for a person, it's row is expanded and all phone numbers are shown. Then we can delete any number by clicking the icon at left. We can add a new phone from the inputs at last line.
Changes in view are shown below:

@foreach (var person in Model.Items)
{
<a href="javascript:;" class="list-group-item"<EMAIL_ADDRESS>

@person.Name @person.Surname

<button title="@L("Edit")" class="btn btn-circle btn-icon-only green edit-person">

</button>
@if (IsGranted(AppPermissions.Pages_Tenant_PhoneBook_DeletePerson))
{
<button title="@L("Delete")" class="btn btn-circle btn-icon-only red delete-person" href="javascript:;">

</button>
}

@person.EmailAddress

@L("Type")
@L("PhoneNumber")

@foreach (var phone in person.Phones)
{
@Html.Partial("_PhoneRowInPersonList", new PhoneRowInPersonListViewModel(phone))
}

<button class="btn btn-sm green button-save-phone">

</button>

<select name="Type">
<option value="0">@L("PhoneType_Mobile")</option>
<option value="1">@L("PhoneType_Home")</option>
<option value="2">@L("PhoneType_Business")</option>
</select>

<input type="text" name="Number" />

}

We added an edit button for each person. Then added a table for each person that shows phones of the related person and allows adding a new phone. Phones table is only shown if we click the edit button. This is implemented using a bit CSS and javascript (we will see in next sections).
One important think here is we rendered phone rows in a partial view. This is done to make this part re-usable. Because we will use the same partial view when we create a new phone. The _PhoneRowInPersonList partial view is here:
@model Acme.PhoneBook.Web.Areas.Mpa.Models.PhoneBook.PhoneRowInPersonListViewModel
<tr<EMAIL_ADDRESS>
<button class="btn btn-sm default button-delete-phone">

</button>

@Model.GetPhoneTypeAsString()
<EMAIL_ADDRESS>

And the PhoneRowInPersonListViewModel is here:
public class PhoneRowInPersonListViewModel
{
public PhoneInPersonListDto Phone { get; set; }
public PhoneRowInPersonListViewModel(PhoneInPersonListDto phone)
{
Phone = phone;
}
public string GetPhoneTypeAsString()
{
return LocalizationHelper.GetString(PhoneBookConsts.LocalizationSourceName, "PhoneType_" + Phone.Type);
}
}
Changed Index.less a bit to adapt to the changed view:
#AllPeopleList { .list-group-item-heading { span.person-buttons { float: right; } } .table-phones { display: none; } .person-editing { background-color: #ccffcc; h4 { font-weight: bold; } .table-phones { display: table; } } }
Added following codes into Index.js:
//Edit person button
$('#AllPeopleList button.edit-person').click(function (e) {
e.preventDefault();
var $listItem = $(this).closest('.list-group-item');
$listItem
.toggleClass('person-editing')
.siblings().removeClass('person-editing');
});
//Save phone button
$('#AllPeopleList .button-save-phone').click(function (e) {
e.preventDefault();
var $phoneEditorRow = $(this).closest('tr');
abp.ajax({
url: abp.appPath + 'Mpa/PhoneBook/AddPhone',
dataType: 'html',
data: JSON.stringify({
personId: $phoneEditorRow.closest('.list-group-item').attr('data-person-id'),
Type: $phoneEditorRow.find('select[name=Type]').val(),
Number: $phoneEditorRow.find('input[name=Number]').val()
})
}).done(function (result) {
$(result).insertBefore($phoneEditorRow);
});
});
//Delete phone button
$('#AllPeopleList').on('click', '.button-delete-phone', function (e) {
e.preventDefault();
var $phoneRow = $(this).closest('tr');
var phoneId = $phoneRow.attr('data-phone-id');
_personService.deletePhone({
id: phoneId
}).done(function () {
abp.notify.success(app.localize('SuccessfullyDeleted'));
$phoneRow.remove();
});
});
When click to 'edit person' button, we simple open/close (toggle) the phones table of related person by using css classes.
In the 'save phone' button's click, we make an AJAX request to PhoneBookController's AddPhone action. Server returns an HTML which is then inserted to the table. That's why we did this part partial (We will see PhoneBookController.AddPhone action in the next section).
Lastly, we deleting the phone when clicking to the 'delete phone' button and remove the related phone row (tr) from DOM. Notice the event registration here. We used on function of jQuery. Thus, the selector becomes live. That means, if we add new elements to the page and any element matches to the selector, it's click event is automatically binded.
We added AddPhone action to the PhoneController as shown below:
[HttpPost]
public async Task<PartialViewResult> AddPhone(AddPhoneInput input)
{
PhoneInPersonListDto phoneInPersonList = await _personAppService.AddPhone(input);
var model = new PhoneRowInPersonListViewModel(phoneInPersonList);
return PartialView("_PhoneRowInPersonList", model);
}
It simply uses PersonAppService.AddPhone and returns _PhoneRowInPersonList partial view as response. Thus, we directly insert returning value to the table. A sample return value is shown below:

<button class="btn btn-sm default button-delete-phone">

</button>

Mobile
129838172

As you see, this can be directly inserted to the table, as we already do.
We have built a fully functional application until here. Now, we will see how to convert it to a multi-tenant application easily.
We disabled multi-tenancy at the begginning of this document. Now, re-enabling it in PhoneBookCoreModule class:
Configuration.MultiTenancy.IsEnabled = true;
In a multi-tenant application, a tenant's entities should be isolated by other tenants. For this example project, every tenant should have own phone book with isolated people and phone numbers.
When we implement IMustHaveTenant interface, ABP automatically filters data based on current Tenant, while retrieving entities from database. So, we should declare that Person entity must have a tenant using IMustHaveTenant interface:
public class Person : FullAuditedEntity, IMustHaveTenant
{
public virtual int TenantId { get; set; }
//...other properties
}
We may want to add IMustHaveTenant interface to also Phone entity. This is needed if we directly use phone repository to get phones. In this sample project, it's not needed.
Since entities have changed, we should create a new database migration:
Add-Migration "Implemented_IMustHaveTenant_For_Person"
This command creates a new code-first database migration. The migration class adds an annotation this is needed for automatic filtering. We don't have to know what it is since it's done automatically. And also it adds a TenantId column to PbPersons table as shown below:
AddColumn("dbo.PbPersons", "TenantId", c => c.Int(nullable: false, defaultValue: 1));
I added defaultValue as 1 to AddColumn options. Thus, current people are automatically assigned to default tenant (default tenant's id is 1).
Now, we can update the database again:
Update-Database
It's finished! We can test the application. Run the project, login as host as shown blow:
Since we enabled multi-tenancy, we see a Tenancy name input on login form. When we leave it empty, we login as a host user. Default admin password is 123qwe.
After login, we see the tenant list which only contains a default tenant. We can create a new tenant:
I created a new tenant named trio. Now, tenant list has two tenants:
I can logout and login as trio tenant admin:
After login, we see that phone book is empty:
It's empty because trio tenant has a completely islolated people list. You can add people here, logout and login as different teants (you can login as default tenant for example). You will see that each tenant has an isolated phone book and can not see other's people.
In this document, we built a complete example that covers most parts of the ASP.NET Zero system. We hope that it will help you to build your own application.
We intentionally used different approaches for similar tasks to show you different styles of development. ASP.NET Zero provides an architecture but does not restrict you. You can make your own style development.
You should purchase ASP.NET Zero in order to get source code. After purchasing, you can get the sample project from private Github repository: https://github.com/aspnetzero/aspnet-zero-samples


Release history¶
Release notes¶
Qiskit Terra 0.6.0¶
This release includes a redesign of internal components centered around a new,
formal communication format (Qobj
), along with long awaited features to
improve the user experience as a whole. The highlights, compared to the 0.5
release, are:
- Improvements for inter-operability (based on the
Qobj
specification) and extensibility (facilities for extending Qiskit with new backends in a seamless way). - New options for handling credentials and authentication for the IBM Q backends, aimed at simplifying the process and supporting automatic loading of user credentials.
- A revamp of the visualization utilities: stylish interactive visualizations are now available for Jupyter users, along with refinements for the circuit drawer (including a matplotlib-based version).
- Performance improvements centered around circuit transpilation: the basis for a more flexible and modular architecture have been set, including paralellization of the circuit compilation and numerous optimizations.
Upgrading to 0.6.0¶
Please note that some backwards-incompatible changes have been introduced during this release - the following notes contain information on how to adapt to the new changes.
Removal of QuantumProgram
¶
As hinted during the 0.5 release, the deprecation of the QuantumProgram
class has now been completed and is no longer available, in favor of working
with the individual components (BaseJob
,
QuantumCircuit
,
ClassicalRegister
,
QuantumRegister
,
qiskit
) directly.
Please check the 0.5 release notes and the Getting Started examples for details about the transition
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
from qiskit import available_backends, execute
q = QuantumRegister(2)
c = ClassicalRegister(2)
qc = QuantumCircuit(q, c)
qc.h(q[0])
qc.cx(q[0], q[1])
qc.measure(q, c)
print("Local backends: ", available_backends({'local': True}))
job_sim = execute(qc, "local_qasm_simulator")
sim_result = job_sim.result()
print("simulation: ", sim_result)
print(sim_result.get_counts(qc))
IBM Q Authentication and Qconfig.py
¶
The managing of credentials for authenticating when using the QX backends has been expanded, and there are new options that can be used for convenience:
save your credentials in disk once, and automatically load them in future sessions. This provides a one-off mechanism:
from qiskit import IBMQ IBQM.save_account('MY_API_TOKEN', 'MY_API_URL')
afterwards, your credentials can be automatically loaded from disk by invoking
load_accounts()
:from qiskit import IBMQ IBMQ.load_accounts()
or you can load only specific accounts if you only want to use those in a session:
IBMQ.load_accounts(project='MY_PROJECT')
use environment variables. If
QE_TOKEN
andQE_URL
is set, theIBMQ.load_accounts()
call will automatically load the credentials from them.
Additionally, the previous method of having a Qconfig.py
file in the program
folder and passing the credentials explicitly is still supported. Please check
the 3. Configure your API token and QE credentials section for more details about combining and using
the different authentication options.
Working with backends¶
A new mechanism has been introduced in Terra 0.6 as the recommended way for obtaining
a backend, allowing for more powerful and unified filtering and integrated with
the new credentials system. The previous top-level methods
register()
,
available_backends()
and
get_backend()
are still supported, but will
deprecated in upcoming versions in favor of using the qiskit.IBMQ and
qiskit.Aer objects directly, which allow for more complex filtering.
For example, to list and use a local backend:
from qiskit import Aer
all_local_backends = Aer.backends(local=True) # returns a list of instances
qasm_simulator = Aer.backends('qasm_simulator')
And for listing and using remote backends:
from qiskit import IBMQ
IBMQ.enable_account('MY_API_TOKEN')
5_qubit_devices = IBMQ.backends(simulator=True, n_qubits=5)
ibmqx4 = IBMQ.get_backend('ibmqx4')
Please note as well that the names of the local simulators have been simplified. The previous names can still be used, but it is encouraged to use the new, shorter names:
| Qiskit Terra 0.5 | Qiskit Terra 0.6 |
|---|---|
| ‘local_qasm_simulator’ | ‘qasm_simulator’ |
| ‘local_statevector_simulator’ | ‘statevector_simulator’ |
| ‘local_unitary_simulator_py’ | ‘unitary_simulator’ |
Backend and Job API changes¶
Jobs submitted to IBM Q backends have improved capabilities. It is possible to cancel them and replenish credits (
job.cancel()
), and to retrieve previous jobs executed on a specific backend either by job id (backend.retrieve_job(job_id)
) or in batch of latest jobs (backend.jobs(limit)
)Properties for checking each individual job status (
queued
,running
,validating
,done
andcancelled
) no longer exist. If you want to check the job status, use the identity comparison againstjob.status
:from qiskit.backends import JobStatus job = execute(circuit, backend) if job.status() is JobStatus.RUNNING: handle_job(job)
Please consult the new documentation of the
IBMQJob
class to get further insight in
how to use the simplified API.
- A number of members of
BaseBackend
andBaseJob
are no longer properties, but methods, and as a result they need to be invoked as functions.
| Qiskit Terra 0.5 | Qiskit Terra 0.6 |
|---|---|
| backend.name | backend.name() |
| backend.status | backend.status() |
| backend.configuration | backend.configuration() |
| backend.calibration | backend.properties() |
| backend.parameters | backend.jobs() backend.retrieve_job(job_id) |
| job.status | job.status() |
| job.cancelled | job.queue_position() |
| job.running | job.cancel() |
| job.queued | |
| job.done |
Better Jupyter tools¶
The new release contains improvements to the user experience while using Jupyter notebooks.
First, new interactive visualizations of counts histograms and quantum states are provided:
plot_histogram()
and plot_state()
.
These methods will default to the new interactive kind when the environment is Jupyter and internet
connection exists.
Secondly, the new release provides Jupyter cell magics for keeping track of the progress of your code.
Use %%qiskit_job_status
to keep track of the status of submitted jobs to IBMQ backends.
Use %%qiskit_progress_bar
to keep track of the progress of compilation/execution.
Qiskit Terra 0.5.0¶
This release brings a number of improvements to Qiskit, both for the user experience and under the hood. Please refer to the full changelog for a detailed description of the changes - the highlights are:
- new
statevector
simulators
and feature and performance improvements to the existing ones (in particular to the C++ simulator), along with a reorganization of how to work with backends focused on extensibility and flexibility (using aliases and backend providers). - reorganization of the asynchronous features, providing a friendlier interface
for running jobs asynchronously via
Job
instances. - numerous improvements and fixes throughout the SDK as a whole, both for convenience of the users (such as allowing anonymous registers) and for enhanced functionality (such as improved plotting of circuits).
Upgrading to 0.5.0¶
Please note that several backwards-incompatible changes have been introduced during this release as a result of the ongoing development. While some of these features will continue to be supported during a period of time before being fully deprecated, it is recommended to update your programs in order to prepare for the new versions and take advantage of the new functionality.
QuantumProgram
changes¶
Several methods of the QuantumProgram
class are on their way
to being deprecated:
methods for interacting with the backends and the API:
The recommended way for opening a connection to the IBMQ API and for using the backends is through the top-level functions directly instead of the
QuantumProgram
methods. In particular, theqiskit.register()
method provides the equivalent of the previousqiskit.QuantumProgram.set_api()
call. In a similar vein, there is a newqiskit.available_backends()
,qiskit.get_backend()
and related functions for querying the available backends directly. For example, the following snippet for version 0.4:from qiskit import QuantumProgram quantum_program = QuantumProgram() quantum_program.set_api(token, url) backends = quantum_program.available_backends() print(quantum_program.get_backend_status('ibmqx4')
would be equivalent to the following snippet for version 0.5:
from qiskit import register, available_backends, get_backend register(token, url) backends = available_backends() backend = get_backend('ibmqx4') print(backend.status)
methods for compiling and executing programs:
The top-level functions now also provide equivalents for the
qiskit.QuantumProgram.compile()
andqiskit.QuantumProgram.execute()
methods. For example, the following snippet from version 0.4:quantum_program.execute(circuit, args, ...)
would be equivalent to the following snippet for version 0.5:
from qiskit import execute execute(circuit, args, ...)
In general, from version 0.5 onwards we encourage to try to make use of the
individual objects and classes directly instead of relying on
QuantumProgram
. For example, a QuantumCircuit
can be
instantiated and constructed by appending QuantumRegister
,
ClassicalRegister
, and gates directly. Please check the
update example in the Quickstart section, or the
using_qiskit_core_level_0.py
and using_qiskit_core_level_1.py
examples on the main repository.
Backend name changes¶
In order to provide a more extensible framework for backends, there have been some design changes accordingly:
local simulator names
The names of the local simulators have been homogenized in order to follow the same pattern:
PROVIDERNAME_TYPE_simulator_LANGUAGEORPROJECT
- for example, the C++ simulator previously namedlocal_qiskit_simulator
is nowlocal_qasm_simulator_cpp
. An overview of the current simulators:QASM
simulator is supposed to be like an experiment. You apply a circuit on some qubits, and observe measurement results - and you repeat for many shots to get a histogram of counts viaresult.get_counts()
.Statevector
simulator is to get the full statevector (\(2^n\) amplitudes) after evolving the zero state through the circuit, and can be obtained viaresult.get_statevector()
.Unitary
simulator is to get the unitary matrix equivalent of the circuit, returned viaresult.get_unitary()
.- In addition, you can get intermediate states from a simulator by applying
a
snapshot(slot)
instruction at various spots in the circuit. This will save the current state of the simulator in a given slot, which can later be retrieved viaresult.get_snapshot(slot)
.
backend aliases:
The SDK now provides an “alias” system that allows for automatically using the most performant simulator of a specific type, if it is available in your system. For example, with the following snippet:
from qiskit import get_backend backend = get_backend('local_statevector_simulator')
the backend will be the C++ statevector simulator if available, falling back to the Python statevector simulator if not present.
More flexible names and parameters¶
Several functions of the SDK have been made more flexible and user-friendly:
automatic circuit and register names
qiskit.ClassicalRegister
,qiskit.QuantumRegister
andqiskit.QuantumCircuit
can now be instantiated without explicitly giving them a name - a new autonaming feature will automatically assign them an identifier:q = QuantumRegister(2)
Please note as well that the order of the parameters have been swapped
QuantumRegister(size, name)
.methods accepting names or instances
In combination with the autonaming changes, several methods such as
qiskit.Result.get_data()
now accept both names and instances for convenience. For example, when retrieving the results for a job that has a single circuit such as:qc = QuantumCircuit(..., name='my_circuit') job = execute(qc, ...) result = job.result()
The following calls are equivalent:
data = result.get_data('my_circuit') data = result.get_data(qc) data = result.get_data()
Changelog¶
Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog.
Types of changes:
- Added: for new features.
- Changed: for changes in existing functionality.
- Deprecated: for soon-to-be removed features.
- Removed: for now removed features.
- Fixed: for any bug fixes.
- Security: in case of vulnerabilities.
UNRELEASED¶
Changed¶
0.6.0 - 2018-10-04¶
Added¶
- Added SchemaValidationError to be thrown when schema validation fails (#881)
- Generalized Qobj schema validation functions for all qiskit schemas (#882).
- Added decorator to check for C++ simulator availability (#662)
- It is possible to cancel jobs in non comercial backends (#687)
- Introduced new qiskit.IBMQ provider, with centralized handling of IBMQ credentials (qiskitrc file, environment variables). (#547, #948, #1000)
- Add OpenMP parallelization for Apple builds of the cpp simulator (#698).
- Add parallelization utilities (#701)
- Parallelize transpilation (#701)
- New interactive visualizations (#765).
- Added option to reverse the qubit order when plotting a circuit. (#762, #786)
- Jupyter notebook magic function qiskit_job_status, qiskit_progress_bar (#701, #734)
- Add a new function
qobj_to_circuits
to convert a Qobj object to a list of QuantumCircuit objects (#877) - Allow selective loading of accounts from disk via hub/group/project filters to IBMQ.load_accounts().
Changed¶
- Schema tests in tests/schemas/test_schemas.py replaced with proper unit test (#834).
- Renamed
QISKit
toQiskit
in the documentation. (#634) - Use
Qobj
as the formally defined schema for sending information to the devices: - introduce theqiskit.qobj
module. (#589, #655) - update theQobj
JSON schema. (#668, #677, #703, #709) - update the local simulators for acceptingQobj
as input. (#667) - update theResult
class. (#773) - Use
get_status_job()
for checking IBMQJob status. (#641) - Q network hub/group/project credentials replaced by new url format. (#740)
- Breaking change:
Jobs
API simplification. (#686) - Breaking change: altered tomography APIs to not use QuantumProgram. (#818)
- Breaking change:
BaseBackend
API changed, properties are now methods (#858) - When
plot_histogram()
orplot_state()
are called from a jupyter notebook if there is network connectivity the interactive plots will be used by default (#862, #866) - Breaking change:
BaseJob
API changed, any job constructor must be passed the backend used to run them and a unique job id (#936). - Add support for drawing circuit barriers to the latex circuit drawer. This requires having the LaTeX qcircuit package version >=2.6.0 installed (#764)
Deprecated¶
- The
number_to_keep
kwarg on theplot_histogram()
function is now deprecated. A field of the same name should be used in theoption
dictionary kwarg instead. (#866) - Breaking change:
backend.properties()
instead ofbackend.calibration()
andbackend.parameters()
(#870)
Removed¶
- Removed the QuantumProgram class. (#724)
Fixed¶
- Fixed
get_ran_qasm
methods onResult
instances (#688). - Fixed
probabilities_ket
computation in C++ simulator (#580). - Fixed bug in the definition of
cswap
gate and its test (#685). - Fixed the examples to be compatible with version 0.5+ (#672).
- Fixed swap mapper using qubits after measurement (#691).
- Fixed error in cpp simulator for 3+ qubit operations (#698).
- Fixed issue with combining or extending circuits that contain CompositeGate (#710).
- Fixed the random unitary generation from the Haar measure (#760).
- Fixed the issue with control lines spanning through several classical registers (#762).
- Fixed visualizations crashing when using simulator extensions (#885).
- Fixed check for network connection when loading interactive visualizations (#892).
0.5.6 - 2018-07-06¶
Changed¶
- Rename repository to
qiskit-terra
(#606). - Update Bloch sphere to QuTiP version (#618).
- Adjust margin of matplotlib_circuit_drawer (#632)
Removed¶
- Remove OpenQuantumCompiler (#610).
Fixed¶
- Fixed broken process error and simulator slowdown on Windows (#613).
- Fixed yzy_to_zyz bugs (#520, #607) by moving to quaternions (#626).
0.5.5 - 2018-07-02¶
Added¶
- Retrieve IBM Q jobs from server (#563, #585).
- Add German introductory documentation (
doc/de
) (#592). - Add
unregister()
for removing previously registered providers (#584). - Add matplotlib-based circuit drawer (#579).
- Adding backend filtering by least busy (#575).
- Allow running with new display names for IBMQ devices,
and return those from
available_backends()
(#566) - Introduce Qiskit Transpiler and refactor compilation flow (#578)
- Add CXCancellation pass (#578)
Changed¶
- Remove backend filtering in individual providers, keep only in wrapper (#575).
- Single source of version information (#581)
- Bumped IBMQuantumExperience dependency to 1.9.6 (#600).
- For backend status, status[‘available’] is now status[‘operational’] (#609).
- Added support for registering third-party providers in register() (#602).
- Order strings in the output of
available_backends()
(#566)
Removed¶
- Remove Clifford simulator from default available_backends, until its stable release (#555).
- Remove ProjectQ simulators for moving to new repository (#553).
- Remove QuantumJob class (#616)
Fixed¶
- Fix issue with unintended inversion of initializer gates (#573).
- Fix issue with skip_transpiler causing some gates to be ignored silently (#562).
0.5.4 - 2018-06-11¶
Added¶
- Performance improvements:
- remove deepcopies from dagcircuit, and extra check on qasm() (#523).
Changed¶
- Rename repository to
qiskit-core
(#530). - Repository improvements: new changelog format (#535), updated issue templates (#531).
- Renamed the specification schemas (#464).
- Convert
LocalJob
tests into unit-tests. (#526) - Move wrapper
load_qasm_*
methods to a submodule (#533).
Removed¶
- Remove Sympy simulators for moving to new repository (#514)
Fixed¶
- Fix erroneous density matrix and probabilities in C++ simulator (#518)
- Fix hardcoded backend mapping tests (#521)
- Removed
_modifiers call
fromreapply
(#534) - Fix circuit drawer issue with filename location on windows (#543)
- Change initial qubit layout only if the backend coupling map is not satisfied (#527)
- Fix incorrect unrolling of t to tdg in CircuitBackend (#557)
- Fix issue with simulator extension commands not reapplying correctly (#556)
0.5.3 - 2018-05-29¶
Added¶
- load_qasm_file / load_qasm_string methods
Changed¶
- Dependencies version bumped
Fixed¶
- Crash in the cpp simulator for some linux platforms
- Fixed some minor bugs
0.5.2 - 2018-05-21¶
Changed¶
- Adding Result.get_unitary()
Deprecated¶
- Deprecating
ibmqx_hpc_qasm_simulator
andibmqx_qasm_simulator
in favor ofibmq_qasm_simulator
.
Fixed¶
- Fixing a Mapper issue.
- Fixing Windows 7 builds.
0.5.1 - 2018-05-15¶
There are no code changes.
MacOS simulator has been rebuilt with external user libraries compiled statically, so there’s no need for users to have a preinstalled gcc environment.
Pypi forces us to bump up the version number if we want to upload a new package, so this is basically what have changed.
0.5.0 - 2018-05-11¶
Improvements¶
- Introduce providers and rework backends (#376).
- Split backends into
local
andibmq
. - Each provider derives from the following classes for its specific
requirements (
BaseProvider
,BaseBackend
,BaseJob
). - Allow querying result by both circuit name and QuantumCircuit instance.
- Split backends into
- Introduce the Qiskit
wrapper
(#376). - Introduce convenience wrapper functions around commonly used Qiskit
components (e.g.
compile
andexecute
functions). - Introduce the DefaultQISKitProvider, which acts as a context manager for
the current session (e.g. providing easy access to all
available_backends
). - Avoid relying on QuantumProgram (eventual deprecation).
- The functions are also available as top-level functions (for example,
qiskit.get_backend()
).
- Introduce convenience wrapper functions around commonly used Qiskit
components (e.g.
- Introduce the Qiskit
- Introduce
BaseJob
class and asynchronous jobs (#403). - Return
BaseJob
afterrun()
. - Mechanisms for querying
status
andresults
, or tocancel
a job.
- Return
- Introduce
- Introduce a
skip_transpiler
flag forcompile()
(#411). - Introduce schemas for validating interfaces between qiskit and backends (#434)
- qobj_schema
- result_schema
- job_status_schema
- default_pulse_config_schema
- backend_config_schema
- backend_props_schema
- backend_status_schema
- Improve C++ simulator (#386)
- Add
tensor_index.hpp
for multi-partite qubit vector indexing. - Add
qubit_vector.hpp
for multi-partite qubit vector algebra. - Rework C++ simulator backends to use QubitVector class instead of
std::vector
.
- Add
- Improve interface to simulator backends (#435)
- Introduce
local_statevector_simulator_py
andlocal_statevector_simulator_cpp
. - Introduce aliased and deprecated backend names and mechanisms for resolving them.
- Introduce optional
compact
flag to query backend names only by unique function. - Introduce result convenience functions
get_statevector
,get_unitary
- Add
snapshot
command for caching a copy of the current simulator state.
- Introduce
- Introduce circuit drawing via
circuit_drawer()
andplot_circuit()
(#295, #414) - Introduce benchmark suite for performance testing
(
test/performance
) (#277) - Introduce more robust probability testing via assertDictAlmostEqual (#390)
- Allow combining circuits across both depth and width (#389)
- Enforce string token names (#395)
Fixed¶
- Fix coherent error bug in
local_qasm_simulator_cpp
(#318) - Fix the order and format of result bits obtained from device backends (#430)
- Fix support for noises in the idle gate of
local_clifford_simulator_cpp
(#440) - Fix JobProcessor modifying input qobj (#392) (and removed JobProcessor during #403)
- Fix ability to apply all gates on register (#369)
Deprecated¶
- Some methods of
QuantumProgram
are soon to be deprecated. Please use the top-level functions instead. - The
Register
instantiation now expectssize, name
. Usingname, size
is still supported but will be deprecated in the future. - Simulators no longer return wavefunction by setting shots=1. Instead,
use the
local_statevector_simulator
, or explicitly ask forsnapshot
. - Return
job
instance afterrun()
, rather thanresult
. - Rename simulators according to
PROVIDERNAME_SIMPLEALIAS_simulator_LANGUAGEORPROJECT
- Move simulator extensions to
qiskit/extensions/simulator
- Move Rzz and CSwap to standard extension library
0.4.15 - 2018-05-07¶
Fixed¶
- Fixed an issue with legacy code that was affecting Developers Challenge.
0.4.14 - 2018-04-18¶
Fixed¶
- Fixed an issue about handling Basis Gates parameters on backend configurations.
0.4.13 - 2018-04-16¶
Changed¶
- OpenQuantumCompiler.dag2json() restored for backward compatibility.
Fixed¶
- Fixes an issue regarding barrier gate misuse in some circumstances.
0.4.12 - 2018-03-11¶
Changed¶
- Improved circuit visualization.
- Improvements in infrastructure code, mostly tests and build system.
- Better documentation regarding contributors.
Fixed¶
- A bunch of minor bugs have been fixed.
0.4.11 - 2018-03-13¶
Added¶
- More testing :)
Changed¶
- Stabilizing code related to external dependencies.
Fixed¶
- Fixed bug in circuit drawing where some gates in the standard library were not plotting correctly.
0.4.10 - 2018-03-06¶
Added¶
- Chinese translation of README.
Changed¶
- Changes related with infrastructure (linter, tests, automation) enhancement.
Fixed¶
- Fix installation issue when simulator cannot be built.
- Fix bug with auto-generated CNOT coherent error matrix in C++ simulator.
- Fix a bug in the async code.
0.4.9 - 2018-02-12¶
Changed¶
- CMake integration.
- QASM improvements.
- Mapper optimizer improvements.
Fixed¶
- Some minor C++ Simulator bug-fixes.
0.4.8 - 2018-01-29¶
Fixed¶
- Fix parsing U_error matrix in C++ Simulator python helper class.
- Fix display of code-blocks on
.rst
pages.
0.4.7 - 2018-01-26¶
Changed¶
- Changes some naming conventions for
amp_error
noise parameters tocalibration_error
.
Fixed¶
- Fixes several bugs with noise implementations in the simulator.
- Fixes many spelling mistakes in simulator README.
0.4.6 - 2018-01-22¶
Changed¶
We have upgraded some of out external dependencies to:
- matplotlib >=2.1,<2.2
- networkx>=1.11,<2.1
- numpy>=1.13,<1.15
- ply==3.10
- scipy>=0.19,<1.1
- Sphinx>=1.6,<1.7
- sympy>=1.0
0.4.4 - 2018-01-09¶
Changed¶
- Update dependencies to more recent versions.
Fixed¶
- Fix bug with process tomography reversing qubit preparation order.
0.4.3 - 2018-01-08¶
Removed¶
- Static compilation has been removed because it seems to be failing while installing Qiskit via pip on Mac.
0.4.0 - 2018-01-08¶
Added¶
- Job handling improvements.
- Allow asynchronous job submission.
- New JobProcessor class: utilizes concurrent.futures.
- New QuantumJob class: job description.
- Modularize circuit “compilation”.
- Takes quantum circuit and information about backend to transform circuit into one which can run on the backend.
- Standardize job description.
- All backends take QuantumJob objects which wraps
qobj
program description.
- Simplify addition of backends, where circuits are run/simulated.
qiskit.backends
package added.- Real devices and simulators are considered “backends” which inherent from
BaseBackend
.
- Reorganize and improve Sphinx documentation.
- Improve unittest framework.
- Add tools for generating random circuits.
- New utilities for fermionic Hamiltonians (
qiskit/tools/apps/fermion
). - New utilities for classical optimization and chemistry
(
qiskit/tools/apps/optimization
). - Randomized benchmarking data handling.
- Quantum tomography (
qiskit/tools/qcvv
). - Added functions for generating, running and fitting process tomography experiments.
- Quantum tomography (
- Quantum information functions (
qiskit/tools/qi
). - Partial trace over subsystems of multi-partite vector.
- Partial trace over subsystems of multi-partite matrix.
- Flatten an operator to a vector in a specified basis.
- Generate random unitary matrix.
- Generate random density matrix.
- Generate normally distributed complex matrix.
- Generate random density matrix from Hilbert-Schmidt metric.
- Generate random density matrix from the Bures metric.
- Compute Shannon entropy of probability vector.
- Compute von Neumann entropy of quantum state.
- Compute mutual information of a bipartite state.
- Compute the entanglement of formation of quantum state.
- Quantum information functions (
- Visualization improvements (
qiskit/tools
). - Wigner function representation.
- Latex figure of circuit.
- Visualization improvements (
- Use python logging facility for info, warnings, etc.
- Auto-deployment of sphinx docs to github pages.
- Check IBMQuantumExperience version at runtime.
- Add QuantumProgram method to reconfigure already generated qobj.
- Add Japanese introductory documentation (
doc/ja
). - Add Korean translation of readme (
doc/ko
). - Add appveyor for continuous integration on Windows.
- Enable new IBM Q parameters for hub/group/project.
- Add QuantumProgram methods for destroying registers and circuits.
- Use Sympy for evaluating expressions.
- Add support for ibmqx_hpc_qasm_simulator backend.
- Add backend interface to Project Q C++ simulator.
- Requires installation of Project Q.
- Introduce
InitializeGate
class. - Generates circuit which initializes qubits in arbitrary state.
- Introduce
- Introduce
local_qiskit_simulator
a C++ simulator with realistic noise. - Requires C++ build environment for
make
-based build.
- Introduce
- Introduce
local_clifford_simulator
a C++ Clifford simulator. - Requires C++ build environment for
make
-based build.
- Introduce
Changed¶
- The standard extension for creating U base gates has been modified to be consistent with the rest of the gate APIs (see #203).
Removed¶
- The
silent
parameter has been removed from a number ofQuantumProgram
methods. The same behaviour can be achieved now by using theenable_logs()
anddisable_logs()
methods, which use the standard Python logging.
Fixed¶
- Fix basis gates (#76).
- Enable QASM parser to work in multiuser environments.
- Correct operator precedence when parsing expressions (#190).
- Fix “math domain error” in mapping (#111, #151).


What's something that we all have but is what makes us unique?
soul emphasizes on individuality and unity.
We believe that people should acknowledge and respect each others' differences but not only that — we also believe that
people should come together more often in such divided times.
Embrace yourself, but also embrace others.
That is soul.


@* * Copyright 2023 HM Revenue & Customs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *@ @import github4s.domain.RefCommit @import uk.gov.hmrc.eeittadminfrontend.deployment.GithubContent @import uk.gov.hmrc.eeittadminfrontend.models.github.Authorization @import uk.gov.hmrc.eeittadminfrontend.utils.DateUtils @(authorization: Authorization, githubContent: GithubContent, commit: RefCommit )
Last modified by @commit.author.name on @DateUtils.formatAsInstant(commit.author.date) in commit @deployment_link_github_commit(authorization, githubContent.commitSha): @commit.message


Transport code
Overview
The transports
code in the transports/
directory is the code translating
the streaming protocols available into a unified API.
Its roles are to:
-
download the Manifest and parse it into an object that can be understood by the core of the rx-player
-
download segments, convert them into a decodable format if needed, and report important information about them (like the duration of a segment)
-
give networking metrics to allow the core to better adapt to poor networking conditions
As such, most network request needed by the player are directly performed by
the transports
code.
Note: the only HTTP request which might be done elsewhere would be the request
for a directfile
content. That request is not done explicely with a JavaScript
API but implicitely by the browser (inclusion of an src
attribute).
Implementation
This code is completely divided by streaming protocols used.
E.g. DASH
streaming is entirely defined in its own directory and the same
thing is true for Smooth Streaming
or MetaPlaylist
contents.
When playing a DASH
content only the DASH-related code will be called. When
switching to a Smooth Streaming
content, only the Smooth Streaming
code
will be used instead.
To allow this logic, any streaming protocol exposed in transports
exposes
the same interface and abstracts the difference to the rest of the code.
For the core of the rx-player, we do not have any difference between playing
any of the streaming protocols available.
This also means that the code relative to a specific streaming technology is
within the transports
directory.
This allows to greatly simplify code maintenance and evolutivity. For example,
managing a new streaming protocol would mainly just need us to add some code
there (you might also need to add parsers in the parsers
directory). Same
thing for adding a new feature to e.g. DASH
or Smooth
.
Each streaming protocol implementation present in the transports
code exports
a single transport
function.
The object returned by that function is often referenced as the transport pipelines
. It is documented here.
MetaPlaylist implementation
A MetaPlaylist is a specific case, as it wraps other streaming protocols.
More documentation about it can be found in the corresponding API documentation.
Architecture information on it can also be found here.


Draw.io
Home
About Us
Saved Images
How to play
Draw what you want to. The most important thing is to have fun.
Reset
Save


RELOAD Editor Help
Welcome to the Help Files for the RELOAD Editor. These files should provide all the information you need to use and exploit the RELOAD Editor. The files encompass background and technical information, a short tutorial, a description of the workspace and toolbars, explanation of advanced features and links to external resources.
RELOAD Manual
These help files include a copy of the RELOAD Manual:
| Click here to open the RELOAD Manual as a PDF document (To store elsewhere or open separately to the help pages: Right click the link and choose Save Target As ... or Save Link to Disk ...). NB The RELOAD manual and Help files share much of their content. Which you use will depend on your individual preference. |
RELOAD In Action
For a general introduction to Interoperability and to see how the RELOAD editor fits into the interoperability process, you may wish to read the article: A recipe for interoperability in practice from the CETIS web site. The article, and associated resources is available as a 2mb Content Package which can be downloaded from: http://www.reload.ac.uk/ex/ecsig8demo.zip. This package may also be useful as a sample content package as you learn to use RELOAD.
Comments
If you have any comments or suggestions for these help files, please email Colin Milligan at<EMAIL_ADDRESS>These help files refer to version 1.1.3a of the tools, built in November 2003. For the most up to date copy of the tools, please visit http://www.reload.ac.uk/


{% load static %}
Solution for which course to enroll in order to build a specific career!
Solution for where places are located on campus!
Solution for all services information at one place!


Album Art is a podcast currently under development by Isaac Halvorson. The podcast will debut sometime in 2017. Unil then, please follow the podcast on Twitter for updates.
Album Art is a podcast currently under development by Isaac Halvorson. The podcast will debut sometime in 2017. Unil then, please follow the podcast on Twitter for updates.


It is the template for aIt is the template for an ink level monitored as “gel jet color printer” in Ricoh.
A warning trigger is activated when the ink remaining falls below 5%
A mild failed trigger will be activated when the remaining amount increases in the + direction and the ink remaining amount reaches 0% after the cartridge is changed.
If you send an e-mail with this trigger in Zabbix action, you can change an consumable cartridges automatically.
From Zabbix 2.2 onwards GXe series, they works but I guess from Zabbix 2.0 it will work as well.
Also in the GX series I guess it will work unless SNMP is interrupted with a sleep mode. (it doesn’t work actally)
Update information:
I can monitor the free space of the wasted ink box from the SG series
whose value decreases from 100% (empty) to 0% (full).
Attention
Regarding to the waste ink box, we set the item but we do not register the trigger.
Toshihiro_SKK
There are no macros links in this template.
There are no template links in this template.
There are no discovery rules in this template.
| Name | Description | Type | Key and additional info |
|---|---|---|---|
| Full color |
-
 | SNMP agent |
fullcolor
Update: 600;3600/1-6,19:00-24:00;3600/1-6,00:00-08:00;3600/7,00:00-24:00
 |
| Save color |
-
 | SNMP agent |
saveprint
Update: 600;3600/1-6,19:00-24:00;3600/1-6,00:00-08:00;3600/7,00:00-24:00
 |
| Current volume of red ink |
-
 | SNMP agent |
prtMarkerSuppliesLevelmagen
Update: 180;3600/7,00:00-24:00
 |
| Current volume of yellow ink |
-
 | SNMP agent |
prtMarkerSuppliesLevelyellow
Update: 180;3600/7,00:00-24:00
 |
| Current capacity of blue ink |
-
 | SNMP agent |
prtMarkerSuppliesLevelcyan
Update: 180;3600/7,00:00-24:00
 |
| Waste ink box free space |
Place where the waste ink at the ink head cleaning is discarded. If this becomes full, the printer will not be able to print, so please change it by then.
 | SNMP agent |
prtMarkerSuppliesLeveldustBOX
Update: 1800;3600/1-5,00:00-08:00;3600/6-7,00:00-24:00;3600/1-5,19:00-24:00
 |
| all print |
-
 | SNMP agent |
allprint
Update: 600;3600/1-6,19:00-24:00;3600/1-6,00:00-08:00;3600/7,00:00-24:00
 |
| mono color |
-
 | SNMP agent |
monoprint
Update: 600;3600/1-6,19:00-24:00;3600/1-6,00:00-08:00;3600/7,00:00-24:00
 |
| Current capacity of black ink |
-
 | SNMP agent |
prtMarkerSuppliesLevelblack
Update: 180;3600/7,00:00-24:00
 |
There are no triggers in this template.
It is the template for aIt is the template for an ink level monitored as “gel jet color printer” in Ricoh.
A warning trigger is activated when the ink remaining falls below 5%
A mild failed trigger will be activated when the remaining amount increases in the + direction and the ink remaining amount reaches 0% after the cartridge is changed.
If you send an e-mail with this trigger in Zabbix action, you can change an consumable cartridges automatically.
From Zabbix 2.2 onwards GXe series, they works but I guess from Zabbix 2.0 it will work as well.
Also in the GX series I guess it will work unless SNMP is interrupted with a sleep mode. (it doesn’t work actally)
Update information:
I can monitor the free space of the wasted ink box from the SG series
whose value decreases from 100% (empty) to 0% (full).
Attention
Regarding to the waste ink box, we set the item but we do not register the trigger.
Toshihiro_SKK
There are no macros links in this template.
There are no template links in this template.
There are no discovery rules in this template.
| Name | Description | Type | Key and additional info |
|---|---|---|---|
| Current capacity of blue ink |
-
 | SNMP agent |
prtMarkerSuppliesLevelcyan
Update: 180;3600/7,00:00-24:00
 |
| Current volume of red ink |
-
 | SNMP agent |
prtMarkerSuppliesLevelmagen
Update: 180;3600/7,00:00-24:00
 |
| Full color |
-
 | SNMP agent |
fullcolor
Update: 600;3600/1-6,19:00-24:00;3600/1-6,00:00-08:00;3600/7,00:00-24:00
 |
| Current capacity of black ink |
-
 | SNMP agent |
prtMarkerSuppliesLevelblack
Update: 180;3600/7,00:00-24:00
 |
| Waste ink box free space |
Place where the waste ink at the ink head cleaning is discarded. If this becomes full, the printer will not be able to print, so please change it by then.
 | SNMP agent |
prtMarkerSuppliesLeveldustBOX
Update: 1800;3600/1-5,00:00-08:00;3600/6-7,00:00-24:00;3600/1-5,19:00-24:00
 |
| all print |
-
 | SNMP agent |
allprint
Update: 600;3600/1-6,19:00-24:00;3600/1-6,00:00-08:00;3600/7,00:00-24:00
 |
| Save color |
-
 | SNMP agent |
saveprint
Update: 600;3600/1-6,19:00-24:00;3600/1-6,00:00-08:00;3600/7,00:00-24:00
 |
| mono color |
-
 | SNMP agent |
monoprint
Update: 600;3600/1-6,19:00-24:00;3600/1-6,00:00-08:00;3600/7,00:00-24:00
 |
| Current volume of yellow ink |
-
 | SNMP agent |
prtMarkerSuppliesLevelyellow
Update: 180;3600/7,00:00-24:00
 |
There are no triggers in this template.
It is the template for aIt is the template for an ink level monitored as “gel jet color printer” in Ricoh.
A warning trigger is activated when the ink remaining falls below 5%
A mild failed trigger will be activated when the remaining amount increases in the + direction and the ink remaining amount reaches 0% after the cartridge is changed.
If you send an e-mail with this trigger in Zabbix action, you can change an consumable cartridges automatically.
From Zabbix 2.2 onwards GXe series, they works but I guess from Zabbix 2.0 it will work as well.
Also in the GX series I guess it will work unless SNMP is interrupted with a sleep mode. (it doesn’t work actally)
Update information:
I can monitor the free space of the wasted ink box from the SG series
whose value decreases from 100% (empty) to 0% (full).
Attention
Regarding to the waste ink box, we set the item but we do not register the trigger.
Toshihiro_SKK
There are no macros links in this template.
There are no template links in this template.
There are no discovery rules in this template.
| Name | Description | Type | Key and additional info |
|---|---|---|---|
| Current capacity of blue ink |
-
 | SNMP agent |
prtMarkerSuppliesLevelcyan
Update: 180;3600/7,00:00-24:00
 |
| Current volume of red ink |
-
 | SNMP agent |
prtMarkerSuppliesLevelmagen
Update: 180;3600/7,00:00-24:00
 |
| Full color |
-
 | SNMP agent |
fullcolor
Update: 600;3600/1-6,19:00-24:00;3600/1-6,00:00-08:00;3600/7,00:00-24:00
 |
| Current capacity of black ink |
-
 | SNMP agent |
prtMarkerSuppliesLevelblack
Update: 180;3600/7,00:00-24:00
 |
| Waste ink box free space |
Place where the waste ink at the ink head cleaning is discarded. If this becomes full, the printer will not be able to print, so please change it by then.
 | SNMP agent |
prtMarkerSuppliesLeveldustBOX
Update: 1800;3600/1-5,00:00-08:00;3600/6-7,00:00-24:00;3600/1-5,19:00-24:00
 |
| all print |
-
 | SNMP agent |
allprint
Update: 600;3600/1-6,19:00-24:00;3600/1-6,00:00-08:00;3600/7,00:00-24:00
 |
| Save color |
-
 | SNMP agent |
saveprint
Update: 600;3600/1-6,19:00-24:00;3600/1-6,00:00-08:00;3600/7,00:00-24:00
 |
| mono color |
-
 | SNMP agent |
monoprint
Update: 600;3600/1-6,19:00-24:00;3600/1-6,00:00-08:00;3600/7,00:00-24:00
 |
| Current volume of yellow ink |
-
 | SNMP agent |
prtMarkerSuppliesLevelyellow
Update: 180;3600/7,00:00-24:00
 |
There are no triggers in this template.


Installation
Option 1: Install from source in GitHub
FitHiChIP is hosted in https://github.com/ay-lab/FitHiChIP
Open a bash terminal, go to (or create) the directory to contain the FitHiChIP source code, and then type the following command in the terminal:
git clone https://github.com/ay-lab/FitHiChIP.git
Alternatively, user can download the ZIP from GitHub, and extract.
Prerequisite softwares / packages / libraries
FitHiChIP requires the following packages / libraries to be installed first:
Python3 (>= version 3.4)
Note: Since version 9.1, FitHiChIP is upgraded to support python3 instead of the deprecated python2
Following python libraries are to be installed:
OptionParser (from the library optparse; available in Python installation)
gzip (available in Python installation)
networkx (available in https://networkx.github.io/).
Note
Can be installed by the command pip install networkx
numpy (required for installing the package HiC-pro)
Note
Can be installed by the command pip install numpy
hicstraw (required for processing .hic files)
Note
Can be installed by the command pip install hicstraw
cooler (required for processing .cool or .mcool files)
Note
Can be installed by the command pip install cooler (or check the documentation: https://cooler.readthedocs.io/en/latest/quickstart.html#installation)
R (>= 3.4.3)
Note
User may follow https://www.datacamp.com/community/tutorials/installing-R-windows-mac-ubuntu for step by step installation of R.
In addition, user needs to install the following packages (needs to type the following command in an R terminal):
install.packages(c("optparse", "ggplot2", "data.table", "splines", "fdrtool", "parallel", "tools", "plyr", "dplyr"))
Further, user needs to install the following Bioconductor packages:
GenomicRanges https://bioconductor.org/packages/release/bioc/html/GenomicRanges.html
EdgeR https://bioconductor.org/packages/release/bioc/html/edgeR.html
Note
These two packages are required for differential analysis of FitHiChIP loops.
User should check their R version, and Bioconductor version, to install the appropriate versions of these packages.
bedtools (version >= 2.26.0) http://bedtools.readthedocs.io/en/latest/
samtools (version >= 1.6) http://www.htslib.org/
New in version 6.0:
Also install htslib (version >= 1.6) specifically for the utilities bgzip and tabix
Bowtie2 (available in http://bowtie-bio.sourceforge.net/bowtie2/index.shtml)
HiC-pro (https://github.com/nservant/HiC-Pro)
Note
Required version 2.11.4 or later (we recommend using the latest version of HiCPro).
Upon extracting the GitHub archieve of HiC-pro, user needs to edit the file config-install.txt and specify the installed paths of mentioned packages.
- Then, in a command line terminal, user should type the following commands:
make configure
make CONFIG_SYS=config-install.txt install
Note
Installation of HiC-pro is mandatory.
macs2 for peak calling https://github.com/taoliu/MACS
Note
To check if the above packages are installed, user can type the name of each package in the command line terminal
FitHiChIP is tested in linux environment, and requires bash for executing the main script.
Run FitHiChIP:
Use the following command:
bash ./FitHiChIP_HiCPro.sh -C /Your/Config/Files/Path
Option 2: Running FitHiChIP with Docker or Singularity
To not deal with any dependencies and be sure that program will execute correctly, we have prepared images for you to run your analysis in.
Choose a container system:
Most popular option is Docker (https://www.docker.com/).
But if you are running FitHiChIP on a cluster, you likely won't have docker installed. In that case, you can use the Singularity (https://sylabs.io/singularity/) option.
Install Docker:
If you choose to use Docker for executing FitHiChIP, you can check whether you have docker installed by typing this command in the terminal.
docker run hello-world
If you see the hello text you are good to continue.
If you get an error that says it couldn't connect to the Docker daemon, make sure you have the docker daemon running.
If you get an error that says command isn't recognised, install docker by following the instructions located here: https://docs.docker.com/install/
Use Singularity
Singularity is used in environments where the users aren't trusted with the system priviliges required by Docker such as computing clusters. You can check if you have singularity installed with this command:
singularity version
If you don't have it installed in your computing environment, contact the system managers.
Get the FitHiChIP scripts from Github:
Either download the contents of FitHiChIP Github repository or clone the repository using these commands:
git clone https://github.com/ay-lab/FitHiChIP/
cd ./FitHiChIP
Run FitHiChIP:
Use one of these commands depending on your choice of using Docker or Singularity:
For Docker, use the following command:
bash ./FitHiChIP_Docker.sh -C /Your/Config/Files/Path
For Singularity, use the following command:
bash ./FitHiChIP_Singularity.sh -C /Your/Config/Files/Path
Note
Your first run will likely take longer than average as you will download the image to run FitHiChIP in.
Output:
If there are no errors, you will see a success message and FitHiChIP results will be located in the output directory you specified in the configuration file.


Patriots’ Offense Receives Huge Boost Ahead Of Cowboys Game
by Chris RosvoglouEven though the New England Patriots own a 9-1 record, the offense has really struggled over the past few weeks. Fortunately for the defending champions, help is on the way.
One of the main concerns for the Patriots is their offensive line, which hasn’t been very effective through the first two months of the season.
Injuries have played a major factor in why New England is having issues in the trenches. However, the offensive line will receive a much-needed boost this weekend against the Dallas Cowboys.
According to ESPN insider Field Yates, the Patriots have officially activated Isaiah Wynn to the 53-man roster.
Wynn is set to play this Sunday against Dallas. He missed the past eight games due to a foot injury.
The Patriots believe Wynn’s return will help protect Tom Brady’s blindside.
New England selected Wynn in the first round of the 2018 NFL Draft. This is the second-straight season that Wynn missed time because of injuries – he missed all of his rookie campaign due to a torn Achilles.
Marshall Newhouse has served as the starting left tackle for the Patriots in Wynn’s absence. He’ll most likely be the backup offensive tackle this Sunday.
Kickoff for this weekend’s Patriots-Cowboys game is at 4:25 p.m. ET from Gillette Stadium.


{{ .Params.lead | safeHTML }}
Discover your Reachy Kit and everything you need to know to set it up: hardware presentation, installation and conection.
Easy control of a Reachy robot in Python: read sensor information (eg. camera, joint position, force) and send actuator commands.
Control the robot remotely using Reachy's VR teleoperation application.
Use Reachy packages to control it directly using ROS2 Foxy: URDF, kinematics, joint_state, RViz, etc.
Can't solve your problem? Ask for help!