Top Mainframe Interview Questions for 2023 - IQCode

Mainframe Interview Questions for Freshers

// The mainframe ecosystem is made up of computers that come in different combinations of processors and memory. They function as workstations and terminals for processing jobs and performing necessary operations. The first mainframe computer was developed in the 1930s and was ready to use in 1943. This computer weighed approximately five tons, filled an entire room, and cost approximately $200K.

// IBM started developing smaller, Linux-based systems in 1998. Nowadays, mainframe computers are known for being powerful and agile, and they are no larger than refrigerators. They are used primarily for data processing and analysis, capable of processing trillions of instructions per second. Due to their powerful processing capabilities, the need for mainframe developers is still in demand, even though it has gained the status of a legacy technology. 

// In this section, we will cover the most commonly asked mainframe interview questions, including concepts on COBOL and JCL, which will help developers ace mainframe interviews.

// We also offer a free mock interview, providing instant feedback and recommendations.

// Mainframe Interview Questions for Freshers

1. What are mainframe computers?

Mainframe computers are a type of large-scale computer that are capable of handling a huge amount of data, processing trillions of instructions per second. They are often used for data processing and analysis and are known for their powerful processing capabilities. Despite being considered legacy technology, the need for mainframe developers remains high. The first mainframe computer was developed in the 1930s and was ready for use in 1943. They are made up of computers with various combinations of processors and memory, functioning as workstations and terminals for processing jobs and carrying out necessary operations. IBM started developing smaller, Linux-based systems in 1998, resulting in mainframe computers being no larger than refrigerators nowadays.

Understanding Self-Referencing Constraints

Self-referencing constraints are constraints in a database table that reference the same table. In other words, the constraint applies to the same table that it is defined in. This type of constraint is often used to establish relationships between data within the same table, such as parent-child relationships. It can help maintain data integrity and consistency by ensuring that a record cannot be deleted if it has related records that depend on it. Self-referencing constraints are commonly used in hierarchical data structures.

Differences between SEARCH and SEARCH ALL




are COBOL verbs used for searching an item in an array. However, they have some differences that developers should keep in mind:


    checks the array elements one by one, and after finding the first matching item, it returns immediately.


    does a binary search on a sorted array and thus can find all matching items in a single search, saving time and resources.


    is suitable for unsorted arrays, while


    is suitable for sorted arrays.

It is important to note that


has a constraint that the array being searched must be sorted in ascending order, otherwise, incorrect results may be found.

Definition of Copybook in COBOL

In COBOL, a copybook is a mechanism to include common code, such as file descriptions and data structure definitions, in multiple programs. A copybook is a separate file that contains these shared definitions and is then copied into each program that needs them using the COPY statement. This helps to reduce duplication of code and ensures consistency across programs. Copybooks are declared with the COPY LIBRARY statement, which specifies the directory where the copybook resides.

Understanding Index Cardinality in DB2

Index cardinality in DB2 refers to the uniqueness of values in an index. It represents the number of distinct values in the indexed column or columns. In simpler terms, index cardinality gives an idea of how many unique values are present in an index.

For example, consider an index on a column that has 1000 rows, but only 500 unique values. In this case, the index cardinality would be 500.

The higher the index cardinality, the greater the chances of selectivity, which results in better query performance. It is important to keep index cardinality in mind while designing indexes in DB2. Poor index cardinality can result in decreased query performance, as the database engine would need to scan more rows to retrieve the desired data.

Therefore, it is recommended to analyze the index cardinality before creating new indexes in DB2. This can be achieved by running the 'runstats' command on the indexed table, which provides statistics on the distribution of values in indexed columns, including the index cardinality.

Importance of DBCTL

DBCTL stands for Database Control. It is a subsystem that manages the processing of database requests from different application programs running concurrently. The importance of DBCTL can be summarized as follows:

1. Effective Management of Databases: DBCTL performs the functions of database management more efficiently than other methods, ensuring that the data is consistent and accurate.

2. Efficient Use of System Resources: DBCTL optimizes the use of system resources since it coordinates the activities of different application programs requesting access to the database.

3. Improved Performance: DBCTL provides support for components that enhance the performance of database processing such as buffer pools, buffer pool services, cache services, and prefetch services.

4. Security: DBCTL provides a secure environment for database processing, ensuring that the data is accessed only by authorized users.

5. Reduced Complexity: DBCTL reduces the complexity of database management as it provides a centralized management system, which makes it easier to manage a large number of databases.

In summary, DBCTL is an essential component that enables effective database management, efficient use of system resources, improved performance, security, and reduced complexity.

Definition of Update Cursor

An update cursor is a type of cursor in computer programming that is used to modify or update records in a database. It allows the programmer to iterate through a set of records, make changes to specific fields or values, and then update those changes back into the database. Update cursors are commonly used in database management systems (DBMS) to implement forms-based interfaces, transaction processing, and other applications that require the ability to modify database records. In general, update cursors are an efficient and effective tool for managing a large amount of data in a database.

Usage of 88 Levels in COBOL

In COBOL, 88 levels are used as condition names to assign a boolean value (true or false) to a data item based on certain conditions. These conditions are defined using the level number 88 followed by a name and a value.

For example,

   05 EMP-NAME         PIC X(20).
   05 EMP-AGE          PIC 99.
   05 EMP-SALARY       PIC 9(6).
   88 SALARY-HIGH      VALUE 100000.

Here, SALARY-HIGH is the condition name assigned to the 88 level. It will be true if the value of EMP-SALARY is greater than or equal to 100000, else false.

These condition names can then be used in conditional statements such as IF, EVALUATE, and PERFORM to make the code more readable and easier to understand.

Types of JCL Statements for Running a Job

In JCL (Job Control Language), there are several types of statements used for running a job:

  1. Job statement
  2. Executive control statements
  3. DD (Data Definition) statements
  4. Procedure statements
  5. Conditional processing statements
  6. Generation data group (GDG) control statements
  7. System initialization statements
  8. Authorization control statements

Each statement has a unique purpose and is used to control or define different aspects of a job.

Explanation of Comp Sync

Comp Sync, short for "composition synchronization," is a feature in video editing software that helps to keep audio and video clips in sync during the editing process. This feature automatically adjusts the timing of audio and video clips so that they match up perfectly, even if the clips were recorded separately. Comp Sync is especially useful when creating music videos, syncing up sound effects, or editing footage that was filmed from multiple camera angles.

Methods for Achieving Static and Dynamic Linking

Static and dynamic linking are two methods of connecting programs with their required libraries. Static linking is the process of combining all necessary libraries into a single executable file before running the program, while dynamic linking performs the linking during runtime by loading libraries as needed.

In C and C++, static linking is achieved by passing the '-static' flag to the linker, while dynamic linking is the default behavior.

Other programming languages like Java and Python use their own methods for linking libraries, such as compiling to bytecode or using virtual environments.

Differences between Global and External Variables

Global and external variables are two types of variables used in programming languages, including C. Here are the main differences between them:

  • Global variables: Defined outside of a function, global variables can be accessed by any function in the program. They have a global scope, meaning they can be accessed from any part of the code.
  • External variables: Defined outside of a function, external variables can be accessed across different source files in a program. They are declared using the "extern" keyword and provide a way to share data between different parts of a program.

While both types of variables have their uses, it's important to use them carefully and avoid overuse to prevent confusion and bugs in your code.

Types of Conditional Statements in COBOL

In COBOL, there are three different types of conditional statements: IF, EVALUATE, and INSPECT.

The IF statement allows you to test a single condition. It follows the format:

IF condition
    statements to be executed if condition is true
    statements to be executed if condition is false

The EVALUATE statement tests multiple conditions and chooses one set of statements to execute based on which condition is true. It follows the format:

EVALUATE identifier
    WHEN value-1
        statements to be executed if value-1 is true
    WHEN value-2
        statements to be executed if value-2 is true
        statements to be executed if none of the previous conditions are true

The INSPECT statement is used to search for a specific character or string within a variable. It follows the format:

INSPECT identifier
    TALLYING count 
        FOR character/string

These conditional statements are essential in making decisions and directing program flow in COBOL programs.

Mainframe Interview Questions for Experienced: Difference between Index and Subscript

In computer programming, an index and a subscript are both used to access elements in an array. However, there is a subtle difference between the two.

An index is typically an integer value that is used to indicate the position of an element in an array. It is commonly used in programming languages like Java and C#.

On the other hand, a subscript is usually a value used to access an element in an array in programming languages like COBOL and FORTRAN. A subscript can be an integer or a string value.

In summary, while both an index and a subscript are used to access elements in an array, an index is typically an integer value, and a subscript can be a value of any type that can be used to identify an element in an array.

Types of Locks and Their Functions

There are numerous types of locks available to use, some of which are:

- Deadbolts: They are known for providing high-level security as they can't be moved until the cylinder is rotated.

- Knob Locks: They are commonly used in interior doors and are easy to install.

- Lever Handle Locks: These locks are easier to operate as compared to knob locks, making them a great choice for people with physical disabilities.

- Cam Locks: They are often used in filing cabinets, mailboxes, and furniture.

- Padlocks: They come in various sizes and shapes and can be easily carried around.

- Mortise Locks: They come in two parts, a lock body, and a mortise lock.

- Euro Profile Cylinders: They are widely used in Europe and Asia and are gaining popularity in the US as well.

- Smart Locks: They can be operated via Bluetooth or Wi-Fi and are the future of modern security systems.

Each of these lock types has its unique function that caters to specific security needs.

Importance of DCB Parameter in DD Statements

The DCB (Data Control Block) parameter in DD (Data Definition) statements is crucial for specifying the attributes of dataset or file. The DCB parameter determines the organization, block size, record format, and other properties of the data, which enables the operating system to handle the data correctly. It is important to provide accurate DCB values in the DD statements to ensure the smooth functioning of the program and prevent errors in data processing.

Ensuring Program Execution Above 16 Meg Line

To ensure the program executes above the 16 meg line, several steps can be taken:

1. Optimize the program code: Review the program and look for any inefficiencies and optimize the code. Remove any redundant code and streamline operations. This will reduce the memory requirements for the program and allow it to execute on the higher memory range.

2. Increase the memory available to the program: Allocate more memory to the program to ensure it can run above the 16 meg line. This can be achieved by purchasing additional memory for the system or by adjusting the virtual memory settings.

3. Use a memory manager: Implement a memory manager that can manage memory efficiently and ensure the program runs within the available memory limits. This will help the program to execute above the 16 meg line without hitting any memory limits.


// Memory management function 
void memoryManager(){
  // Implement memory allocation and deallocation logic here

// Main function
int main(){
  int memorySize = 20; // Define the amount of memory required by the program
  if(memorySize > 16){
    memoryManager(); // Call memory management function
  // Rest of the program logic goes here
  return 0;

P: By following the above steps, you can ensure that your program executes above the 16 meg line. Optimizing the code, increasing memory availability, and using a memory manager can help your program run smoothly and without any memory-related issues.

Consequences of Specifying Both STEPLIB and JOBLIB Statements

When both STEPLIB and JOBLIB statements are specified in a job control language (JCL) statement, then the system first searches for the dataset libraries specified in the STEPLIB statement during the processing of individual job steps. If the system is unable to find a required program or data set in the specified STEPLIB libraries, then it searches for the same in the JOBLIB libraries. Therefore, if both STEPLIB and JOBLIB statements are specified and a program or a data set is in both libraries, the system uses the copy of the program or data set that is in the STEPLIB libraries.

Handling Deadlocks in a DB2 Program

When working with a DB2 program, it's possible to encounter a deadlock situation, which results in a -911 error. To handle this situation, you can follow these steps:

1. Identify the cause of the deadlock by looking at the error message and the DB2 logs. 2. Modify the application program to avoid the deadlock. This may involve changing the order in which resources are accessed or reducing the amount of time that locks are held. 3. Retry the failed transaction after a delay. You can include a delay in your program to give other transactions time to complete and release the necessary resources. 4. Implement DB2 features such as locking timeouts and deadlock detection to prevent future deadlocks.

By following these steps, you can effectively handle deadlock situations and ensure the smooth operation of your DB2 program.

Repairing SOC-7 Error

The SOC-7 error, also known as a data exception error, occurs when there is an attempt to perform an arithmetic operation on non-numeric data. To repair the SOC-7 error, you can follow these steps:

1. Identify the source of the error: You need to figure out which instruction or variable is causing the error. You can use the job log for this purpose.

2. Determine the cause of the error: Once you've identified the instruction or variable that's causing the error, try to determine why it's causing the error. Check for any invalid characters in the data or any missing data that's required for the operation.

3. Fix the error: Depending on the cause of the error, you may need to modify the code or data to fix the error. For example, you can use the TRIM function to remove any leading or trailing spaces from the data.

4. Test the fix: Once you've made the necessary changes, test the code to ensure that the error no longer occurs.

By following these steps, you should be able to repair the SOC-7 error and ensure that your program runs smoothly.

Various Forms of Evaluate Statements

The EVALUATE statement can take different forms in programming languages. Here are some common forms:

1. Simple EVALUATE statement - used to evaluate a single expression or variable.

2. EVALUATE statement with WHEN clauses - used to evaluate multiple conditions.

3. EVALUATE statement with WHEN OTHER - used to provide a default action if none of the conditions are met.

4. EVALUATE statement with GOTO - used to jump to specific labels based on the evaluated value.

It is important to understand the various forms of EVALUATE statement to effectively use it in programming.

Steps to create a COBOL program:

1. Start with identifying the requirements of the program. 2. Define the data structure and variables required to implement the logic. 3. Write the necessary code using COBOL syntax. 4. Test the program thoroughly to ensure it meets the requirements. 5. Debug and correct any errors that arise during testing. 6. Document the program code and design to make it more accessible for future use. 7. Compile the program to generate an executable file. 8. Execute the program and verify that it produces the desired output.

Why is it important to code commits in batch programs?

Batch programming involves executing a sequence of commands or programs that are stored in a file. When these programs run, errors can occur that cause the entire batch to fail. It's essential, therefore, to use commits in batch programs to ensure that each step can be checked and verified before moving on to the next one.

Commits provide a way to break up long batches into smaller, more manageable chunks. Each commit is a checkpoint that captures the state of the batch at a specific point in time. If an error occurs, the batch can be rolled back to the last commit, and the steps leading up to it can be checked for errors.

Also, committing code makes it easier to collaborate with other developers. Each commit allows other team members to track changes made to the code and helps ensure that everyone is working with the same version. Additionally, commits provide an audit trail that can be used to improve the quality of the code and make it easier to debug if necessary.

In summary, coding commits in batch programs is essential for ensuring the successful execution of long and complex batches, enabling better collaboration, and providing an audit trail for quality assurance.

Understanding Paging in Memory

Paging is a memory management technique that allows the operating system to store and retrieve data from the secondary storage device or disk, which from the perspective of the CPU appears to be a contiguous block of memory. It breaks down the memory into equal fixed-size blocks or pages, typically 4KB or 8KB in size, and stores them in the physical memory or RAM.

To access the data stored in a particular page, the operating system uses a page table data structure, which contains the mapping of logical addresses of each process to its corresponding physical addresses, along with necessary control bits such as the present/absent bit, dirty bit, access bit, etc. Whenever a process needs a particular page of memory, the operating system looks up the page table to find its physical address and then retrieves or stores the data to or from the disk.

When a process tries to access a page of memory that is not present in the physical memory, a page fault interrupt occurs, and the operating system swaps in the required page from the disk. Similarly, when the physical memory becomes full, and no free page is available, the operating system uses a page replacement algorithm to choose a victim page to swap out to the disk, making room for the new page.

In summary, paging allows efficient use of memory resources and provides a way to use more memory than physically available by using the disk as a virtual memory extension.

How to determine if a module is called statically or dynamically?

To check if a module in Python is called statically or dynamically, you can use the `__name__` attribute of the module.

If the value of `__name__` is equal to the name of the module file when it is imported, then it was called statically. On the other hand, if the value of `__name__` is not equal to the name of the module file when it is imported, then it was called dynamically.


# Example module named ""

def example_function():
    print("This is an example function.")

if __name__ == "__main__":
    print("Module was called statically.")
    print("Module was called dynamically.")

In the above example, if we run the `` file directly, we will see the message "Module was called statically." printed to the console. However, if we import `example_module` into another file and call the function, we will see the message "Module was called dynamically." printed instead.

Differences between External and Internal Sort

In computing, internal sorting and external sorting are two contrasting algorithms for sorting data. The difference between the two algorithms lies in the way they handle the amount of data they sort.

Internal Sort: Internal sorting is a sorting algorithm that can handle all the data to be sorted in the primary memory (RAM) of the computer. It sorts the data in place, without the need for additional memory. Examples of internal sort algorithms include QuickSort, MergeSort, and InsertionSort.


void quickSort(int arr[], int low, int high) {
    if (low < high) {
        int pi = partition(arr, low, high);
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);

External Sort: External sorting is a sorting algorithm used when the data to be sorted is too large to fit into the primary memory (RAM) of the computer. It involves dividing the data into smaller chunks that can be sorted internally in memory and then merged back into a single file. It requires additional memory space and is usually slower than internal sorting algorithms.


void mergeSort(char* input_file, char* output_file, int chunk_size) {
    // divide data into chunks
    while (fgets(line, MAX_LINE_SIZE, input)) {
        buffer[current_buffer_size++] = line;
        if (current_buffer_size == chunk_size) {
            sort(buffer, current_buffer_size);
            write_buffer_to_disk(buffer, current_buffer_size, tmp_files_queue);
            current_buffer_size = 0;
    // merge sorted chunks
    merge_sorted_chunks(tmp_files_queue, output_file);

Stages in Processing a Job

In computing, a job typically goes through several stages in order to be processed. The different stages include:

  1. Submission: This is the stage where a user submits their job to the system.
  2. Hold: At this stage, a job may be put on hold either by the user or the system administrator.
  3. Scheduling: This is where the system schedules jobs to be processed based on priority.
  4. Processing: At this stage, the job is finally processed by the system.
  5. Completion: When the job is finished, it moves to the completion stage and outputs the result.


// This code represents the different stages in processing a job

// Submission stage
function submitJob(job) {
  // code to submit job here

// Hold stage
function putJobOnHold(job) {
  // code to put job on hold here

// Scheduling stage
function scheduleJob(job) {
  // code to schedule job here

// Processing stage
function processJob(job) {
  // code to process job here

// Completion stage
function completeJob(job) {
  // code to complete job here

How to pass incentives from JCL to COBOL

In COBOL, incentives can be passed from JCL using the special register called "SYSIN". This can be accomplished by including the following statement in your COBOL program:


This statement assigns the standard input stream (SYSIN) to the file control block (FCB) for the input file named SYSIN. This allows you to use the "ACCEPT" statement in your COBOL program to read in the incentives passed from JCL.

For example:



This code will read in the value of the incentive from the JCL and store it in the "WS-INCENTIVE" variable. From there, you can use it as needed in your COBOL program.

Avoiding Deadlocks when Reading Data on a Mainframe

Deadlocks can occur when multiple transactions are trying to access the same data simultaneously. To avoid deadlocks when reading data on a mainframe, follow these guidelines:

1. Use the correct isolation level when reading data to prevent other transactions from locking the same records. 2. Avoid long running transactions, as they increase the likelihood of deadlocks. 3. Use proper indexing to reduce contention and improve performance. 4. Ensure that all transactions release locks as soon as they are no longer needed. 5. Monitor and analyze performance to identify and address any potential issues.

By following these guidelines, you can help prevent deadlocks and ensure that your mainframe performs optimally.

Mainframe scenario-based interview question:

// Declare cursor to retrieve the first 100 rows from the DB2 table 
SELECT column_name 
FROM table_name 

// Update the column value of the retrieved rows 
UPDATE table_name 
SET column_name = new_value 
WHERE CURRENT OF cursor_name

// Commit the changes 

In this scenario, we can use a cursor to retrieve the first 100 records from the DB2 table and then update the column value of these rows. The cursor is declared with the FETCH FIRST 100 ROWS ONLY clause to limit the number of rows retrieved. Once we have retrieved the rows, we can update the column value using a simple SQL update statement. Before committing the changes, make sure to close the cursor.

Defining the sort file in JCL for running a COBOL program

To define the sort file in JCL for executing a COBOL program, you can use the following syntax:


Here, SORTFILE is the name of the file you want to define, DSN is the dataset name of the file, and DISP=SHR indicates that the file will be shared between multiple job steps.

For example, if you want to define a sort file named SORT01.DAT, you can use the following JCL statement:


This statement will define the SORT01.DAT file and make it available for use in the COBOL program.

Is it possible to redefine a field with X(200) from X(100)? If yes, how?

Yes, it is possible to redefine a field with X(200) from X(100) by using the REDEFINES clause. Here's an example:

01  FIELD-X.
        05 FILLER    PIC X(100).

        05 FILLER    PIC X(200).

In the above example, FIELD-Y is a redefinition of FIELD-X. It contains the same amount of total storage, but the internal specification is different. FIELD-Y holds twice as much data as FIELD-X as it is now defined as X(200).

How to Copy Data From One Dataset to Another Using SORT Card?

To copy data from one dataset to another using a SORT card, we can follow these steps:

  1. Define two datasets in your JCL (Job Control Language) as input and output.
  2. Allocate both datasets in your JCL.
  3. Use the SORT card with the COPY parameter.
  4. Specify the input dataset name after the SORT statement.
  5. Specify the output dataset name after the OUT statement.
  6. Run the JCL.

Here's an example of a SORT card to copy data from one dataset to another:

//            SPACE=(CYL,(5,5),RLSE),
//            UNIT=SYSDA
//SYSIN   DD  *

In the example above, "Input.Data.Set" is the name of the input dataset, and "Output.Data.Set" is the name of the output dataset. The SORT card with the COPY parameter is used to copy data from the input dataset to the output dataset. The DISP parameter is used to specify the disposition of the output dataset. The SPACE parameter specifies the amount of space to be allocated for the output dataset.

Make sure to test your SORT card thoroughly before using it in production.

Notifying Other Users of Job Completion in an Application or System

In an application or system, there are different ways to inform users of job completion. This could include:

1. Pop-up notifications: These are small notifications that appear on the screen to inform users that a job has been completed successfully. This is a quick and easy way to inform users, especially if they are working on other tasks in the application.

2. Email notifications: This could be an automated email that is sent to users to inform them of job completion. This is helpful for users who are not currently logged into the application or system.

3. In-app notifications: This is similar to pop-up notifications, but appears within the application itself rather than as a separate window.

4. Push notifications: This is a notification that is sent directly to the user's mobile device or desktop, even if they are not currently using the application.

The method used will depend on the specific application or system and the preferences of the users. It is important to ensure that the method used is effective and non-intrusive to the user's workflow.

Achieving Auto Restart in Case of Job Abends

To achieve auto restart in case of job abends, we can make use of the following methods:

1. Restarting the job using checkpoint data: We can enable the check-point restart feature for the failed job to automatically restart the job at the point where it failed using the checkpoint data. This method requires that checkpoint data is saved periodically during the job run.

2. Restarting the job from the beginning: If the job has failed due to an unrecoverable error, we can set up the job to start again from the beginning once it is detected that the job has abended. This method requires that the job parameters are properly configured to restart the job from the beginning.

3. Using automation tools: Automation tools such as IBM Tivoli Workload Scheduler can be used to monitor job execution and detect job abends. These tools can then automatically restart the job using the appropriate method based on the cause of the abend.

Regardless of the method used, it is important to have a proper monitoring and notification system in place to alert the appropriate personnel in case of job abends and ensure that the issue is resolved as quickly as possible.

Checking for an empty file in JCL

To check if a file is empty in JCL, we can make use of the COND parameter and the utility program IEBGENER.


//              DSNAME=<filename>    

Replace `` with the name of the file you want to check for emptiness.


We use IEBGENER with DUMMY input to check if the file is empty or not. If the file is not empty, then the PGM will create a new file with the same content. The COND parameter is used to check the status of the utility program. If the status is not zero, then it means the file is empty.

Technical Interview Guides

Here are guides for technical interviews, categorized from introductory to advanced levels.

View All

Best MCQ

As part of their written examination, numerous tech companies necessitate candidates to complete multiple-choice questions (MCQs) assessing their technical aptitude.

View MCQ's
Made with love
This website uses cookies to make IQCode work for you. By using this site, you agree to our cookie policy

Welcome Back!

Sign up to unlock all of IQCode features:
  • Test your skills and track progress
  • Engage in comprehensive interactive courses
  • Commit to daily skill-enhancing challenges
  • Solve practical, real-world issues
  • Share your insights and learnings
Create an account
Sign in
Recover lost password
Or log in with

Create a Free Account

Sign up to unlock all of IQCode features:
  • Test your skills and track progress
  • Engage in comprehensive interactive courses
  • Commit to daily skill-enhancing challenges
  • Solve practical, real-world issues
  • Share your insights and learnings
Create an account
Sign up
Or sign up with
By signing up, you agree to the Terms and Conditions and Privacy Policy. You also agree to receive product-related marketing emails from IQCode, which you can unsubscribe from at any time.