text:
// Copyright (c) Microsoft. All rights reserved.

#include "pch.h"
#include "Scenario5_RoundingAndPadding.xaml.h"

using namespace SDKTemplate;

using namespace Platform;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Navigation;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Globalization::NumberFormatting;

Scenario5_RoundingAndPadding::Scenario5_RoundingAndPadding()
{
    InitializeComponent();
}

/// <summary>
/// Used to display the rounding algorithm in a string format.  Used by the different scenarios when
/// displaying results for the scenario
/// </summary>
/// <param name="roundingAlgorithm"></param>
String^ Scenario5_RoundingAndPadding::DisplayRoundingAlgorithmAsString(RoundingAlgorithm roundingAlgorithm)
{
    String^ roundingAsString = "";

    // Convert the enumeration value into a string representation
    switch (roundingAlgorithm) {
        case RoundingAlgorithm::None:
            roundingAsString = "no";
            break;
        case RoundingAlgorithm::RoundAwayFromZero:
            roundingAsString = "away from zero";
            break;
        case RoundingAlgorithm::RoundDown:
            roundingAsString = "down";
            break;
        case RoundingAlgorithm::RoundHalfAwayFromZero:
            roundingAsString = "half away from zero";
            break;
        case RoundingAlgorithm::RoundHalfDown:
            roundingAsString = "half down";
            break;
        case RoundingAlgorithm::RoundHalfToEven:
            roundingAsString = "half to even";
            break;
        case RoundingAlgorithm::RoundHalfToOdd:
            roundingAsString = "half to odd";
            break;
        case RoundingAlgorithm::RoundHalfTowardsZero:
            roundingAsString = "half towards zero";
            break;
        case RoundingAlgorithm::RoundHalfUp:
            roundingAsString = "half up";
            break;
        case RoundingAlgorithm::RoundTowardsZero:
            roundingAsString = "toward zero";
            break;
        case RoundingAlgorithm::RoundUp:
            roundingAsString = "up";
            break;
        default:
            roundingAsString = "unknown";
            break;
    }

    return roundingAsString;
}

/// <summary>
/// Executes the padding scenarios.
/// </summary>
/// <param name="formatter">
/// The formatter parameter can be either a DecimalFormatter, PercentFormatter
/// PerMilleFormatter or CurrencyFormatter
/// </param>
String^ Scenario5_RoundingAndPadding::DoPaddingScenarios(INumberFormatter^ formatter)
{
    // Display the properties of the scenario
    String^ results = "Padding with ";
    results = results + ((ISignificantDigitsOption^)formatter)->SignificantDigits + " significant digits, ";
    results = results + ((INumberFormatterOptions^)formatter)->IntegerDigits + " integer digits, ";
    results = results + ((INumberFormatterOptions^)formatter)->FractionDigits + " fractional digits\n\n";

    // Iterate through the numbers to pad, format them and add them to the results
    double numbersToPad[] = { 0.12, 1.2, 10.2, 102 };
    for (int index = 0; index < sizeof(numbersToPad)/sizeof(double); index++)
    {
        double numberToPad = numbersToPad[index];
        String^ paddedNumber = formatter->Format(numberToPad);
        results = results + "Value: " + numberToPad + " Padded: " + paddedNumber + "\n";
    }

    // Add a carriage return at the end of the scenario for readability
    return results + "\n";
}

/// <summary>
/// Demonstrates how to perform padding and rounding by using the DecimalFormatter class (can be any of the
/// formatter classes in the Windows.Globalization.Numberformatting namespace) and the IncrementNumberRounder
/// to do so.  The SignificantDigitsNumberRounder can also be used instead of the latter.
/// </summary>
/// <param name="roundingAlgorithm"></param>
/// <param name="significantDigits"></param>
/// <param name="integerDigits"></param>
/// <param name="fractionalDigits"></param>
String^ Scenario5_RoundingAndPadding::DoPaddingAndRoundingScenarios(RoundingAlgorithm roundingAlgorithm, unsigned int significantDigits, int integerDigits, int fractionalDigits)
{
    // Create the rounder and set the rounding algorithm provided as a parameter
    IncrementNumberRounder^ rounder = ref new Windows::Globalization::NumberFormatting::IncrementNumberRounder();
    rounder->RoundingAlgorithm = roundingAlgorithm;

    // Create the formatter, set the padding properties provided as parameters and associate the rounder
    // we have just created
    DecimalFormatter^ formatter = ref new Windows::Globalization::NumberFormatting::DecimalFormatter();
    formatter->SignificantDigits = significantDigits;
    formatter->IntegerDigits = integerDigits;
    formatter->FractionDigits = fractionalDigits;
    formatter->NumberRounder = rounder;

    // Stores the results
    String^ results = "";

    // Iterate through the increments we have defined in the scenario
    double incrementsToRound[] = { 0.001, 0.01, 0.1, 1.0 };
    for (int incrementIndex=0; incrementIndex < sizeof(incrementsToRound)/sizeof(double); incrementIndex++)
    {
        // Set the increment to round to
        rounder->Increment = incrementsToRound[incrementIndex];

        // Display the properties of the scenario
        results = results + "Padding and rounding with ";
        results = results + formatter->SignificantDigits + " significant digits, ";
        results = results + formatter->IntegerDigits + " integer digits, ";
        results = results + formatter->FractionDigits + " fractional digits, ";
        results = results + rounder->Increment + " increment and ";
        results = results + DisplayRoundingAlgorithmAsString(rounder->RoundingAlgorithm) + " rounding algorithm\n\n";

        // Iterate through the numbers to round and pad, format them and add them to the results
        double numbersToFormat[] = { 0.1458, 1.458, 14.58, 145.8 };
        for (int numberIndex = 0; numberIndex < sizeof(numbersToFormat)/sizeof(double); numberIndex++)
        {
            double numberToFormat = numbersToFormat[numberIndex];
            String^ formattedNumber = formatter->Format(numberToFormat);
            results = results + "Value: " + numberToFormat + " Formatted: " + formattedNumber + "\n";
        }

        // Add a carriage return at the end of the scenario for readability
        results = results + "\n";
    }

    return results;
}

/// <summary>
/// This scenario illustrates how to provide a rounding algorithm to a CurrencyFormatter class by means of the
/// applyRoundingForCurrency method.  This will associate an IncrementNumberRounder using the same increment as the
/// fractionDigits appropriate for the currency and language.  You can always choose to provide a different rounding
/// algorithm by setting the numberRounder property, as depicted in the doPaddingAndRoundingScenarios function.
/// The mechanism provided here is better suited for currencies.
/// </summary>
/// <param name="currencyCode"></param>
/// <param name="roundingAlgorithm"></param>
String^ Scenario5_RoundingAndPadding::DoCurrencyRoundingScenarios(String^ currencyCode, RoundingAlgorithm roundingAlgorithm)
{
    // Create the currency formatter and set the rounding algorithm provided as a parameter
    CurrencyFormatter^ currencyFormatter = ref new Windows::Globalization::NumberFormatting::CurrencyFormatter(currencyCode);
    currencyFormatter->ApplyRoundingForCurrency(roundingAlgorithm);

    // Display the properties of the scenario
    String^ results = "Currency formatting for ";
    results = results + currencyFormatter->Currency + " currency and using the ";
    results = results + DisplayRoundingAlgorithmAsString(roundingAlgorithm) + " rounding algorithm\n\n";

    // Iterate through the numbers to round and add them to the results
    double numbersToFormat[] = { 14.55, 3.345, 16.2, 175.8 };
    for (int numberIndex = 0; numberIndex < sizeof(numbersToFormat)/sizeof(double); numberIndex++)
    {
        double numberToFormat = numbersToFormat[numberIndex];
        String^ formattedNumber = currencyFormatter->Format(numberToFormat);
        results = results + "Value: " + numberToFormat + " Formatted: " + formattedNumber + "\n";
    }

    // Add a carriage return at the end of the scenario for readability
    return results + "\n";
}

/// <summary>
/// Shows how to do number rounding using the IncrementNumberRounding class.
///</summary>
///<param name="roundingAlgorithm"></param>
String^ Scenario5_RoundingAndPadding::DoIncrementRoundingScenarios(RoundingAlgorithm roundingAlgorithm)
{
    // Create the rounder and set the rounding algorithm provided as a parameter
    IncrementNumberRounder^ rounder = ref new Windows::Globalization::NumberFormatting::IncrementNumberRounder();
    rounder->RoundingAlgorithm = roundingAlgorithm;

    // Formatter to display the rounded value.  It is recommended to use the increment number
    // rounder within a formatter object to avoid precision issues when displaying.
    DecimalFormatter^ formatter = ref new Windows::Globalization::NumberFormatting::DecimalFormatter();
    formatter->NumberRounder = rounder;

    // Stores the results
    String^ results = "";

    // Iterate through the increments we have defined in the scenario
    double incrementsToRound[] = { 0.001, 0.01, 0.1, 1.0 };
    for (int incrementIndex = 0; incrementIndex < sizeof(incrementsToRound)/sizeof(double); incrementIndex++)
    {
        // Set the significant digits to round to
        rounder->Increment = incrementsToRound[incrementIndex];

        // Display the properties of the scenario
        results = results + "Rounding with ";
        results = results + rounder->Increment + " increment and ";
        results = results + DisplayRoundingAlgorithmAsString(rounder->RoundingAlgorithm) + " rounding algorithm\n\n";

        // Iterate through the numbers to round and add them to the results
        double numbersToRound[] = { 0.1458, 1.458, 14.58, 145.8 };
        for (int numberIndex = 0; numberIndex < sizeof(numbersToRound)/sizeof(double); numberIndex++)
        {
            double numberToRound = numbersToRound[numberIndex];
            results = results + "Value: " + numberToRound + " Rounded: " + formatter->Format(numberToRound) + "\n";
        }

        // Add a carriage return at the end of the scenario for readability
        results = results + "\n";
    }

    return results;
}

/// <summary>
/// Shows how to do number rounding using the SignificantDigitsNumberRounder class.
/// </summary>
/// <param name="roundingAlgorithm"></param>
String^ Scenario5_RoundingAndPadding::DoSignificantDigitRoundingScenarios(RoundingAlgorithm roundingAlgorithm)
{
    // Create the rounder and set the rounding algorithm provided as a parameter.
    SignificantDigitsNumberRounder^ rounder = ref new Windows::Globalization::NumberFormatting::SignificantDigitsNumberRounder();
    rounder->RoundingAlgorithm = roundingAlgorithm;

    // Stores the results
    String^ results = "";

    // Iterate through the significant digits we have defined in the scenario
    unsigned int digitsToRound[] = { 3, 2, 1 };
    for (int digitIndex = 0; digitIndex < sizeof(digitsToRound)/sizeof(unsigned int); digitIndex++)
    {
        // Set the significant digits to round to
        rounder->SignificantDigits = digitsToRound[digitIndex];

        // Display the properties of the scenario
        results = results + "Rounding with ";
        results = results + rounder->SignificantDigits + " significant digits and ";
        results = results + DisplayRoundingAlgorithmAsString(rounder->RoundingAlgorithm) + " rounding algorithm\n\n";

        // Iterate through the numbers to round and add them to the results
        double numbersToRound[] = { 0.1458, 1.458, 14.58, 145.8 };
        for (int numberIndex = 0; numberIndex < sizeof(numbersToRound)/sizeof(double); numberIndex++)
        {
            double numberToRound = numbersToRound[numberIndex];
            double roundedValue = rounder->RoundDouble(numberToRound);
            results = results + "Value: " + numberToRound + " Rounded: " + roundedValue + "\n";
        }

        // Add a carriage return at the end of the scenario for readability
        results = results + "\n";
    }

    return results;
}

/// <summary>
/// This is the click handler for the 'Display' button.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Scenario5_RoundingAndPadding::Display_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    // Variable where we keep results to display
    String^ results = "";

    // Create a decimal formatter used to do padding with only 4 significant digits.  We zero the
    // integerDigits and fractionDigits to only show the behavior of the significantDigits property
    // when formatting.
    DecimalFormatter^ decimalFormatter = ref new DecimalFormatter();
    decimalFormatter->SignificantDigits = 4;
    decimalFormatter->IntegerDigits = 0;
    decimalFormatter->FractionDigits = 0;

    // Run through the scenarios with padding
    results = results + DoPaddingScenarios(decimalFormatter);

    // Create a percent formatter used to do padding with 4 significant digits, 2 minimum integer
    // digits, 2 minimum factional digits.  This will show how the behavior of the significantDigits
    // property in conjunction with the integerDigits and fractionDigits properties.
    PercentFormatter^ percentFormatter = ref new PercentFormatter();
    percentFormatter->SignificantDigits = 4;
    percentFormatter->IntegerDigits = 2;
    percentFormatter->FractionDigits = 2;

    // Run through the scenarios
    results = results + DoPaddingScenarios(percentFormatter);

    // Do the significant rounding scenarios with round up algorithm
    results = results + DoSignificantDigitRoundingScenarios(RoundingAlgorithm::RoundUp);

    // Do the significant rounding scenarios with round down algorithm
    results = results + DoSignificantDigitRoundingScenarios(RoundingAlgorithm::RoundDown);

    // Do the increment rounding scenarios with round half up algorithm
    results = results + DoIncrementRoundingScenarios(RoundingAlgorithm::RoundHalfUp);

    // Do the increment rounding scenarios with round half down algorithm
    results = results + DoIncrementRoundingScenarios(RoundingAlgorithm::RoundHalfDown);

    // Do currency formatting with rounding for Japanese Yen with round half to odd algorithm
    results = results + DoCurrencyRoundingScenarios("JPY", RoundingAlgorithm::RoundHalfToOdd);

    // Do currency formatting with rounding for Euro with round half to even algorithm
    results = results + DoCurrencyRoundingScenarios("EUR", RoundingAlgorithm::RoundHalfToEven);

    // Do padding and rounding scenarios using round half up algorithm
    results = results + DoPaddingAndRoundingScenarios(RoundingAlgorithm::RoundHalfUp, 4, 3, 2);

    // Do padding and rounding scenarios using round half down algorithm
    results = results + DoPaddingAndRoundingScenarios(RoundingAlgorithm::RoundHalfDown, 4, 3, 2);

    OutputTextBlock->Text = results;
}


text:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Code generated by Microsoft (R) AutoRest Code Generator.

package com.azure.resourcemanager.postgresqlflexibleserver.generated;

import com.azure.core.util.Context;

/** Samples for Configurations Get. */
public final class ConfigurationsGetSamples {
    /*
     * x-ms-original-file: specification/postgresql/resource-manager/Microsoft.DBforPostgreSQL/stable/2021-06-01/examples/ConfigurationGet.json
     */
    /**
     * Sample code: ConfigurationGet.
     *
     * @param manager Entry point to PostgreSqlManager.
     */
    public static void configurationGet(com.azure.resourcemanager.postgresqlflexibleserver.PostgreSqlManager manager) {
        manager.configurations().getWithResponse("testrg", "testserver", "array_nulls", Context.NONE);
    }
}

redpajama_set_name: RedPajamaGithub


text:
- Project managers need to use **systems thinking**: to take a holistic(整體的) view of carrying out projects within the context of the organization.
- a **systems approach** includes:
    - **Systems philosophy**
    - **Systems analysis**
    - **Systems management**

### 2. Three Sphere(領域) Model of Systems Management

- Organizations:
    - **Structural frame**: Roles and responsibilities, coordination and control.  (Organizational charts help describe the frame)
    - **Human resources frame**: Providing harmony between needs of the organization and needs of people.
    - **Political frame**: Coalitions(並集) composed of varied individuals and interest groups. Conflicts and power are key issues.
    - **symbolic frame**: Symbols and meanings related to events. Culture, language, traditions and image are all parts of this frame.

### 3. Organizational Structures

- Functional: **functional managers** -> **CEO**
- Project: **program managers** -> **CEO**
- Matrix: **personnel** -> **two or more bosses** (between functional and project structures)

### 4. Organiazational Culture

- a set of shared assumptions, values and behaviors that characterize the functioning of an organiaztion.
- characteristics of organizational culture (**bold** means it's more important):
    - **Member identify**
    - **Risk tolerance**
    - **Group emphasis**
    - **Reward criteria**
    - People focus
    - **Conflict tolerance**
    - **Unit integration**
    - Means-ends orientation(導向)
    - Control
    - **Open-systems focus**

### 5. Project Life Cycle

- a **project life cycle**: a collection of project phases. (from the projects' start point to the end point)
- phases of a traditional project life cycle.

- a **Systems Development Life Cycle(ADLC)** is a framework for describing the phases involved in developing and maintaining information systems. A system development project can follow:
    - **Predictive life cycle**: the scope of the project can be clearly articulated(清楚說明的) and the schedule and cost can be predicted.
        - **Waterfall Model**: has well-defined, linear stages of systems development and support.
        - **Spiral Model**: shows that software is developed using an iterative(迭代) or spiral(螺旋) approach rather than a linear approach.
        - **Incremental Build Model**: provides for progressive(漸進的) development of operational software.
        - **Prototyping(原型) Model**: used for developing prototypes to clarify user requirements.
        - **Rapid Application Development(RAD) Model**: used to produce systems quickly without sacrificing(犧牲) quality.
    - **Adaptive software development life cycle**: requirements cannot be clearly expressed, projects are mission driven and component based, using time-based cycles to meet target dates.
        - **Agile Development Model**

### 6. Definitives

- **Globalization**: software has been completed by people all around the world in many companies.
- **Outsourcing(外包)**: an organization acquires goods and/or sources from an outside source.
    - **Offshoring(離岸外包)**: to describe outsourcing from another countries.
- **Virtual teams**: a group of individuals working across time and space using communiation technologies.

### 7. Scrum Framework

- **Scrum Framework** is a leading agile development method.

### 8. Q&A

- In what organizational structure, program managers, rather than functional managers or vice presidents, report to the CEO. Their staffs have a variety of skills needed to complete all required tasks within their programs.

> answer: *Project.*

- Which of the following is true of a matrix organizational structure?
    - In a matrix organizational structure, employees are organized into departments according to their skills, and there is little interaction between employees from different departments.
    - Project managers in matrix organizations have staff from only a single functional area working on their projects.
    - In a strong matrix organizational structure, the project manager controls the project budget and has moderate to high authority.
    - A matrix organizational structure is hierarchical, but instead of functional managers reporting to the CEO, program managers report to the CEO.

> answer: *In a strong matrix organizational structure, the project manager controls the project budget and has moderate to high authority.*

- Which characteristic of organizational culture describes the degree to which management's decisions take into account the effect of outcomes on people within the organization?

> answer: *people focus.*

- What refers to the degree to employees identify with the organization as a whole, rather than with their types of job or profession?

> answer: *Member identity.*

- What refers to the degree to which departments within an organization are encouraged to coordinate with each other?

> answer: *Not group emphasis, but unit integration.*

- What refers to the degree to which the organization monitors and responds to changes in the external environment?

> answer: *Open-systems focus.*

- The first two traditional project phases (concept and development) focus on planning, and are often referred to as what?

> answer: *project feasibility.*

- In what phase, the project team creates a definitive or very accurate cost estimate, delivers the required work, and provides performance reports to stakeholders?

> answer: *implementation.*

- Which of the following is a disadvantage of virtual teams as compared to traditional teams?
    - Increased costs for office space and support
    - Limited flexibility in team working hours
    - Reduced opportunities for informal transfer of information
    - Reduced dependence on technology and processes for accomplishing work

> answer: *Reduced opportunities for informal transfer of information.*


text:
program test

  use FoX_wkml

  implicit none

  type(xmlf_t) :: myfile
  type(color_t) :: mycolor

  call kmlSetCustomColor(mycolor, 'F90000FF')

  call kmlBeginFile(myfile, "test.xml", -1)
  call kmlCreateLineStyle(myfile, id='myid', width=1, colorname='red', color=mycolor)
  call kmlFinishFile(myfile)

end program test


text:
package edu.upc.eetac.dsa.grouptalk;

import edu.upc.eetac.dsa.grouptalk.dao.*;
import edu.upc.eetac.dsa.grouptalk.entity.AuthToken;
import edu.upc.eetac.dsa.grouptalk.entity.InterestGroups;
import edu.upc.eetac.dsa.grouptalk.entity.JoinGroup;
import edu.upc.eetac.dsa.grouptalk.entity.User;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.SQLException;

/**
 * Created by Jordi on 28/10/2015.
 */

@Path("joingroup")
public class JoinGroupResource {
    @Context
    private SecurityContext securityContext;
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(GrouptalkMediaType.GROUPTALK_AUTH_TOKEN)
    public Response createJoinGroup(@FormParam("userid") String userid, @FormParam("groupid") String groupid,@Context UriInfo uriInfo) throws URISyntaxException {
        if(userid == null || groupid == null)
            throw new BadRequestException("all parameters are mandatory");
        JoinGroupDAO joinGroupDAO = new JoinGroupDAOImpl();
        JoinGroup joinGroup = null;
        AuthToken authenticationToken = null;
        try {
            joinGroup = joinGroupDAO.createJoinGroup(securityContext.getUserPrincipal().getName(), groupid);
        } catch (SQLException e) {
            throw new InternalServerErrorException();
        }
        URI uri = new URI(uriInfo.getAbsolutePath().toString() + "/" + joinGroup.getUserid());
        return Response.created(uri).type(GrouptalkMediaType.GROUPTALK_InterestGroups).entity(joinGroup).build();
    }
    @Path("/goout")
    @DELETE
    public Response deleteJoinGroup(@FormParam("userid") String userid, @FormParam("groupid") String groupid,@Context UriInfo uriInfo) throws URISyntaxException {
        if(userid == null || groupid == null)
            throw new BadRequestException("all parameters are mandatory");
        JoinGroupDAO joinGroupDAO = new JoinGroupDAOImpl();
        JoinGroup joinGroup = null;
        AuthToken authenticationToken = null;
        try {
            joinGroup = joinGroupDAO.deleteJoinGroup(securityContext.getUserPrincipal().getName(), groupid);
        } catch (SQLException e) {
            throw new InternalServerErrorException();
        }
        URI uri = new URI(uriInfo.getAbsolutePath().toString() + "/" + joinGroup.getUserid());
        return Response.created(uri).type(GrouptalkMediaType.GROUPTALK_InterestGroups).entity(joinGroup).build();
    }
}


text:
package cs.si.stavor;

import cs.si.stavor.app.Parameters;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;

public class SplashActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_splash);

		new Handler().postDelayed(new Runnable() {

            /*
             * Showing splash screen with a timer. This will be useful when you
             * want to show case your app logo / company
             */

            @Override
            public void run() {
                // This method will be executed once the timer is over
                // Start your app main activity
                Intent i = new Intent(SplashActivity.this, MainActivity.class);
                startActivity(i);

                // close this activity
                finish();
            }
        }, Parameters.App.splash_min_time_ms);
	}
}


text:
require 'test/test_helper'

class TimeoutableTest < ActiveSupport::TestCase

  test 'should be expired' do
    assert new_user.timedout?(31.minutes.ago)
  end

  test 'should not be expired' do
    assert_not new_user.timedout?(29.minutes.ago)
  end

  test 'should not be expired when params is nil' do
    assert_not new_user.timedout?(nil)
  end

  test 'fallback to Devise config option' do
    swap Devise, :timeout_in => 1.minute do
      user = new_user
      assert user.timedout?(2.minutes.ago)
      assert_not user.timedout?(30.seconds.ago)

      Devise.timeout_in = 5.minutes
      assert_not user.timedout?(2.minutes.ago)
      assert user.timedout?(6.minutes.ago)
    end
  end
end


text:
Websockets

<textarea id="log" style="width:100%;height:100%"></textarea>


text:
// See docs in ../ops/nn_ops.cc.

#define EIGEN_USE_THREADS

#include "tensorflow/core/kernels/data_format_ops.h"

#include <map>

#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/platform/errors.h"

namespace tensorflow {

typedef Eigen::ThreadPoolDevice CPUDevice;
typedef Eigen::GpuDevice GPUDevice;

// Ensure that `src` and `dst` define a valid permutation.
// Ops defined in this file assume that user specifies a permutation via two
// string attributes. This check validates that these attributes properly define
// it to prevent security vulnerabilities.
static bool IsValidPermutation(const std::string& src, const std::string& dst) {
  if (src.size() != dst.size()) {
    return false;
  }

  std::map<char, bool> characters;

  // Every character in `src` must be present only once
  for (const auto c : src) {
    if (characters[c]) {
      return false;
    }
    characters[c] = true;
  }

  // Every character in `dst` must show up in `src` exactly once
  for (const auto c : dst) {
    if (!characters[c]) {
      return false;
    }
    characters[c] = false;
  }

  // At this point, characters[] has been switched to true and false exactly
  // once for all character in `src` (and `dst`) so we have a valid permutation
  return true;
}

template <typename Device, typename T>
class DataFormatDimMapOp : public OpKernel {
 public:
  explicit DataFormatDimMapOp(OpKernelConstruction* context)
      : OpKernel(context) {
    string src_format;
    OP_REQUIRES_OK(context, context->GetAttr("src_format", &src_format));
    string dst_format;
    OP_REQUIRES_OK(context, context->GetAttr("dst_format", &dst_format));
    OP_REQUIRES(context, src_format.size() == 4 || src_format.size() == 5,
                errors::InvalidArgument(
                    "Source format must be of length 4 or 5, received "
                    "src_format = ",
                    src_format));
    OP_REQUIRES(context, dst_format.size() == 4 || dst_format.size() == 5,
                errors::InvalidArgument("Destination format must be of length "
                                        "4 or 5, received dst_format = ",
                                        dst_format));
    OP_REQUIRES(
        context, IsValidPermutation(src_format, dst_format),
        errors::InvalidArgument(
            "Destination and source format must determine a permutation, got ",
            src_format, " and ", dst_format));
    dst_idx_ = Tensor(DT_INT32, {static_cast<int64_t>(src_format.size())});
    for (int i = 0; i < src_format.size(); ++i) {
      for (int j = 0; j < dst_format.size(); ++j) {
        if (dst_format[j] == src_format[i]) {
          dst_idx_.vec<int>()(i) = j;
          break;
        }
      }
    }
  }

  void Compute(OpKernelContext* context) override {
    const Tensor& input = context->input(0);
    Tensor* output;
    OP_REQUIRES_OK(context,
                   context->allocate_output(0, input.shape(), &output));
    functor::DataFormatDimMap<Device, T>()(context->eigen_device<Device>(),
                                           input.flat<T>(), output->flat<T>(),
                                           dst_idx_.vec<int>());
  }

  Tensor dst_idx_;
};

template <typename Device, typename T>
class DataFormatVecPermuteOp : public OpKernel {
 public:
  explicit DataFormatVecPermuteOp(OpKernelConstruction* context)
      : OpKernel(context) {
    string src_format;
    OP_REQUIRES_OK(context, context->GetAttr("src_format", &src_format));
    OP_REQUIRES(context, src_format.size() == 4 || src_format.size() == 5,
                errors::InvalidArgument(
                    "Source format must be of length 4 or 5, received "
                    "src_format = ",
                    src_format));
    string dst_format;
    OP_REQUIRES_OK(context, context->GetAttr("dst_format", &dst_format));
    OP_REQUIRES(context, dst_format.size() == 4 || dst_format.size() == 5,
                errors::InvalidArgument("Destination format must be of length "
                                        "4 or 5, received dst_format = ",
                                        dst_format));
    OP_REQUIRES(
        context, IsValidPermutation(src_format, dst_format),
        errors::InvalidArgument(
            "Destination and source format must determine a permutation, got ",
            src_format, " and ", dst_format));
    src_format_ = src_format;
    dst_format_ = dst_format;
  }

  void Compute(OpKernelContext* context) override {
    const Tensor& input = context->input(0);
    OP_REQUIRES(context, input.dims() == 1 || input.dims() == 2,
                errors::InvalidArgument(
                    "input must be a vector or 2D tensor, but got shape ",
                    input.shape().DebugString()));

    const int full_dim_count = src_format_.size();
    const int spatial_dim_count = full_dim_count - 2;

    if (input.dims() == 1) {
      OP_REQUIRES(context,
                  input.NumElements() == spatial_dim_count ||
                      input.NumElements() == full_dim_count,
                  errors::InvalidArgument("1D input must be of size ",
                                          spatial_dim_count, " or ",
                                          full_dim_count, ", but got shape ",
                                          input.shape().DebugString()));
    } else if (input.dims() == 2) {
      OP_REQUIRES(context,
                  input.dim_size(0) == spatial_dim_count ||
                      input.dim_size(0) == full_dim_count,
                  errors::InvalidArgument("First dimension of 2D input must be "
                                          "of size ",
                                          spatial_dim_count, " or ",
                                          full_dim_count, ", but got shape ",
                                          input.shape().DebugString()));
      OP_REQUIRES(
          context, input.dim_size(1) == 2,
          errors::InvalidArgument(
              "Second dimension of 2D input must be of size 2, but got shape ",
              input.shape().DebugString()));
    }

    Tensor* output = nullptr;
    OP_REQUIRES_OK(context,
                   context->allocate_output(0, input.shape(), &output));
    // Support 1D and 2D cases.
    Eigen::DSizes<Eigen::DenseIndex, 10> dst_idx;
    string src_format_str = src_format_;
    string dst_format_str = dst_format_;
    if (input.dim_size(0) == spatial_dim_count) {
      // If the input is a vector of size spatial_dim_count, treat the elements
      // as spatial dimensions.
      auto keep_only_spatial_dimensions =
          [spatial_dim_count](string* format_str) -> void {
        auto new_end =
            std::remove_if(format_str->begin(), format_str->end(),
                           [spatial_dim_count](const char dim) {
                             return dim != 'H' && dim != 'W' &&
                                    (spatial_dim_count == 2 || dim != 'D');
                           });
        format_str->erase(new_end, format_str->end());
      };
      keep_only_spatial_dimensions(&src_format_str);
      keep_only_spatial_dimensions(&dst_format_str);
      if (spatial_dim_count == 3) {
        OP_REQUIRES(
            context, src_format_str.size() == 3 && dst_format_str.size() == 3,
            errors::InvalidArgument(
                "Format specifier must contain D, H and W for 2D case"));
      } else {
        DCHECK(spatial_dim_count == 2);
        OP_REQUIRES(context,
                    src_format_str.size() == 2 && dst_format_str.size() == 2,
                    errors::InvalidArgument(
                        "Format specifier must contain H and W for 2D case"));
      }
    }
    ComputeDstIndex(src_format_str, dst_format_str, input.dims(), &dst_idx);

    functor::DataFormatVecPermute<Device, T>()(context->eigen_device<Device>(),
                                               input.flat<T>(),
                                               output->flat<T>(), dst_idx);
  }

 private:
  // Finds out the destination index. Support 1D and 2D cases.
  // Example: HWNC --> NHWC
  // 1D: dst = [1, 2, 0, 3],
  // 2D: dst = [2, 3, 4, 5, 0, 1, 6, 7]
  static void ComputeDstIndex(const string& src_format_str,
                              const string& dst_format_str, int num_dim,
                              Eigen::DSizes<Eigen::DenseIndex, 10>* dst) {
    for (int i = 0; i < src_format_str.size(); ++i) {
      for (int j = 0; j < dst_format_str.size(); ++j) {
        if (dst_format_str[j] != src_format_str[i]) continue;
        // Found the dst index. Set output based on the number of dims.
        for (int k = 0; k < num_dim; ++k) {
          (*dst)[i * num_dim + k] = j * num_dim + k;
        }
      }
    }
  }

  string src_format_;
  string dst_format_;
};

#define REGISTER_KERNEL(T)                                                \
  REGISTER_KERNEL_BUILDER(                                                \
      Name("DataFormatDimMap").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      DataFormatDimMapOp<CPUDevice, T>);
TF_CALL_int32(REGISTER_KERNEL);
TF_CALL_int64(REGISTER_KERNEL);
#undef REGISTER_KERNEL

#define REGISTER_KERNEL(T)                                                    \
  REGISTER_KERNEL_BUILDER(                                                    \
      Name("DataFormatVecPermute").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      DataFormatVecPermuteOp<CPUDevice, T>);
TF_CALL_int32(REGISTER_KERNEL);
TF_CALL_int64(REGISTER_KERNEL);
#undef REGISTER_KERNEL

#define REGISTER_KERNEL(T)                             \
  REGISTER_KERNEL_BUILDER(Name("DataFormatDimMap")     \
                              .Device(DEVICE_CPU)      \
                              .Label("host")           \
                              .TypeConstraint<T>("T"), \
                          DataFormatDimMapOp<CPUDevice, T>);
TF_CALL_int32(REGISTER_KERNEL);
TF_CALL_int64(REGISTER_KERNEL);
#undef REGISTER_KERNEL

#define REGISTER_KERNEL(T)                             \
  REGISTER_KERNEL_BUILDER(Name("DataFormatVecPermute") \
                              .Device(DEVICE_CPU)      \
                              .Label("host")           \
                              .TypeConstraint<T>("T"), \
                          DataFormatVecPermuteOp<CPUDevice, T>);
TF_CALL_int32(REGISTER_KERNEL);
TF_CALL_int64(REGISTER_KERNEL);
#undef REGISTER_KERNEL

#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
// Forward declarations of the functor specializations for GPU.
namespace functor {
#define DECLARE_GPU_SPEC(T)                                    \
  template <>                                                  \
  void DataFormatDimMap<GPUDevice, T>::operator()(             \
      const GPUDevice& d, typename TTypes<T>::ConstFlat x,     \
      typename TTypes<T>::Flat y, const TTypes<int>::Vec dst); \
  extern template struct DataFormatDimMap<GPUDevice, T>;
#define DECLARE_GPU_SPECS(T) DECLARE_GPU_SPEC(T);
TF_CALL_int32(DECLARE_GPU_SPECS);
TF_CALL_int64(DECLARE_GPU_SPECS);
#undef DECLARE_GPU_SPEC

#define DECLARE_GPU_SPEC(T)                                 \
  template <>                                               \
  void DataFormatVecPermute<GPUDevice, T>::operator()(      \
      const GPUDevice& d, typename TTypes<T>::ConstFlat x,  \
      typename TTypes<T>::Vec y,                            \
      const Eigen::DSizes<Eigen::DenseIndex, 10>& dst_idx); \
  extern template struct DataFormatVecPermute<GPUDevice, T>;
#define DECLARE_GPU_SPECS(T) DECLARE_GPU_SPEC(T);
TF_CALL_int32(DECLARE_GPU_SPECS);
TF_CALL_int64(DECLARE_GPU_SPECS);
#undef DECLARE_GPU_SPEC
}  // namespace functor

// Registration of the GPU implementations.
#define REGISTER_GPU_KERNEL(T)                                            \
  REGISTER_KERNEL_BUILDER(                                                \
      Name("DataFormatDimMap").Device(DEVICE_GPU).TypeConstraint<T>("T"), \
      DataFormatDimMapOp<GPUDevice, T>);
TF_CALL_int32(REGISTER_GPU_KERNEL);
TF_CALL_int64(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL

#define REGISTER_GPU_KERNEL(T)                                                \
  REGISTER_KERNEL_BUILDER(                                                    \
      Name("DataFormatVecPermute").Device(DEVICE_GPU).TypeConstraint<T>("T"), \
      DataFormatVecPermuteOp<GPUDevice, T>);
TF_CALL_int32(REGISTER_GPU_KERNEL);
TF_CALL_int64(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL
#endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM

// Registration of the DEVICE_DEFAULT implementations.
#define REGISTER_DEVICE_DEFAULT_KERNEL(T)              \
  REGISTER_KERNEL_BUILDER(Name("DataFormatDimMap")     \
                              .Device(DEVICE_DEFAULT)  \
                              .HostMemory("x")         \
                              .HostMemory("y")         \
                              .Label("host")           \
                              .TypeConstraint<T>("T"), \
                          DataFormatDimMapOp<CPUDevice, T>);
TF_CALL_int32(REGISTER_DEVICE_DEFAULT_KERNEL);
TF_CALL_int64(REGISTER_DEVICE_DEFAULT_KERNEL);
#undef REGISTER_DEVICE_DEFAULT_KERNEL

#define REGISTER_DEVICE_DEFAULT_KERNEL(T)              \
  REGISTER_KERNEL_BUILDER(Name("DataFormatVecPermute") \
                              .Device(DEVICE_DEFAULT)  \
                              .HostMemory("x")         \
                              .HostMemory("y")         \
                              .Label("host")           \
                              .TypeConstraint<T>("T"), \
                          DataFormatVecPermuteOp<CPUDevice, T>);
TF_CALL_int32(REGISTER_DEVICE_DEFAULT_KERNEL);
TF_CALL_int64(REGISTER_DEVICE_DEFAULT_KERNEL);
#undef REGISTER_DEVICE_DEFAULT_KERNEL

}  // namespace tensorflow