text:
class SaveCardOfferObserver;

namespace autofill {

// Manages logic for determining whether upload credit card save to Google
// Payments is available as well as actioning both local and upload credit card
// save logic.  Owned by FormDataImporter.
class CreditCardSaveManager {
 public:
  // Possible fields and values detected during credit card form submission, to
  // be sent to Google Payments to better determine if upload credit card save
  // should be offered.  These should stay consistent with the equivalent enum
  // in Google Payments code.
  enum DetectedValue {
    // Set if a valid CVC was detected.  Will always be set if the CVC fix flow
    // is enabled.
    CVC = 1 << 0,
    // Set if a cardholder name was found, *unless* conflicting names were
    // found.
    CARDHOLDER_NAME = 1 << 1,
    // Set if an address name was found, *unless* conflicting names were found.
    ADDRESS_NAME = 1 << 2,
    // Set if an address line was found in any address (regardless of
    // conflicts).
    ADDRESS_LINE = 1 << 3,
    // Set if a locality was found in any address (regardless of conflicts).
    LOCALITY = 1 << 4,
    // Set if an administrative area was found in any address (regardless of
    // conflicts).
    ADMINISTRATIVE_AREA = 1 << 5,
    // Set if a postal code was found in any address, *unless* conflicting
    // postal codes were found.
    POSTAL_CODE = 1 << 6,
    // Set if a country code was found in any address (regardless of conflicts).
    COUNTRY_CODE = 1 << 7,
    // Set if the user is already syncing data from a Google Payments account.
    HAS_GOOGLE_PAYMENTS_ACCOUNT = 1 << 8,
    // Card expiration month.
    CARD_EXPIRATION_MONTH = 1 << 9,
    // Card expiration year.
    CARD_EXPIRATION_YEAR = 1 << 10,
    // Phone number was found on any address (not currently used).
    PHONE_NUMBER = 1 << 11,
    // Set if cardholder name was explicitly requested in the offer-to-save
    // dialog.  In general, this should happen when name is conflicting/missing
    // and the user does not have a Google Payments account.
    USER_PROVIDED_NAME = 1 << 12,
    // Set if expiration date was explicitly requested in the offer-to-save
    // dialog. In general, this should happen when expiration date month or year
    // is missing.
    USER_PROVIDED_EXPIRATION_DATE = 1 << 13,
  };

  // An observer class used by browsertests that gets notified whenever
  // particular actions occur.
  class ObserverForTest {
   public:
    virtual ~ObserverForTest() = default;
    virtual void OnOfferLocalSave() {}
    virtual void OnOfferUploadSave() {}
    virtual void OnDecideToRequestUploadSave() {}
    virtual void OnReceivedGetUploadDetailsResponse() {}
    virtual void OnSentUploadCardRequest() {}
    virtual void OnReceivedUploadCardResponse() {}
    virtual void OnShowCardSavedFeedback() {}
    virtual void OnStrikeChangeComplete() {}
  };

  // The parameters should outlive the CreditCardSaveManager.
  CreditCardSaveManager(AutofillClient* client,
                        payments::PaymentsClient* payments_client,
                        const std::string& app_locale,
                        PersonalDataManager* personal_data_manager);

  CreditCardSaveManager(const CreditCardSaveManager&) = delete;
  CreditCardSaveManager& operator=(const CreditCardSaveManager&) = delete;

  virtual ~CreditCardSaveManager();

  // Begins the process to offer local credit card save to the user.
  // If |has_non_focusable_field| is true, the save is triggered by a form that
  // has non_focusable fields.
  // If |from_dynamic_change_form| is true, the save is triggered by a dynamic
  // change form. Returns true if the prompt is shown.
  bool AttemptToOfferCardLocalSave(bool from_dynamic_change_form,
                                   bool has_non_focusable_field,
                                   const CreditCard& card);

  // Begins the process to offer upload credit card save to the user if the
  // imported card passes all requirements and Google Payments approves.
  // If |has_non_focusable_field| is true, the save is triggered by a form that
  // has non-focusable fields. if |uploading_local_card| is true, the card being
  // offered for upload is already a local card on the device. If
  // |from_dynamic_change_form| is true, the save is triggered by a dynamic
  // change form.
  void AttemptToOfferCardUploadSave(const FormStructure& submitted_form,
                                    bool from_dynamic_change_form,
                                    bool has_non_focusable_field,
                                    const CreditCard& card,
                                    const bool uploading_local_card);

  // Returns true if all the conditions for enabling the upload of credit card
  // are satisfied.
  virtual bool IsCreditCardUploadEnabled();

  // For testing.
  void SetAppLocale(std::string app_locale) { app_locale_ = app_locale; }

  // Set Autofill address profiles that are only preliminarily imported.
  // A preliminary import may happen when the address is found in the same
  // form as a credit card that is currently processed by the manager.
  void SetPreliminarilyImportedAutofillProfile(
      const std::vector<AutofillProfile>& profiles) {
    preliminarily_imported_address_profiles_ = profiles;
  }

  // Clear the preliminarily imported Autofill address profiles.
  void ClearPreliminarilyImportedAutofillProfile() {
    preliminarily_imported_address_profiles_.clear();
  }

 protected:
  // Returns the result of an upload request. If |result| ==
  // |AutofillClient::PaymentsRpcResult::kSuccess|, clears strikes for the saved
  // card. Additionally, |server_id| may, optionally, contain the opaque
  // identifier for the card on the server. Exposed for testing.
  virtual void OnDidUploadCard(
      AutofillClient::PaymentsRpcResult result,
      const payments::PaymentsClient::UploadCardResponseDetails&
          upload_card_response_details);

 private:
  friend class CreditCardSaveManagerTest;
  friend class CreditCardSaveManagerTestObserverBridge;
  friend class LocalCardMigrationBrowserTest;
  friend class TestCreditCardSaveManager;
  friend class SaveCardBubbleViewsFullFormBrowserTest;
  friend class SaveCardInfobarEGTestHelper;
  friend class ::SaveCardOfferObserver;
  FRIEND_TEST_ALL_PREFIXES(
      SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream,
      StrikeDatabase_Upload_FullFlowTest);
  FRIEND_TEST_ALL_PREFIXES(SaveCardBubbleViewsFullFormBrowserTest,
                           StrikeDatabase_Local_FullFlowTest);
  FRIEND_TEST_ALL_PREFIXES(SaveCardBubbleViewsFullFormBrowserTestForStatusChip,
                           Feedback_CardSavingAnimation);

  // Returns the CreditCardSaveStrikeDatabase for |client_|.
  CreditCardSaveStrikeDatabase* GetCreditCardSaveStrikeDatabase();

#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
  // Returns the GetLocalCardMigrationStrikeDatabase for |client_|.
  LocalCardMigrationStrikeDatabase* GetLocalCardMigrationStrikeDatabase();
#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)

  // Returns the legal message retrieved from Payments. On failure or not
  // meeting Payments's conditions for upload, |legal_message| will contain
  // nullptr. |supported_card_bin_ranges| is a list of BIN prefix ranges which
  // are supoorted, with the first and second number in the pair being the start
  // and end of the range.
  void OnDidGetUploadDetails(
      AutofillClient::PaymentsRpcResult result,
      const std::u16string& context_token,
      std::unique_ptr<base::Value> legal_message,
      std::vector<std::pair<int, int>> supported_card_bin_ranges);

  // Logs the number of strikes that a card had when save succeeded.
  void LogStrikesPresentWhenCardSaved(bool is_local, const int num_strikes);

  // Examines |card| and the stored profiles and if a candidate set of profiles
  // is found that matches the client-side validation rules, assigns the values
  // to |upload_request.profiles|. If any problems are found when determining
  // the candidate set of profiles, sets |upload_decision_metrics_| with the
  // failure reasons. Appends any experiments that were triggered to
  // |upload_request.active_experiments|. Note that if the relevant feature is
  // enabled, the addresses being assigned to |upload_request.profiles| may only
  // contain countries.
  void SetProfilesForCreditCardUpload(
      const CreditCard& card,
      payments::PaymentsClient::UploadRequestDetails* upload_request);

  // Analyzes the decisions made while importing address profile and credit card
  // data in preparation for upload credit card save, in order to determine what
  // uploadable data is actually available.
  int GetDetectedValues() const;

  // Offers local credit card save once the Autofill StrikeSystem has made its
  // decision.
  void OfferCardLocalSave();

  // Offers credit card upload if Payments has allowed offering to save and the
  // Autofill StrikeSystem has made its decision.
  void OfferCardUploadSave();

  // Called once the user makes a decision with respect to the local credit card
  // offer-to-save prompt. If accepted, clears strikes for the to-be-saved card
  // and has |personal_data_manager_| save the card.
  void OnUserDidDecideOnLocalSave(
      AutofillClient::SaveCardOfferUserDecision user_decision);

  // Called once the user makes a decision with respect to the credit card
  // upload offer-to-save prompt.
  // If accepted:
  //   Sets |user_did_accept_upload_prompt_| and calls SendUploadCardRequest if
  //   the risk data is available. Sets the cardholder name on the upload
  //   request if |user_provided_card_details.cardholder_name| is set. Sets the
  //   expiration date on the upload request if
  //   |user_provided_card_details.expiration_date_month| and
  //   |user_provided_card_details.expiration_date_year| are both set.
  // If rejected or ignored:
  //   Logs a strike against the current card to deter future offers to save.
  void OnUserDidDecideOnUploadSave(
      AutofillClient::SaveCardOfferUserDecision user_decision,
      const AutofillClient::UserProvidedCardDetails&
          user_provided_card_details);

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
  // Upload the card details with the user provided cardholder_name.
  // Only relevant for mobile as fix flow is two steps on mobile compared to
  // one step on desktop.
  void OnUserDidAcceptAccountNameFixFlow(const std::u16string& cardholder_name);

  // Upload the card details with the user provided expiration date month and
  // year. Only relevant for mobile as fix flow is two steps on mobile compared
  // to one step on desktop.
  void OnUserDidAcceptExpirationDateFixFlow(const std::u16string& month,
                                            const std::u16string& year);
#endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)

  // Helper function that calls SendUploadCardRequest by setting
  // UserProvidedCardDetails.
  void OnUserDidAcceptUploadHelper(
      const AutofillClient::UserProvidedCardDetails&
          user_provided_card_details);

  // Saves risk data in |uploading_risk_data_| and calls SendUploadCardRequest
  // if the user has accepted the prompt.
  void OnDidGetUploadRiskData(const std::string& risk_data);

  // Finalizes the upload request and calls PaymentsClient::UploadCard().
  void SendUploadCardRequest();

  // Called when the user ignored or declined the credit card save prompt. Logs
  // a strike for the given card in order to help deter future offers to save,
  // provided that save was actually offered to the user.
  void OnUserDidIgnoreOrDeclineSave(
      const std::u16string& card_last_four_digits);

  // Used for browsertests. Gives the |observer_for_testing_| a notification
  // a strike change has been made.
  void OnStrikeChangeComplete(const int num_strikes);

  // Returns metric relevant to the CVC field based on values in
  // |found_cvc_field_|, |found_value_in_cvc_field_| and
  // |found_cvc_value_in_non_cvc_field_|. Only called when a valid CVC was NOT
  // found.
  autofill_metrics::CardUploadDecision GetCVCCardUploadDecisionMetric() const;

  // Logs the card upload decisions in UKM and UMA.
  // |upload_decision_metrics| is a bitmask of
  // |AutofillMetrics::CardUploadDecisionMetric|.
  void LogCardUploadDecisions(int upload_decision_metrics);

  // Logs the card upload decisions bitmask to chrome://autofill-internals.
  void LogCardUploadDecisionsToAutofillInternals(int upload_decision_metrics);

  // Logs the reason why expiration date was explicitly requested.
  void LogSaveCardRequestExpirationDateReasonMetric();

  // For testing.
  void SetEventObserverForTesting(ObserverForTest* observer) {
    observer_for_testing_ = observer;
  }

  const raw_ptr<AutofillClient> client_;

  // Handles Payments service requests.
  // Owned by BrowserAutofillManager.
  raw_ptr<payments::PaymentsClient> payments_client_;

  std::string app_locale_;

  // The personal data manager, used to save and load personal data to/from the
  // web database.  This is overridden by the BrowserAutofillManagerTest.
  // Weak reference.
  // May be NULL.  NULL indicates OTR.
  raw_ptr<PersonalDataManager> personal_data_manager_;

  // The credit card to be saved if local credit card save is accepted.
  CreditCard local_card_save_candidate_;

  // Collected information about a pending upload request.
  payments::PaymentsClient::UploadRequestDetails upload_request_;

  // A bitmask of |AutofillMetrics::CardUploadDecisionMetric| representing the
  // decisions made when determining if credit card upload save should be
  // offered.
  int upload_decision_metrics_ = 0;

  // |true| if the offer-to-save bubble/infobar should pop-up, |false| if not.
  // Will be absl::nullopt until data has been retrieved from the StrikeSystem.
  absl::optional<bool> show_save_prompt_;

  // |true| if the card being offered for upload is already a local card on the
  // device; |false| otherwise.
  bool uploading_local_card_ = false;

  // |true| if the user has opted to upload save their credit card to Google.
  bool user_did_accept_upload_prompt_ = false;

  // |should_request_expiration_date_from_user_| is |true| if the upload save
  // dialog should request expiration date from the user.
  bool should_request_expiration_date_from_user_ = false;

  // |should_request_name_from_user_| is |true| if the upload save dialog should
  // request cardholder name from the user (prefilled with Google Account name).
  bool should_request_name_from_user_ = false;

  // |found_cvc_field_| is |true| if there exists a field that is determined to
  // be a CVC field via heuristics.
  bool found_cvc_field_ = false;
  // |found_value_in_cvc_field_| is |true| if a field that is determined to
  // be a CVC field via heuristics has non-empty |value|.
  // |value| may or may not be a valid CVC.
  bool found_value_in_cvc_field_ = false;
  // |found_cvc_value_in_non_cvc_field_| is |true| if a field that is not
  // determined to be a CVC field via heuristics has a valid CVC |value|.
  bool found_cvc_value_in_non_cvc_field_ = false;

  // |has_non_focusable_field_| is |true| if there exists a field that
  // |is_focusable| is false.
  bool has_non_focusable_field_ = false;

  // |from_dynamic_change_form_| is |true| values imported from dynamic change
  // form.
  bool from_dynamic_change_form_ = false;

  // The origin of the top level frame from which a form is uploaded.
  url::Origin pending_upload_request_origin_;

  // The parsed lines from the legal message returned from GetUploadDetails.
  LegalMessageLines legal_message_lines_;

  std::unique_ptr<CreditCardSaveStrikeDatabase>
      credit_card_save_strike_database_;

  // Profiles that are only preliminarily imported. Those profiles are used
  // during a card import to determine the name and country for storing a new
  // card.
  std::vector<AutofillProfile> preliminarily_imported_address_profiles_;

#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
  std::unique_ptr<LocalCardMigrationStrikeDatabase>
      local_card_migration_strike_database_;
#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)

  // May be null.
  raw_ptr<ObserverForTest> observer_for_testing_ = nullptr;

  base::WeakPtrFactory<CreditCardSaveManager> weak_ptr_factory_{this};

  FRIEND_TEST_ALL_PREFIXES(
      CreditCardSaveManagerTest,
      UploadCreditCard_ShouldRequestCardholderName_ResetBetweenConsecutiveSaves);
  FRIEND_TEST_ALL_PREFIXES(
      CreditCardSaveManagerTest,
      UploadCreditCard_ShouldRequestExpirationDate_ResetBetweenConsecutiveSaves);
  FRIEND_TEST_ALL_PREFIXES(
      CreditCardSaveManagerTest,
      UploadCreditCard_WalletSyncTransportEnabled_ShouldNotRequestExpirationDate);
  FRIEND_TEST_ALL_PREFIXES(
      CreditCardSaveManagerTest,
      UploadCreditCard_WalletSyncTransportNotEnabled_ShouldRequestExpirationDate);
};

}  // namespace autofill

#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CREDIT_CARD_SAVE_MANAGER_H_


text:
import { Polymer } from '/resources/polymer/@polymer/polymer/lib/legacy/polymer-fn.js';
import { html } from '/resources/polymer/@polymer/polymer/lib/utils/html-tag.js';
import { TgReflector } from '/app/tg-reflector.js';

Polymer({
    _template: html``,

    is: 'tg-criterion-example-supplements',

    properties: {
        bindingEntity: {
            type: Object,
            notify: true
        },

        validationCallback: {
            type: Object,
            notify: true
        },

        maxTextAreaLength: {
            type: Number,
            notify: true
        },

        processResponse: {
            type: Function,
            notify: true
        },

        processError: {
            type: Function,
            notify: true
        },

        orNull: {
            type: Boolean,
            notify: true,
            observer: '_orNullChanged'
        },

        not: {
            type: Boolean,
            notify: true,
            observer: '_notChanged'
        },

        orGroup: {
            type: Number,
            notify: true,
            observer: '_orGroupChanged'
        },

        exclusive: {
            type: Boolean,
            notify: true,
            observer: '_exclusiveChanged'
        },

        exclusive2: {
            type: Boolean,
            notify: true,
            observer: '_exclusive2Changed'
        },

        datePrefix: {
            type: String,
            notify: true,
            observer: '_datePrefixChanged'
        },

        dateMnemonic: {
            type: String,
            notify: true,
            observer: '_dateMnemonicChanged'
        },

        andBefore: {
            type: Object,
            notify: true,
            observer: '_andBeforeChanged'
        }
    },

    created: function () {
        this._reflector = new TgReflector();
    },

    ready: function () {
        this.bindingEntity = this.createBindingEntity();

        this.validationCallback = function () {
            console.log("	validationCallback2");
        };

        this.maxTextAreaLength = 30;

        this.processResponse = function (event) {
            console.log("RESPONSE =", event, event.detail.response); // event.detail is 'iron-request' (which has 'response' inside)
        };
        this.processError = function (event) {
            console.log("ERROR =", event, event.detail.error); // event.detail is { error: 'error', request: 'iron-request' }
        };

        this.orNull = true;
        this.not = false;
        this.orGroup = 1;

        this.exclusive = true;
        this.exclusive2 = false;

        this.datePrefix = 'PREV';
        this.dateMnemonic = 'DAY';
        this.andBefore = true;
    },

    createBindingEntity: function () {
        const bindingView = this._reflector.newEntity('ua.com.fielden.platform.sample.domain.TgPersistentEntityWithProperties');
        bindingView["id"] = 333;
        bindingView["version"] = 0;

        bindingView["@@touchedProps"] = {
            names: [],
            values: [],
            counts: []
        };

        bindingView["@@origin"] = this._reflector.newEntity('ua.com.fielden.platform.sample.domain.TgPersistentEntityWithProperties');
        bindingView["@@origin"]["id"] = 333;
        bindingView["@@origin"]["version"] = 0;

        // integer
        bindingView["@@origin"]['integerProp'] = 23;
        bindingView['@integerProp_editable'] = true;

        /*bindingView.prop('integerProp');
        bindingView.type().prop('integerProp');*/

        // string
        bindingView["@@origin"]['stringProp'] = 'OK';
        bindingView['@stringProp_editable'] = true;

        // date
        bindingView["@@origin"]['dateProp'] = 2000000000;
        bindingView['@dateProp_editable'] = true;

        console.log("this.bindingEntity", bindingView);
        return bindingView;
    },

    _orNullChanged: function (newValue, oldValue) {
        console.log("_orNullChanged:", newValue, oldValue);
    },

    _notChanged: function (newValue, oldValue) {
        console.log("_notChanged:", newValue, oldValue);
    },

    _orGroupChanged: function (newValue, oldValue) {
        console.log("_orGroupChanged:", newValue, oldValue);
    },

    _exclusiveChanged: function (newValue, oldValue) {
        console.log("_exclusiveChanged:", newValue, oldValue);
    },

    _exclusive2Changed: function (newValue, oldValue) {
        console.log("_exclusive2Changed:", newValue, oldValue);
    },

    _datePrefixChanged: function (newValue, oldValue) {
        console.log("_datePrefixChanged:", newValue, oldValue);
    },

    _dateMnemonicChanged: function (newValue, oldValue) {
        console.log("_dateMnemonicChanged:", newValue, oldValue);
    },

    _andBeforeChanged: function (newValue, oldValue) {
        console.log("_andBeforeChanged:", newValue, oldValue);
    }
});

redpajama_set_name: RedPajamaGithub


text:
package com.lesofn.appengine.frame.spring;

import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Configuration;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

@Configuration
public class H2ConsoleConfig implements ServletContextInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        ServletRegistration.Dynamic h2ConsoleServlet = servletContext.addServlet("H2Console", new org.h2.server.web.WebServlet());
        h2ConsoleServlet.addMapping("/h2/*");
        h2ConsoleServlet.setInitParameter("-dev", "src/main/resources");
        h2ConsoleServlet.setLoadOnStartup(1);
    }
}


text:
package vestigo

import "net/http"

// methods - a list of methods that are allowed
var methods = []string{
	"CONNECT",
	"DELETE",
	"GET",
	"HEAD",
	"OPTIONS",
	"PATCH",
	"POST",
	"PUT",
	"TRACE",
}

// AllowTrace - Globally allow the TRACE method handling within vestigo url router.  This
// generally not a good idea to have true in production settings, but excellent for testing.
var AllowTrace = false

// Param - Get a url parameter by name
func Param(r *http.Request, name string) string {
	return r.FormValue(":" + name)
}

// ParamNames - Get a url parameter name list
func ParamNames(r *http.Request) []string {
	r.ParseForm()
	names := []string{}
	for k := range r.Form {
		names = append(names, k)
	}
	return names
}

//validMethod - validate that the http method is valid.
func validMethod(method string) bool {
	var ok = false
	for _, v := range methods {
		if v == method {
			ok = true
			break
		}
	}
	return ok
}

// registerVar - Put the URL Parameter into the request's RawQuery, very PAT like.
func registerVar(r *http.Request, fmtpname string, pvalue string) {
	if r.URL.RawQuery != "" {
		r.URL.RawQuery += "&" + fmtpname + pvalue
	} else {
		r.URL.RawQuery += fmtpname + pvalue
	}
}


text:
package uk.co.badgersinfoil.metaas.impl;

import org.antlr.runtime.tree.Tree;
import uk.co.badgersinfoil.metaas.dom.Expression;
import uk.co.badgersinfoil.metaas.dom.ASExpressionStatement;
import uk.co.badgersinfoil.metaas.impl.antlr.LinkedListTree;

import java.util.ArrayList;
import java.util.List;

public class ASTASExpressionStatement extends ASTScriptElement implements ASExpressionStatement {

	public ASTASExpressionStatement(LinkedListTree ast) {
		super(ast);
	}

    public List<Expression> getSubExpressions() {
        List<Expression> expressions = new ArrayList<Expression>();
        LinkedListTree ast = getAST();
        for (int i = 0; i < ast.getChildCount(); i++) {
            Tree child = ast.getChild(i);
            if (child instanceof LinkedListTree) {
                expressions.add(ExpressionBuilder.build((LinkedListTree) child));
            }
        }
        return expressions;
    }

    public Expression getExpression() {
		return ExpressionBuilder.build(ast.getFirstChild());
	}

	public String getExpressionString() {
		return ASTUtils.stringifyNode(ast.getFirstChild());
	}

	public void setExpression(String expr) {
		ast.setChildWithTokens(0, AS3FragmentParser.parseExprList(expr));
	}

    public List<Comment> getCommentsAfter() {
        return CommentUtils.getCommentAfter(this.getAST());
    }

    public int getSpacerSize() {
        return SpacerUtil.calculateSpacerSize(ast);
    }
}


text:
package com.muhardin.endy.belajar.ci.controller;

import com.muhardin.endy.belajar.ci.service.file.FileService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;

@RestController
@RequestMapping("/api")
public class FileController {

    private static final Logger LOGGER = LoggerFactory.getLogger(FileController.class);

    @Autowired private FileService fileService;

    @PostMapping("/file")
    public ResponseEntity uploadFile(@RequestParam("uploadfile") MultipartFile upload){
        Map<String, String> hasil = new TreeMap<>();
        try {
            fileService.simpan(upload.getOriginalFilename(), upload.getInputStream());
            hasil.put("success", "File tersimpan di "+ upload.getOriginalFilename());
            return ResponseEntity.ok(hasil);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage());
            hasil.put("err", e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(hasil);
        }
    }

    @GetMapping("/file")
    public List<Map<String, Object>> daftarFile(){
        return fileService.daftarFile();
    }

    @GetMapping("/file/{nama:.+}")
    public ResponseEntity<Object> getFile(@PathVariable String nama){
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="+nama);
            return ResponseEntity.ok()
                    .headers(headers)
                    .body(new InputStreamResource(fileService.ambil(nama)));
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(e.getMessage());
        }

    }

    @DeleteMapping("/file/{nama:.+}")
    public void delete(@PathVariable String nama){
        fileService.hapus(nama);
    }
}


text:
package com.davidjohnburrowes.formats.jpeg.test;

import com.davidjohnburrowes.format.encode.Hex2Bin;
import com.davidjohnburrowes.format.jpeg.data.DataItem;
import com.davidjohnburrowes.format.jpeg.support.DataMode;
import com.davidjohnburrowes.format.jpeg.support.FrameMode;
import com.davidjohnburrowes.util.Size;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.StringReader;

public class TestUtils {
	public static final int SKIP_CASE = Integer.MAX_VALUE;

	/**
	 * An enumeration of errors used by the property test routine, below.
	 */
	public enum PropResult {
		SUCCESS,
		INRANGE_ERROR1,
		INRANGE_ERROR2,
		INRANGE_ERROR3,
		INRANGE_ERROR4,
		INRANGE_ERROR5,
		CANT_INVOKE_SETTER_OR_GETTER,
		BELOWMIN_ERROR,
		ABOVEMAX_ERROR,
		ABOVELAXMAX_ERROR,
		SWITCH_FROM_MAX_TO_STRICT_ERROR,
		SWITCH_FROM_MIN_TO_STRICT_ERROR,
		GET_ERROR,
		ERROR
	}

	/**
	 * Given a string containing hexadecimal digits, produce a byte array
	 * containing the bytes specified in the string.
	 */
	public byte[] makeByteArray(String rawInput) throws IOException {
		StringReader inputReader = new StringReader(rawInput);
		byte[] rawInputBytes = new byte[rawInput.length()];
		int aChar = inputReader.read();
		int index = 0;
		while (aChar != -1) {
			rawInputBytes[index] = (byte) aChar;
			aChar = inputReader.read();
			index++;
		}

		Hex2Bin encoder = new Hex2Bin();
		InputStream inputStream = new ByteArrayInputStream(rawInputBytes);

		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		encoder.convert(inputStream, outputStream);

		return outputStream.toByteArray();
	}

	/**
	 * Given a string of hex digits, create an InputStream that accesses the
	 * binary data specified by those digits.
	 */
	public InputStream makeInputStream(String rawInput) throws IOException {
		return new ByteArrayInputStream(makeByteArray(rawInput));
	}

	/**
	 * Given a string of hex digits, create a file on disk and populate it with
	 * bytes specified by those hex digits.
	 */
	public RandomAccessFile makeRandomAccessFile(String data) throws IOException {
		File temp = File.createTempFile("prefix", "suffix");
		FileOutputStream output = new FileOutputStream(temp);

		StringReader inputReader = new StringReader(data);
		byte[] rawInputBytes = new byte[data.length()];
		int aChar = inputReader.read();
		int index = 0;
		while (aChar != -1) {
			rawInputBytes[index] = (byte) aChar;
			aChar = inputReader.read();
			index++;
		}

		Hex2Bin encoder = new Hex2Bin();
		InputStream inputStream = new ByteArrayInputStream(rawInputBytes);

		encoder.convert(inputStream, output);

		output.flush();
		output.close();

		return new RandomAccessFile(temp, "r");
	}

	/**
	 * Overloaded test routine.  Tests the item using a simple property accessor.
	 */
	public PropResult testProp(DataItem item, String propName,
			  Size dataSize,
			  int min, int max) {
		return testProp(item,propName, dataSize, min, max, min, max, min, max, min, max);
	}

	/**
	 * Overloaded routine. Tests the item with a simple property accessor.
	 */
	public PropResult testProp(DataItem item, String propName,
		  Size dataSize,
		  int baselineMin, int baselineMax,
		  int extendedMin, int extendedMax,
		  int progressiveMin, int progressiveMax,
		  int losslessMin, int losslessMax) {
		SimplePropertyAccessor simple = new SimplePropertyAccessor(propName, item, this);
		return this.testProp(simple, item, dataSize, baselineMin, baselineMax, extendedMin, extendedMax,
			  progressiveMin, progressiveMax,
			  losslessMin, losslessMax);
	}

	/**
	 * Tests one property of the specified DataItem in a wide variety of
	 * scenarios.  This runs the specified property through a bunch of tests for
	 * each of the possible categories of FrameMode values.  That is, it will
	 * test the property in a baseline mode, in an extended mode, etc.
	 *
	 * @param accessor An object which will provide read/write access to the
	 *						property to be tested
	 * @param item The data item that contains the property to access
	 * @param dataSize The size of the property's data on disk
	 * @param baselineMin The minimum value in a baseline FrameMode
	 * @param baselineMax The maximum value in a baseline FrameMode
	 * @param extendedMin The minimum value in an extended FrameMode
	 * @param extendedMax The maximum value in an extended FrameMode
	 * @param progressiveMin The minimum value in a progressive FrameMode
	 * @param progressiveMax The maximum value in a progressive FrameMode
	 * @param losslessMin The minimum value in a lossless FrameMode
	 * @param losslessMax The maximum value in a losaless FrameMode
	 * @return One of the PropResult values, above.
	 */
	public PropResult testProp(Accessor accessor, DataItem item,
			  Size dataSize,
			  int baselineMin, int baselineMax,
			  int extendedMin, int extendedMax,
			  int progressiveMin, int progressiveMax,
			  int losslessMin, int losslessMax) {
		PropResult result;

		result = testPropWithOneFrame(accessor, item, dataSize, null, 0, dataSize.getMax());
		if (result != PropResult.SUCCESS) {
			return result;
		}

		if (baselineMin != SKIP_CASE) {
			result = testPropWithOneFrame(accessor, item, dataSize,
					  FrameMode.HUFF_BASELINE_SEQUENTIAL_DCT, baselineMin, baselineMax);
			if (result != PropResult.SUCCESS) {
				return result;
			}
		}

		if (extendedMin != SKIP_CASE) {
			result = testPropWithOneFrame(accessor, item, dataSize,
					  FrameMode.HUFF_EXTENDED_SEQUENTIAL_DCT, extendedMin, extendedMax);

			if (result != PropResult.SUCCESS) {
				return result;
			}
		}

		if (progressiveMin != SKIP_CASE) {
			result = testPropWithOneFrame(accessor, item, dataSize,
					  FrameMode.HUFF_PROGRESSIVE_DCT, progressiveMin, progressiveMax);

			if (result != PropResult.SUCCESS) {
				return result;
			}
		}

		if (losslessMin != SKIP_CASE) {
			result = testPropWithOneFrame(accessor, item, dataSize,
					  FrameMode.HUFF_LOSSLESS, losslessMin, losslessMax);
			if (result != PropResult.SUCCESS) {
				return result;
			}
		}

		return result;
	}

	/**
	 * Test the data bounds of a particular property.  Each property is assumed
	 * to have a range of values it should adhere to.  So, this tests below that
	 * range, above the range, at the min and max of the range, and a value
	 * between the min and max.  The result of this is returned as a constant
	 * value.  This also tests that in LAX mode that the full range of the
	 * disk size is accepted.
	 *
	 * Note: When this fails, it is still relatively opaque and requires
	 * debugging to figure out what is going on.  I'm not proud of this design,
	 * but it has been sufficient for my own development.
	 *
	 * @param accessor An object that will access the property to be tested
	 * @param item The DataItem being tested
	 * @param dataSize The size of the property on disk
	 * @param mode The FrameMode to do this testing in
	 * @param min The minimum value allowed in this FrameMode
	 * @param max The maximum value allowed in this FrameMode
	 * @return An enum value approximately pinpointing the failure, if any.
	 */
	public PropResult testPropWithOneFrame(Accessor accessor, DataItem item,
			  Size dataSize, FrameMode mode, int min, int max) {
		int belowMin = min - 1;
		int aboveMax = max + 1;
		int middle = min + ((max - min) / 2);

		item.setDataMode(DataMode.LAX);
		item.setFrameMode(mode);
		Number num;
		try {
			accessor.setValue(min);
			item.setDataMode(DataMode.STRICT);
			accessor.setValue(min);
			num = (Number) accessor.getValue();
			if (num.intValue() != min) {
				return PropResult.GET_ERROR;
			}
		} catch (Throwable e) {
			return PropResult.INRANGE_ERROR1;
		}

		try {
			accessor.setValue(middle);
			num = (Number) accessor.getValue();
			if (num.intValue() != middle) {
				return PropResult.GET_ERROR;
			}
		} catch (Throwable e) {
			return PropResult.INRANGE_ERROR2;
		}

		try {
			accessor.setValue(max);
			num = (Number) accessor.getValue();
			if (num.intValue() != max) {
				return PropResult.GET_ERROR;
			}
		} catch (Throwable e) {
			return PropResult.INRANGE_ERROR3;
		}

		try {
			item.setDataMode(DataMode.LAX);
			accessor.setValue(0);
			num = (Number) accessor.getValue();
			if (num.intValue() != 0) {
				return PropResult.GET_ERROR;
			}
		} catch (Throwable e) {
			return PropResult.INRANGE_ERROR4;
		}

		try {
			accessor.setValue(dataSize.getMax());
			num = (Number) accessor.getValue();
			if (num.intValue() != dataSize.getMax()) {
				return PropResult.GET_ERROR;
			}

			accessor.setValue(min);
		} catch (Throwable e) {
			return PropResult.INRANGE_ERROR5;
		}

		try {
			item.setDataMode(DataMode.STRICT);
			accessor.setValue(belowMin);
			return PropResult.BELOWMIN_ERROR;
		} catch (Throwable e) {
		}

		try {
			item.setDataMode(DataMode.STRICT);
			accessor.setValue(aboveMax);
			return PropResult.ABOVEMAX_ERROR;
		} catch (Throwable e) {
		}

		try {
			item.setDataMode(DataMode.LAX);
			accessor.setValue(dataSize.getMax() + 1);
			return PropResult.ABOVELAXMAX_ERROR;
		} catch (Throwable e) {
		}

		if (max < dataSize.getMax()) {
			try {
				item.setDataMode(DataMode.LAX);
				accessor.setValue(dataSize.getMax());
				item.setDataMode(DataMode.STRICT);
				return PropResult.SWITCH_FROM_MAX_TO_STRICT_ERROR;
			} catch (Throwable e) {
			}
		}

		if (min > 0) {
			try {
				item.setDataMode(DataMode.LAX);
				accessor.setValue(0);
				item.setDataMode(DataMode.STRICT);
				return PropResult.SWITCH_FROM_MIN_TO_STRICT_ERROR;
			} catch (Throwable e) {
			}
		}

		return PropResult.SUCCESS;
	}
}


text:
<title>SetDragCallback</title>

SetDragCallback()

Syntax

SetDragCallback(@DragCallback())

Description

A callback function to be called during a Drag & Drop operation initiated from this application.
The callback allows to modify the Drag & Drop process provided by PureBasic, for example by providing
a custom cursor through the API of the Operating system.

Parameters

@DragCallback()

The address of a function to call during a drag operation.
The form and purpose of the callback is dependant on the OS.
It must take the following form:

Windows:

  Procedure DragCallback(Action)

    ProcedureReturn #True
  EndProcedure

The callback is called during the Drag & Drop operation. Action specifies the action that would be taken
if the user released the mouse at this point. It can be one of these values:

  #PB_Drag_None: The data will not be accepted if dropped here
  #PB_Drag_Copy: The data will be copied
  #PB_Drag_Move: The data will be moved
  #PB_Drag_Link: The data will be linked

The callback can provide a custom cursor or drag image. If it does so, it should return #False.
Returning #True will cause the default cursor to be used.

Linux:

  Procedure DragCallback(*Context.GdkDragContext, isStart)

  EndProcedure

The callback is only called at the start and the end of a Drag & Drop operation. The '*Context' parameter
specifies the gdk drag context of this operation, 'isStart' specifies whether this is the start or the
end of the operation. The return-value of the callback is ignored.

Gtk functions like gtk_drag_set_icon_pixbuf_() can be used in the callback to set a different drag image
for the operation.

MacOSX:

  Procedure DragCallback(DragReference, isStart)

  EndProcedure

The callback is only called at the start and the end of a Drag & Drop operation. The 'DragReference' parameter
specifies the Carbon drag context of this operation in form of a 'DragRef' value, 'isStart' specifies whether
this is the start or the end of the operation. The return-value of the callback is ignored.

All functions of the Carbon Drag Manager can be used to influence the drag operation before it starts
(adding more flavors/items for example) and to get more information about the operation after it completed.

Return value

None.

See Also

SetDropCallback()

Supported OS
All

<- EventDropY() - DragDrop Index - SetDropCallback() ->


text:
using System.Management.Automation;
using Microsoft.SharePoint.Client;
using Newtonsoft.Json;
using OfficeDevPnP.Core.Framework.Provisioning.Model;
using SharePointPnP.PowerShell.CmdletHelpAttributes;

namespace SharePointPnP.PowerShell.Commands.Branding
{
    [Cmdlet(VerbsCommon.Get, "PnPTheme")]
    [CmdletHelp("Returns the current theme/composed look of the current web.",
        Category = CmdletHelpCategory.Branding,
        OutputType = typeof(OfficeDevPnP.Core.Entities.ThemeEntity))]
    [CmdletExample(
        Code = @"PS:> Get-PnPTheme",
        Remarks = "Returns the current composed look of the current web.",
        SortOrder = 1)]
    [CmdletExample(
        Code = @"PS:> Get-PnPTheme -DetectCurrentComposedLook",
        Remarks = "Returns the current composed look of the current web, and will try to detect the currently applied composed look based upon the actual site. Without this switch the cmdlet will first check for the presence of a property bag variable called _PnP_ProvisioningTemplateComposedLookInfo that contains composed look information when applied through the provisioning engine or the Set-PnPTheme cmdlet.",
        SortOrder = 2)]
    public class GetTheme : PnPWebCmdlet
    {
        [Parameter(Mandatory = false, HelpMessage = "Specify this switch to not use the PnP Provisioning engine based composed look information but try to detect the current composed look as is.")]
        public SwitchParameter DetectCurrentComposedLook;

        protected override void ExecuteCmdlet()
        {
            if (SelectedWeb.PropertyBagContainsKey("_PnP_ProvisioningTemplateComposedLookInfo") && !DetectCurrentComposedLook)
            {
                try
                {
                    WriteWarning("The information presented here is based upon the fact that the theme has been set using either the PnP Provisioning Engine or using the Set-PnPTheme cmdlet. This information is retrieved from a propertybag value and may differ from the actual site.");
                    var composedLook = JsonConvert.DeserializeObject<ComposedLook>(SelectedWeb.GetPropertyBagValueString("_PnP_ProvisioningTemplateComposedLookInfo", ""));
                    WriteObject(composedLook);
                }
                catch
                {
                    var themeEntity = SelectedWeb.GetCurrentComposedLook();
                    WriteObject(themeEntity);
                }

            }
            else
            {
                var themeEntity = SelectedWeb.GetCurrentComposedLook();
                WriteObject(themeEntity);
            }
        }
    }
}


text:
/* Mednafen - Multi-system Emulator
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
  Games to test after changing code affecting CD reading and buffering:
		Bedlam
		Rise 2

*/

// TODO: async command counter and async command phase?
/*

 TODO:
	Implement missing commands.

	SPU CD-DA and CD-XA streaming semantics.
*/

/*
 After eject(doesn't appear to occur when drive is in STOP state):
	* Does not appear to occur in STOP state.
	* Does not appear to occur in PAUSE state.
	* DOES appear to occur in STANDBY state. (TODO: retest)

% Result 0: 16
% Result 1: 08
% IRQ Result: e5
% 19 e0

 Command abortion tests(NOP tested):
	Does not appear to occur when in STOP or PAUSE states(STOP or PAUSE command just executed).

	DOES occur after a ReadTOC completes, if ReadTOC is not followed by a STOP or PAUSE.  Odd.
*/

#include "psx.h"
#include "cdc.h"
#include "spu.h"
#include "endian.h"

using namespace CDUtility;

namespace MDFN_IEN_PSX
{

PS_CDC::PS_CDC() : DMABuffer(4096)
{
 IsPSXDisc = false;
 Cur_disc = NULL;
 Open_disc = NULL;
 EnableLEC = false;

 DriveStatus = DS_STOPPED;
 PendingCommandPhase = 0;
}

PS_CDC::~PS_CDC()
{

}

void PS_CDC::DMForceStop(void)
{
 PSRCounter = 0;

 if((DriveStatus != DS_PAUSED && DriveStatus != DS_STOPPED) || PendingCommandPhase >= 2)
 {
  PendingCommand = 0x00;
  PendingCommandCounter = 0;
  PendingCommandPhase = 0;
 }

 HeaderBufValid = false;
 DriveStatus = DS_STOPPED;
 ClearAIP();
 SectorPipe_Pos = SectorPipe_In = 0;
 SectorsRead = 0;
}

void PS_CDC::OpenTray()
{
	//track the tray state
	TrayOpen = true;

	//effectively a NOP at t=0
	DMForceStop();

	//zero 31-jan-2015 - psxtech says that what this is used for is actually a 'was open' flag which gets cleared after the status gets polled.
	//so lets set it here, and rename it later if we're sure.
	Status_TrayOpenBit = true;

	//since Cur_disc tracks what the CDC sees mounted, it can't see anything now that it's open, so exchange these states
	Open_disc = Cur_disc;
	Cur_disc = NULL;
}

void PS_CDC::CloseTray(bool poke)
{
	//track the tray state
	TrayOpen = false;

	//switch pending (open) disc to current disc
	Cur_disc = Open_disc;
	Open_disc = NULL;

	//cache Open_DiscID and clear it out
	char disc_id[5];
	strncpy(disc_id,(char*)Open_DiscID,4);
	memset(Open_DiscID,0,sizeof(Open_DiscID));

	//prepare analysis if disc: leave in empty state
	IsPSXDisc = false;
	memset(DiscID, 0, sizeof(DiscID));

	//stuff to always happen, even when poking:
	if(Cur_disc)
	{
		Cur_disc->ReadTOC((ShockTOC*)&toc,(ShockTOCTrack*)toc.tracks);

		//complete analysis. if we had a disc ID, then it's a PSX disc; copy it in
		if(disc_id[0])
		{
			strncpy((char *)DiscID, disc_id, 4);
			IsPSXDisc = true;
		}
	}

	//stuff to happen when not poking (reset CDC state)
	if(Cur_disc && !poke)
	{
		HeaderBufValid = false;
		DiscStartupDelay = (int64)1000 * 33868800 / 1000;
	}

}

void PS_CDC::SetDisc(ShockDiscRef *disc, const char *disc_id, bool poke)
{
	Open_disc = disc;
	strncpy((char*)Open_DiscID,disc_id,4);

	if(poke)
		CloseTray(true);
}

int32 PS_CDC::CalcNextEvent(void)
{
 int32 next_event = SPUCounter;

 if(PSRCounter > 0 && next_event > PSRCounter)
  next_event = PSRCounter;

 if(PendingCommandCounter > 0 && next_event > PendingCommandCounter)
  next_event = PendingCommandCounter;

 if(!(IRQBuffer & 0xF))
 {
  if(CDCReadyReceiveCounter > 0 && next_event > CDCReadyReceiveCounter)
   next_event = CDCReadyReceiveCounter;
 }

 if(DiscStartupDelay > 0 && next_event > DiscStartupDelay)
  next_event = DiscStartupDelay;

 //fprintf(stderr, "%d %d %d %d --- %d\n", PSRCounter, PendingCommandCounter, CDCReadyReceiveCounter, DiscStartupDelay, next_event);

 return(next_event);
}

void PS_CDC::SoftReset(void)
{
 ClearAudioBuffers();

 // Not sure about initial volume state
 Pending_DecodeVolume[0][0] = 0x80;
 Pending_DecodeVolume[0][1] = 0x00;
 Pending_DecodeVolume[1][0] = 0x00;
 Pending_DecodeVolume[1][1] = 0x80;
 memcpy(DecodeVolume, Pending_DecodeVolume, sizeof(DecodeVolume));

 RegSelector = 0;
 memset(ArgsBuf, 0, sizeof(ArgsBuf));
 ArgsWP = ArgsRP = 0;

 memset(ResultsBuffer, 0, sizeof(ResultsBuffer));
 ResultsWP = 0;
 ResultsRP = 0;
 ResultsIn = 0;

 CDCReadyReceiveCounter = 0;

 IRQBuffer = 0;
 IRQOutTestMask = 0;
 RecalcIRQ();

 DMABuffer.Flush();
 SB_In = 0;
 SectorPipe_Pos = SectorPipe_In = 0;
 SectorsRead = 0;

 //memset(SubQBuf, 0, sizeof(SubQBuf));
 memset(SubQBuf_Safe, 0, sizeof(SubQBuf_Safe));
 SubQChecksumOK = false;

 memset(HeaderBuf, 0, sizeof(HeaderBuf));

 FilterFile = 0;
 FilterChan = 0;

 PendingCommand = 0;
 PendingCommandPhase = 0;
 PendingCommandCounter = 0;

 Mode = 0x20;

 HeaderBufValid = false;
 DriveStatus = DS_STOPPED;
 ClearAIP();
 StatusAfterSeek = DS_STOPPED;
 SeekRetryCounter = 0;

 Forward = false;
 Backward = false;
 Muted = false;

 PlayTrackMatch = 0;

 PSRCounter = 0;

 CurSector = 0;

 ClearAIP();

 SeekTarget = 0;

 CommandLoc = 0;
 CommandLoc_Dirty = true;

 Status_TrayOpenBit = true;
 TrayOpen = false;
}

void PS_CDC::Power(void)
{
 SPU->Power();

 SoftReset();

 DiscStartupDelay = 0;

 SPUCounter = SPU->UpdateFromCDC(0);
 lastts = 0;
}

SYNCFUNC(PS_CDC)
{
	NSS(TrayOpen);

	NSS(Status_TrayOpenBit);
  NSS(DiscStartupDelay);

  NSS(AudioBuffer);

  NSS(Pending_DecodeVolume);
  NSS(DecodeVolume);

  NSS(ADPCM_ResampBuf);
  NSS(ADPCM_ResampCurPhase);
  NSS(ADPCM_ResampCurPos);

  NSS(RegSelector);
  NSS(ArgsBuf);
  NSS(ArgsWP);
  NSS(ArgsRP);

  NSS(ArgsReceiveLatch);
  NSS(ArgsReceiveBuf);
  NSS(ArgsReceiveIn);

  NSS(ResultsBuffer);
  NSS(ResultsIn);
  NSS(ResultsWP);
  NSS(ResultsRP);

	SSS(DMABuffer);

  NSS(SB);
  NSS(SB_In);

  NSS(SectorPipe);
  NSS(SectorPipe_Pos);
  NSS(SectorPipe_In);

  //NSS(SubQBuf);
  NSS(SubQBuf_Safe);

  NSS(SubQChecksumOK);

  NSS(HeaderBufValid);
  NSS(HeaderBuf);

  NSS(IRQBuffer);
  NSS(IRQOutTestMask);
  NSS(CDCReadyReceiveCounter);

  NSS(FilterFile);
  NSS(FilterChan);

  NSS(PendingCommand);
  NSS(PendingCommandPhase);
  NSS(PendingCommandCounter);

  NSS(SPUCounter);

  NSS(Mode);
  NSS(DriveStatus);
  NSS(StatusAfterSeek);
  NSS(Forward);
  NSS(Backward);
  NSS(Muted);

  NSS(PlayTrackMatch);

  NSS(PSRCounter);

  NSS(CurSector);
	NSS(SectorsRead);

  NSS(AsyncIRQPending);
  NSS(AsyncResultsPending);
  NSS(AsyncResultsPendingCount);

  NSS(SeekTarget);
	NSS(SeekRetryCounter);

 // FIXME: Save TOC stuff?
#if 0
 CDUtility::TOC toc;
 bool IsPSXDisc;
 uint8 DiscID[4];
#endif

  NSS(CommandLoc);
  NSS(CommandLoc_Dirty);
  NSS(xa_previous);

  NSS(xa_cur_set);
  NSS(xa_cur_file);
  NSS(xa_cur_chan);

  NSS(ReportLastF);

	//(%= crap about file format recovery in case SectorPipe_Pos changes)
}

void PS_CDC::ResetTS(void)
{
 lastts = 0;
}

void PS_CDC::RecalcIRQ(void)
{
 IRQ_Assert(IRQ_CD, (bool)(IRQBuffer & (IRQOutTestMask & 0x1F)));
}
//static int32 doom_ts;
void PS_CDC::WriteIRQ(uint8 V)
{
 assert(CDCReadyReceiveCounter <= 0);
 assert(!(IRQBuffer & 0xF));

 //PSX_WARNING("[CDC] ***IRQTHINGY: 0x%02x -- %u", V, doom_ts);

 CDCReadyReceiveCounter = 2000; //1024;

 IRQBuffer = (IRQBuffer & 0x10) | V;
 RecalcIRQ();
}

void PS_CDC::BeginResults(void)
{
 //if(ResultsIn)
 // {
 // printf("Cleared %d results. IRQBuffer=0x%02x\n", ResultsIn, IRQBuffer);
 //}

 ResultsIn = 0;
 ResultsWP = 0;
 ResultsRP = 0;

 memset(ResultsBuffer, 0x00, sizeof(ResultsBuffer));
}

void PS_CDC::WriteResult(uint8 V)
{
 ResultsBuffer[ResultsWP] = V;
 ResultsWP = (ResultsWP + 1) & 0xF;
 ResultsIn = (ResultsIn + 1) & 0x1F;

 if(!ResultsIn)
  PSX_WARNING("[CDC] Results buffer overflow!");
}

uint8 PS_CDC::ReadResult(void)
{
 uint8 ret = ResultsBuffer[ResultsRP];

 if(!ResultsIn)
  PSX_WARNING("[CDC] Results buffer underflow!");

 ResultsRP = (ResultsRP + 1) & 0xF;
 ResultsIn = (ResultsIn - 1) & 0x1F;

 return ret;
}

uint8 PS_CDC::MakeStatus(bool cmd_error)
{
 uint8 ret = 0;

 // Are these bit positions right?

 if(DriveStatus == DS_PLAYING)
  ret |= 0x80;

 // Probably will want to be careful with this HeaderBufValid versus seek/read bit business in the future as it is a bit fragile;
 // "Gran Turismo 1"'s music(or erroneous lack of) is a good test case.
 if(DriveStatus == DS_READING)
 {
  if(!HeaderBufValid)
   ret |= 0x40;
  else
   ret |= 0x20;
 }
 else if(DriveStatus == DS_SEEKING || DriveStatus == DS_SEEKING_LOGICAL)
  ret |= 0x40;

 if(Status_TrayOpenBit)
  ret |= 0x10;

 if(DriveStatus != DS_STOPPED)
  ret |= 0x02;

 if(cmd_error)
  ret |= 0x01;

 //DiscChanged = false;	// FIXME: Only do it on NOP command execution? //comment added with 0.9.38.5 - code removed by octoshock at some unknown point
 //maybe a good point for looking at disc swap related bugs

 return(ret);
}

bool PS_CDC::DecodeSubQ(uint8 *subpw)
{
 uint8 tmp_q[0xC];

 memset(tmp_q, 0, 0xC);

 for(int i = 0; i < 96; i++)
  tmp_q[i >> 3] |= ((subpw[i] & 0x40) >> 6) << (7 - (i & 7));

 if((tmp_q[0] & 0xF) == 1)
 {
  SubQChecksumOK = subq_check_checksum(tmp_q);

  if(SubQChecksumOK)
  {
   memcpy(SubQBuf_Safe, tmp_q, 0xC);
   return(true);
  }
 }

 return(false);
}

static const int16 CDADPCMImpulse[7][25] =
{
 {     0,    -5,    17,   -35,    70,   -23,   -68,   347,  -839,  2062, -4681, 15367, 21472, -5882,  2810, -1352,   635,  -235,    26,    43,   -35,    16,    -8,     2,     0,  }, /* 0 */
 {     0,    -2,    10,   -34,    65,   -84,    52,     9,  -266,  1024, -2680,  9036, 26516, -6016,  3021, -1571,   848,  -365,   107,    10,   -16,    17,    -8,     3,    -1,  }, /* 1 */
 {    -2,     0,     3,   -19,    60,   -75,   162,  -227,   306,   -67,  -615,  3229, 29883, -4532,  2488, -1471,   882,  -424,   166,   -27,     5,     6,    -8,     3,    -1,  }, /* 2 */
 {    -1,     3,    -2,    -5,    31,   -74,   179,  -402,   689,  -926,  1272, -1446, 31033, -1446,  1272,  -926,   689,  -402,   179,   -74,    31,    -5,    -2,     3,    -1,  }, /* 3 */
 {    -1,     3,    -8,     6,     5,   -27,   166,  -424,   882, -1471,  2488, -4532, 29883,  3229,  -615,   -67,   306,  -227,   162,   -75,    60,   -19,     3,     0,    -2,  }, /* 4 */
 {    -1,     3,    -8,    17,   -16,    10,   107,  -365,   848, -1571,  3021, -6016, 26516,  9036, -2680,  1024,  -266,     9,    52,   -84,    65,   -34,    10,    -2,     0,  }, /* 5 */
 {     0,     2,    -8,    16,   -35,    43,    26,  -235,   635, -1352,  2810, -5882, 21472, 15367, -4681,  2062,  -839,   347,   -68,   -23,    70,   -35,    17,    -5,     0,  }, /* 6 */
};

void PS_CDC::ReadAudioBuffer(int32 samples[2])
{
 samples[0] = AudioBuffer.Samples[0][AudioBuffer.ReadPos];
 samples[1] = AudioBuffer.Samples[1][AudioBuffer.ReadPos];

 AudioBuffer.ReadPos++;
}

INLINE void PS_CDC::ApplyVolume(int32 samples[2])
{
 //
 // Take care not to alter samples[] before we're done calculating the new output samples!
 //
 int32 left_out = ((samples[0] * DecodeVolume[0][0]) >> 7) + ((samples[1] * DecodeVolume[1][0]) >> 7);
 int32 right_out = ((samples[0] * DecodeVolume[0][1]) >> 7) + ((samples[1] * DecodeVolume[1][1]) >> 7);

 clamp(&left_out, -32768, 32767);
 clamp(&right_out, -32768, 32767);

 if(Muted)
 {
  left_out = 0;
  right_out = 0;
 }

 samples[0] = left_out;
 samples[1] = right_out;
}

//
// This function must always set samples[0] and samples[1], even if just to 0; range of samples[n] shall be restricted to -32768 through 32767.
//
void PS_CDC::GetCDAudio(int32 samples[2])
{
 const unsigned freq = (AudioBuffer.ReadPos < AudioBuffer.Size) ? AudioBuffer.Freq : 0;

 samples[0] = 0;
 samples[1] = 0;

 if(!freq)
  return;

 if(freq == 7 || freq == 14)
 {
  ReadAudioBuffer(samples);
  if(freq == 14)
   ReadAudioBuffer(samples);
 }
 else
 {
  int32 out_tmp[2] = { 0, 0 };

  for(unsigned i = 0; i < 2; i++)
  {
   const int16* imp = CDADPCMImpulse[ADPCM_ResampCurPhase];
   int16* wf = &ADPCM_ResampBuf[i][(ADPCM_ResampCurPos + 32 - 25) & 0x1F];

   for(unsigned s = 0; s < 25; s++)
   {
    out_tmp[i] += imp[s] * wf[s];
   }

   out_tmp[i] >>= 15;
   clamp(&out_tmp[i], -32768, 32767);
   samples[i] = out_tmp[i];
  }

  ADPCM_ResampCurPhase += freq;

  if(ADPCM_ResampCurPhase >= 7)
  {
   int32 raw[2] = { 0, 0 };

   ADPCM_ResampCurPhase -= 7;
   ReadAudioBuffer(raw);

   for(unsigned i = 0; i < 2; i++)
   {
    ADPCM_ResampBuf[i][ADPCM_ResampCurPos +  0] =
    ADPCM_ResampBuf[i][ADPCM_ResampCurPos + 32] = raw[i];
   }
   ADPCM_ResampCurPos = (ADPCM_ResampCurPos + 1) & 0x1F;
  }
 }

 //
 // Algorithmically, volume is applied after resampling for CD-XA ADPCM playback, per PS1 tests(though when "mute" is applied wasn't tested).
 //
 ApplyVolume(samples);
}

EW_PACKED(
struct XA_Subheader
{
 uint8 file;
 uint8 channel;
 uint8 submode;
 uint8 coding;

 uint8 file_dup;
 uint8 channel_dup;
 uint8 submode_dup;
 uint8 coding_dup;
});

EW_PACKED(
struct XA_SoundGroup
{
 uint8 params[16];
 uint8 samples[112];
});

#define XA_SUBMODE_EOF		0x80
#define XA_SUBMODE_REALTIME	0x40
#define XA_SUBMODE_FORM		0x20
#define XA_SUBMODE_TRIGGER	0x10
#define XA_SUBMODE_DATA		0x08
#define XA_SUBMODE_AUDIO	0x04
#define XA_SUBMODE_VIDEO	0x02
#define XA_SUBMODE_EOR		0x01

#define XA_CODING_EMPHASIS	0x40

//#define XA_CODING_BPS_MASK	0x30
//#define XA_CODING_BPS_4BIT	0x00
//#define XA_CODING_BPS_8BIT	0x10
//#define XA_CODING_SR_MASK	0x0C
//#define XA_CODING_SR_378	0x00
//#define XA_CODING_SR_

#define XA_CODING_8BIT		0x10
#define XA_CODING_189		0x04
#define XA_CODING_STEREO	0x01

// Special regression prevention test cases:
//	Um Jammer Lammy (start doing poorly)
//	Yarudora Series Vol.1 - Double Cast (non-FMV speech)

bool PS_CDC::XA_Test(const uint8 *sdata)
{
 const XA_Subheader *sh = (const XA_Subheader *)&sdata[12 + 4];

 if(!(Mode & MODE_STRSND))
  return false;

 if(!(sh->submode & XA_SUBMODE_AUDIO))
  return false;

 //printf("Test File: 0x%02x 0x%02x - Channel: 0x%02x 0x%02x - Submode: 0x%02x 0x%02x - Coding: 0x%02x 0x%02x - \n", sh->file, sh->file_dup, sh->channel, sh->channel_dup, sh->submode, sh->submode_dup, sh->coding, sh->coding_dup);

 if((Mode & MODE_SF) && (sh->file != FilterFile || sh->channel != FilterChan))
  return false;

 if(!xa_cur_set || (Mode & MODE_SF))
 {
  xa_cur_set = true;
  xa_cur_file = sh->file;
  xa_cur_chan = sh->channel;
 }
 else if(sh->file != xa_cur_file || sh->channel != xa_cur_chan)
  return false;

 if(sh->submode & XA_SUBMODE_EOF)
 {
  //puts("YAY");
  xa_cur_set = false;
  xa_cur_file = 0;
  xa_cur_chan = 0;
 }

 return true;
}

void PS_CDC::ClearAudioBuffers(void)
{
 memset(&AudioBuffer, 0, sizeof(AudioBuffer));
 memset(xa_previous, 0, sizeof(xa_previous));

 xa_cur_set = false;
 xa_cur_file = 0;
 xa_cur_chan = 0;

 memset(ADPCM_ResampBuf, 0, sizeof(ADPCM_ResampBuf));
 ADPCM_ResampCurPhase = 0;
 ADPCM_ResampCurPos = 0;
}

//
// output should be readable at -2 and -1
static void DecodeXAADPCM(const uint8 *input, int16 *output, const unsigned shift, const unsigned weight)
{
 // Weights copied over from SPU channel ADPCM playback code, may not be entirely the same for CD-XA ADPCM, we need to run tests.
 static const int32 Weights[16][2] =
 {
  // s-1    s-2
  {   0,    0 },
  {  60,    0 },
  { 115,  -52 },
  {  98,  -55 },
  { 122,  -60 },
 };

 for(int i = 0; i < 28; i++)
 {
  int32 sample;

  sample = (int16)(input[i] << 8);
  sample >>= shift;

  sample += ((output[i - 1] * Weights[weight][0]) >> 6) + ((output[i - 2] * Weights[weight][1]) >> 6);

  if(sample < -32768)
   sample = -32768;

  if(sample > 32767)
   sample = 32767;

  output[i] = sample;
 }
}

void PS_CDC::XA_ProcessSector(const uint8 *sdata, CD_Audio_Buffer *ab)
{
 const XA_Subheader *sh = (const XA_Subheader *)&sdata[12 + 4];
 const unsigned unit_index_shift = (sh->coding & XA_CODING_8BIT) ? 0 : 1;

 //printf("File: 0x%02x 0x%02x - Channel: 0x%02x 0x%02x - Submode: 0x%02x 0x%02x - Coding: 0x%02x 0x%02x - \n", sh->file, sh->file_dup, sh->channel, sh->channel_dup, sh->submode, sh->submode_dup, sh->coding, sh->coding_dup);
 ab->ReadPos = 0;
 ab->Size = 18 * (4 << unit_index_shift) * 28;

 if(sh->coding & XA_CODING_STEREO)
  ab->Size >>= 1;

 ab->Freq = (sh->coding & XA_CODING_189) ? 3 : 6;

 //fprintf(stderr, "Coding: %02x %02x\n", sh->coding, sh->coding_dup);

 for(unsigned group = 0; group < 18; group++)
 {
  const XA_SoundGroup *sg = (const XA_SoundGroup *)&sdata[12 + 4 + 8 + group * 128];

  for(unsigned unit = 0; unit < (4U << unit_index_shift); unit++)
  {
   const uint8 param = sg->params[(unit & 3) | ((unit & 4) << 1)];
   const uint8 param_copy = sg->params[4 | (unit & 3) | ((unit & 4) << 1)];
   uint8 ibuffer[28];
   int16 obuffer[2 + 28];

   if(param != param_copy)
   {
    PSX_WARNING("[CDC] CD-XA param != param_copy --- %d %02x %02x\n", unit, param, param_copy);
   }

   for(unsigned i = 0; i < 28; i++)
   {
    uint8 tmp = sg->samples[i * 4 + (unit >> unit_index_shift)];

    if(unit_index_shift)
    {
     tmp <<= (unit & 1) ? 0 : 4;
     tmp &= 0xf0;
    }

    ibuffer[i] = tmp;
   }

   const bool ocn = (bool)(unit & 1) && (sh->coding & XA_CODING_STEREO);

   obuffer[0] = xa_previous[ocn][0];
   obuffer[1] = xa_previous[ocn][1];

   DecodeXAADPCM(ibuffer, &obuffer[2], param & 0x0F, param >> 4);

   xa_previous[ocn][0] = obuffer[28];
   xa_previous[ocn][1] = obuffer[29];

   if(param != param_copy)
    memset(obuffer, 0, sizeof(obuffer));

   if(sh->coding & XA_CODING_STEREO)
   {
    for(unsigned s = 0; s < 28; s++)
    {
     ab->Samples[ocn][group * (2 << unit_index_shift) * 28 + (unit >> 1) * 28 + s] = obuffer[2 + s];
    }
   }
   else
   {
    for(unsigned s = 0; s < 28; s++)
    {
     ab->Samples[0][group * (4 << unit_index_shift) * 28 + unit * 28 + s] = obuffer[2 + s];
     ab->Samples[1][group * (4 << unit_index_shift) * 28 + unit * 28 + s] = obuffer[2 + s];
    }
   }
  }
 }

#if 0
 // Test
 for(unsigned i = 0; i < ab->Size; i++)
 {
  static unsigned counter = 0;

  ab->Samples[0][i] = (counter & 2) ? -0x6000 : 0x6000;
  ab->Samples[1][i] = rand();
  counter++;
 }
#endif
}

void PS_CDC::ClearAIP(void)
{
 AsyncResultsPendingCount = 0;
 AsyncIRQPending = 0;
}

void PS_CDC::CheckAIP(void)
{
 if(AsyncIRQPending && CDCReadyReceiveCounter <= 0)
 {
  BeginResults();

  for(unsigned i = 0; i < AsyncResultsPendingCount; i++)
   WriteResult(AsyncResultsPending[i]);

  WriteIRQ(AsyncIRQPending);

  ClearAIP();
 }
}

void PS_CDC::SetAIP(unsigned irq, unsigned result_count, uint8 *r)
{
 if(AsyncIRQPending)
 {
  PSX_WARNING("***WARNING*** Previous notification skipped: CurSector=%d, old_notification=0x%02x", CurSector, AsyncIRQPending);
 }
 ClearAIP();

 AsyncResultsPendingCount = result_count;

 for(unsigned i = 0; i < result_count; i++)
  AsyncResultsPending[i] = r[i];

 AsyncIRQPending = irq;

 CheckAIP();
}

void PS_CDC::SetAIP(unsigned irq, uint8 result0)
{
 uint8 tr[1] = { result0 };
 SetAIP(irq, 1, tr);
}

void PS_CDC::SetAIP(unsigned irq, uint8 result0, uint8 result1)
{
 uint8 tr[2] = { result0, result1 };
 SetAIP(irq, 2, tr);
}

void PS_CDC::EnbufferizeCDDASector(const uint8 *buf)
{
	CD_Audio_Buffer *ab = &AudioBuffer;

        ab->Freq = 7 * ((Mode & MODE_SPEED) ? 2 : 1);
        ab->Size = 588;

	if(SubQBuf_Safe[0] & 0x40)
	{
	 for(int i = 0; i < 588; i++)
	 {
	  ab->Samples[0][i] = 0;
	  ab->Samples[1][i] = 0;
	 }
	}
	else
	{
	 for(int i = 0; i < 588; i++)
	 {
	  ab->Samples[0][i] = (int16)MDFN_de16lsb<false>(&buf[i * sizeof(int16) * 2 + 0]);
	  ab->Samples[1][i] = (int16)MDFN_de16lsb<false>(&buf[i * sizeof(int16) * 2 + 2]);
	 }
	}

	ab->ReadPos = 0;
}

// SetAIP(CDCIRQ_DISC_ERROR, MakeStatus() | 0x04, 0x04);
void PS_CDC::HandlePlayRead(void)
{
 uint8 read_buf[2352 + 96];

 //PSX_WARNING("Read sector: %d", CurSector);

 if(CurSector >= ((int32)toc.tracks[100].lba + 300) && CurSector >= (75 * 60 * 75 - 150))
 {
  PSX_WARNING("[CDC] Read/Play position waaay too far out(%u), forcing STOP", CurSector);
  DriveStatus = DS_STOPPED;
  SectorPipe_Pos = SectorPipe_In = 0;
  SectorsRead = 0;
  return;
 }

 if(CurSector >= (int32)toc.tracks[100].lba)
 {
  PSX_WARNING("[CDC] In leadout area: %u", CurSector);
	//ZERO TODO - this is the critical point for testing leadout-reading.
 }

 Cur_disc->ReadLBA2448(CurSector,read_buf);	// FIXME: error out on error.
 DecodeSubQ(read_buf + 2352);

 if(SubQBuf_Safe[1] == 0xAA && (DriveStatus == DS_PLAYING || (!(SubQBuf_Safe[0] & 0x40) && (Mode & MODE_CDDA))))
 {
  HeaderBufValid = false;

  PSX_WARNING("[CDC] CD-DA leadout reached: %u", CurSector);

  // Status in this end-of-disc context here should be generated after we're in the pause state.
  DriveStatus = DS_PAUSED;
  SectorPipe_Pos = SectorPipe_In = 0;
  SectorsRead = 0;
  SetAIP(CDCIRQ_DATA_END, MakeStatus());

  return;
 }

 if(DriveStatus == DS_PLAYING)
 {
  // Note: Some game(s) start playing in the pregap of a track(so don't replace this with a simple subq index == 0 check for autopause).
  if(PlayTrackMatch == -1 && SubQChecksumOK)
   PlayTrackMatch = SubQBuf_Safe[0x1];

  if((Mode & MODE_AUTOPAUSE) && PlayTrackMatch != -1 && SubQBuf_Safe[0x1] != PlayTrackMatch)
  {
   // Status needs to be taken before we're paused(IE it should still report playing).
   SetAIP(CDCIRQ_DATA_END, MakeStatus());

   DriveStatus = DS_PAUSED;
   SectorPipe_Pos = SectorPipe_In = 0;
   SectorsRead = 0;
   PSRCounter = 0;
   return;
  }

  if((Mode & MODE_REPORT) && (((SubQBuf_Safe[0x9] >> 4) != ReportLastF) || Forward || Backward) && SubQChecksumOK)
  {
   uint8 tr[8];
   //zero 14-jun-2016 - useful after all for fixing bugs in "Fantastic Pinball Kyutenkai"
#if 1
   uint16 abs_lev_max = 0;
   bool abs_lev_chselect = SubQBuf_Safe[0x8] & 0x01;

   for(int i = 0; i < 588; i++)
    abs_lev_max = std::max<uint16>(abs_lev_max, std::min<int>(abs((int16)MDFN_de16lsb(&read_buf[i * 4 + (abs_lev_chselect * 2)])), 32767));
   abs_lev_max |= abs_lev_chselect << 15;
#endif

   ReportLastF = SubQBuf_Safe[0x9] >> 4;

   tr[0] = MakeStatus();
   tr[1] = SubQBuf_Safe[0x1];	// Track
   tr[2] = SubQBuf_Safe[0x2];	// Index

   if(SubQBuf_Safe[0x9] & 0x10)
   {
    tr[3] = SubQBuf_Safe[0x3];		// R M
    tr[4] = SubQBuf_Safe[0x4] | 0x80;	// R S
    tr[5] = SubQBuf_Safe[0x5];		// R F
   }
   else
   {
    tr[3] = SubQBuf_Safe[0x7];	// A M
    tr[4] = SubQBuf_Safe[0x8];	// A S
    tr[5] = SubQBuf_Safe[0x9];	// A F
   }

	//zero 14-jun-2016 - useful after all for fixing bugs in "Fantastic Pinball Kyutenkai"
   //tr[6] = 0; //abs_lev_max >> 0;
   //tr[7] = 0; //abs_lev_max >> 8;
   tr[6] = abs_lev_max >> 0;
   tr[7] = abs_lev_max >> 8;

   SetAIP(CDCIRQ_DATA_READY, 8, tr);
  }
 }

 if(SectorPipe_In >= SectorPipe_Count)
 {
  uint8* buf = SectorPipe[SectorPipe_Pos];
  SectorPipe_In--;

  if(DriveStatus == DS_READING)
  {
   if(SubQBuf_Safe[0] & 0x40) //) || !(Mode & MODE_CDDA))
   {
    memcpy(HeaderBuf, buf + 12, 12);
    HeaderBufValid = true;

    if((Mode & MODE_STRSND) && (buf[12 + 3] == 0x2) && ((buf[12 + 6] & 0x64) == 0x64))
    {
     if(XA_Test(buf))
     {
      if(AudioBuffer.ReadPos < AudioBuffer.Size)
      {
       PSX_WARNING("[CDC] CD-XA ADPCM sector skipped - readpos=0x%04x, size=0x%04x", AudioBuffer.ReadPos, AudioBuffer.Size);
      }
      else
      {
       XA_ProcessSector(buf, &AudioBuffer);
      }
     }
    }
    else
    {
     // maybe if(!(Mode & 0x30)) too?
     if(!(buf[12 + 6] & 0x20))
     {
			#ifdef WANT_LEC_CHECK
			 if (EnableLEC)
			 {
				 if (!edc_lec_check_and_correct(buf, true))
				 {
					 printf("Bad sector? - %d", CurSector);
				 }
			 }
			#endif
     }

     if(!(Mode & 0x30) && (buf[12 + 6] & 0x20))
      PSX_WARNING("[CDC] BORK: %d", CurSector);

     int32 offs = (Mode & 0x20) ? 0 : 12;
     int32 size = (Mode & 0x20) ? 2340 : 2048;

     if(Mode & 0x10)
     {
      offs = 12;
      size = 2328;
     }

     memcpy(SB, buf + 12 + offs, size);
     SB_In = size;
     SetAIP(CDCIRQ_DATA_READY, MakeStatus());
    }
   }
  }

  if(!(SubQBuf_Safe[0] & 0x40) && ((Mode & MODE_CDDA) || DriveStatus == DS_PLAYING))
  {
   if(AudioBuffer.ReadPos < AudioBuffer.Size)
   {
    PSX_WARNING("[CDC] BUG CDDA buffer full");
   }
   else
   {
    EnbufferizeCDDASector(buf);
   }
  }
 }

 memcpy(SectorPipe[SectorPipe_Pos], read_buf, 2352);
 SectorPipe_Pos = (SectorPipe_Pos + 1) % SectorPipe_Count;
 SectorPipe_In++;

 PSRCounter += 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));

 if(DriveStatus == DS_PLAYING)
 {
  // FIXME: What's the real fast-forward and backward speed?
  if(Forward)
   CurSector += 12;
  else if(Backward)
  {
   CurSector -= 12;

   if(CurSector < 0)	// FIXME: How does a real PS handle this condition?
    CurSector = 0;
  }
  else
   CurSector++;
 }
 else
  CurSector++;

 SectorsRead++;
}

pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
{
 int32 clocks = timestamp - lastts;

 //doom_ts = timestamp;

 while(clocks > 0)
 {
  int32 chunk_clocks = clocks;

  if(PSRCounter > 0 && chunk_clocks > PSRCounter)
   chunk_clocks = PSRCounter;

  if(PendingCommandCounter > 0 && chunk_clocks > PendingCommandCounter)
   chunk_clocks = PendingCommandCounter;

  if(chunk_clocks > SPUCounter)
   chunk_clocks = SPUCounter;

  if(DiscStartupDelay > 0)
  {
   if(chunk_clocks > DiscStartupDelay)
    chunk_clocks = DiscStartupDelay;

   DiscStartupDelay -= chunk_clocks;

   if(DiscStartupDelay <= 0)
   {
    DriveStatus = DS_PAUSED;	// or is it supposed to be DS_STANDBY?
   }
  }

  //MDFN_DispMessage("%02x %d -- %d %d -- %02x", IRQBuffer, CDCReadyReceiveCounter, PSRCounter, PendingCommandCounter, PendingCommand);

  if(!(IRQBuffer & 0xF))
  {
   if(CDCReadyReceiveCounter > 0 && chunk_clocks > CDCReadyReceiveCounter)
    chunk_clocks = CDCReadyReceiveCounter;

   if(CDCReadyReceiveCounter > 0)
    CDCReadyReceiveCounter -= chunk_clocks;
  }

  CheckAIP();

  if(PSRCounter > 0)
  {
   uint8 pwbuf[96];

   PSRCounter -= chunk_clocks;

   if(PSRCounter <= 0)
   {
    if(DriveStatus == DS_RESETTING)
    {
     SetAIP(CDCIRQ_COMPLETE, MakeStatus());

     Muted = false; // Does it get reset here?
     ClearAudioBuffers();

     SB_In = 0;
     SectorPipe_Pos = SectorPipe_In = 0;
     SectorsRead = 0;

     Mode = 0x20;	// Confirmed(and see "This Is Football 2").
     CurSector = 0;
     CommandLoc = 0;

     DriveStatus = DS_PAUSED;	// or DS_STANDBY?
     ClearAIP();
    }
    else if(DriveStatus == DS_SEEKING)
    {
     CurSector = SeekTarget;

		 //
		 // CurSector + x for "Tomb Raider"'s sake, as it relies on behavior that we can't emulate very well without a more accurate CD drive
		 // emulation model.
		 //
		 for(int x = -1; x >= -16; x--)
		 {
			 //printf("%d\n", CurSector + x);
			 Cur_disc->ReadLBA_PW(pwbuf, CurSector + x, false);
			 if(DecodeSubQ(pwbuf))
				 break;
		 }
     DriveStatus = StatusAfterSeek;

     if(DriveStatus != DS_PAUSED && DriveStatus != DS_STANDBY)
     {
      PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
     }
    }
    else if(DriveStatus == DS_SEEKING_LOGICAL)
    {
     CurSector = SeekTarget;
     Cur_disc->ReadLBA_PW(pwbuf, CurSector, false);
     DecodeSubQ(pwbuf);

		if(!(Mode & MODE_CDDA) && !(SubQBuf_Safe[0] & 0x40))
     {
      if(!SeekRetryCounter)
      {
       DriveStatus = DS_STANDBY;
       SetAIP(CDCIRQ_DISC_ERROR, MakeStatus() | 0x04, 0x04);
      }
      else
      {
       SeekRetryCounter--;
       PSRCounter = 33868800 / 75;
      }
     }
     else
     {
      DriveStatus = StatusAfterSeek;

      if(DriveStatus != DS_PAUSED && DriveStatus != DS_STANDBY)
      {
       PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
      }
     }
    }
    else if(DriveStatus == DS_READING || DriveStatus == DS_PLAYING)
    {
     HandlePlayRead();
    }
   }
  }

  if(PendingCommandCounter > 0)
  {
   PendingCommandCounter -= chunk_clocks;

   if(PendingCommandCounter <= 0 && CDCReadyReceiveCounter > 0)
   {
    PendingCommandCounter = CDCReadyReceiveCounter; //256;
   }
   //else if(PendingCommandCounter <= 0 && PSRCounter > 0 && PSRCounter < 2000)
   //{
   // PendingCommandCounter = PSRCounter + 1;
   //}
   else if(PendingCommandCounter <= 0)
   {
    int32 next_time = 0;

    if(PendingCommandPhase == -1)
    {
     if(ArgsRP != ArgsWP)
     {
      ArgsReceiveLatch = ArgsBuf[ArgsRP & 0x0F];
      ArgsRP = (ArgsRP + 1) & 0x1F;
      PendingCommandPhase += 1;
      next_time = 1815;
     }
     else
     {
      PendingCommandPhase += 2;
      next_time = 8500;
     }
    }
    else if(PendingCommandPhase == 0)	// Command phase 0
    {
     if(ArgsReceiveIn < 32)
      ArgsReceiveBuf[ArgsReceiveIn++] = ArgsReceiveLatch;

     if(ArgsRP != ArgsWP)
     {
      ArgsReceiveLatch = ArgsBuf[ArgsRP & 0x0F];
      ArgsRP = (ArgsRP + 1) & 0x1F;
      next_time = 1815;
     }
     else
     {
      PendingCommandPhase++;
      next_time = 8500;
     }
    }
    else if(PendingCommandPhase >= 2)	// Command phase 2+
    {
     BeginResults();

     const CDC_CTEntry *command = &Commands[PendingCommand];

     next_time = (this->*(command->func2))();
    }
    else	// Command phase 1
    {
     if(PendingCommand >= 0x20 || !Commands[PendingCommand].func)
     {
      BeginResults();

      PSX_WARNING("[CDC] Unknown command: 0x%02x", PendingCommand);

      WriteResult(MakeStatus(true));
      WriteResult(ERRCODE_BAD_COMMAND);
      WriteIRQ(CDCIRQ_DISC_ERROR);
     }
     else if(ArgsReceiveIn < Commands[PendingCommand].args_min || ArgsReceiveIn > Commands[PendingCommand].args_max)
     {
      BeginResults();

      PSX_DBG(PSX_DBG_WARNING, "[CDC] Bad number(%d) of args(first check) for command 0x%02x", ArgsReceiveIn, PendingCommand);
      for(unsigned int i = 0; i < ArgsReceiveIn; i++)
       PSX_DBG(PSX_DBG_WARNING, " 0x%02x", ArgsReceiveBuf[i]);
      PSX_DBG(PSX_DBG_WARNING, "\n");

      WriteResult(MakeStatus(true));
      WriteResult(ERRCODE_BAD_NUMARGS);
      WriteIRQ(CDCIRQ_DISC_ERROR);
     }
     else
     {
      BeginResults();

      const CDC_CTEntry *command = &Commands[PendingCommand];

      PSX_DBG(PSX_DBG_SPARSE, "[CDC] Command: %s --- ", command->name);
      for(unsigned int i = 0; i < ArgsReceiveIn; i++)
       PSX_DBG(PSX_DBG_SPARSE, " 0x%02x", ArgsReceiveBuf[i]);
      PSX_DBG(PSX_DBG_SPARSE, "\n");

      next_time = (this->*(command->func))(ArgsReceiveIn, ArgsReceiveBuf);
      PendingCommandPhase = 2;
     }
     ArgsReceiveIn = 0;
    } // end command phase 1

    if(!next_time)
     PendingCommandCounter = 0;
    else
     PendingCommandCounter += next_time;
   }
  }

  SPUCounter = SPU->UpdateFromCDC(chunk_clocks);

  clocks -= chunk_clocks;
 } // end while(clocks > 0)

 lastts = timestamp;

 return(timestamp + CalcNextEvent());
}

void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
{
 A &= 0x3;

 //printf("Write: %08x %02x\n", A, V);

 if(A == 0x00)
 {
  RegSelector = V & 0x3;
 }
 else
 {
  const unsigned reg_index = ((RegSelector & 0x3) * 3) + (A - 1);

  Update(timestamp);
  //PSX_WARNING("[CDC] Write to register 0x%02x: 0x%02x @ %d --- 0x%02x 0x%02x\n", reg_index, V, timestamp, DMABuffer.CanRead(), IRQBuffer);

  switch(reg_index)
  {
	default:
		PSX_WARNING("[CDC] Unknown write to register 0x%02x: 0x%02x\n", reg_index, V);
		break;

	 case 0x00:
		if(PendingCommandCounter > 0)
		{
		 PSX_WARNING("[CDC] WARNING: Interrupting command 0x%02x, phase=%d, timeleft=%d with command=0x%02x", PendingCommand, PendingCommandPhase,
			PendingCommandCounter, V);
		}

		if(IRQBuffer & 0xF)
		{
		 PSX_WARNING("[CDC] Attempting to start command(0x%02x) while IRQBuffer(0x%02x) is not clear.", V, IRQBuffer);
		}

		if(ResultsIn > 0)
		{
		 PSX_WARNING("[CDC] Attempting to start command(0x%02x) while command results(count=%d) still in buffer.", V, ResultsIn);
		}

         	PendingCommandCounter = 10500 + PSX_GetRandU32(0, 3000) + 1815;
	 	PendingCommand = V;
         	PendingCommandPhase = -1;
		ArgsReceiveIn = 0;
		break;

	 case 0x01:
		ArgsBuf[ArgsWP & 0xF] = V;
		ArgsWP = (ArgsWP + 1) & 0x1F;

		if(!((ArgsWP - ArgsRP) & 0x0F))
		{
		 PSX_WARNING("[CDC] Argument buffer overflow");
		}
		break;

	 case 0x02:
 	 	if(V & 0x80)
	 	{
	  	 if(!DMABuffer.CanRead())
	  	 {
		  if(!SB_In)
		  {
		   PSX_WARNING("[CDC] Data read begin when no data to read!");

		   DMABuffer.Write(SB, 2340);

		   while(DMABuffer.CanWrite())
		    DMABuffer.WriteByte(0x00);
		  }
		  else
		  {
	   	   DMABuffer.Write(SB, SB_In);
		   SB_In = 0;
		  }
	  	 }
		 else
		 {
		  //PSX_WARNING("[CDC] Attempt to start data transfer via 0x80->1803 when %d bytes still in buffer", DMABuffer.CanRead());
		 }
	 	}
	 	else if(V & 0x40)	// Something CD-DA related(along with & 0x20 ???)?
	 	{
		 for(unsigned i = 0; i < 4 && DMABuffer.CanRead(); i++)
		  DMABuffer.ReadByte();
		}
		else
		{
		 DMABuffer.Flush();
		}

		if(V & 0x20)
		{
		 PSX_WARNING("[CDC] Mystery IRQ trigger bit set.");
		 IRQBuffer |= 0x10;
		 RecalcIRQ();
		}
		break;

	 case 0x04:
	 	IRQOutTestMask = V;
		RecalcIRQ();
		break;

	 case 0x05:
		if((IRQBuffer &~ V) != IRQBuffer && ResultsIn)
		{
		 // To debug icky race-condition related problems in "Psychic Detective", and to see if any games suffer from the same potential issue
		 // (to know what to test when we emulate CPU more accurately in regards to pipeline stalls and timing, which could throw off our kludge
		 //  for this issue)
		 PSX_WARNING("[CDC] Acknowledged IRQ(wrote 0x%02x, before_IRQBuffer=0x%02x) while %u bytes in results buffer.", V, IRQBuffer, ResultsIn);
		}

	 	IRQBuffer &= ~V;
	 	RecalcIRQ();

		if(V & 0x80)	// Forced CD hardware reset of some kind(interface, controller, and drive?)  Seems to take a while(relatively speaking) to complete.
		{
		 PSX_WARNING("[CDC] Soft Reset");
		 SoftReset();
		}

		if(V & 0x40)	// Does it clear more than arguments buffer?  Doesn't appear to clear results buffer.
		{
		 ArgsWP = ArgsRP = 0;
		}
		break;

	 case 0x07:
		Pending_DecodeVolume[0][0] = V;
		break;

	 case 0x08:
		Pending_DecodeVolume[0][1] = V;
		break;

	 case 0x09:
		Pending_DecodeVolume[1][1] = V;
		break;

	 case 0x0A:
		Pending_DecodeVolume[1][0] = V;
		break;

	 case 0x0B:
		if(V & 0x20)
		{
		 memcpy(DecodeVolume, Pending_DecodeVolume, sizeof(DecodeVolume));

		 for(int i = 0; i < 2; i++)
		 {
		  for(int o = 0; o < 2; o++)
		  {
		   //fprintf(stderr, "Input Channel %d, Output Channel %d -- Volume=%d\n", i, o, DecodeVolume[i][o]);
		  }
		 }
		}
		break;
  }
  PSX_SetEventNT(PSX_EVENT_CDC, timestamp + CalcNextEvent());
 }
}

uint8 PS_CDC::Read(const pscpu_timestamp_t timestamp, uint32 A)
{
 uint8 ret = 0;

 A &= 0x03;

 //printf("Read %08x\n", A);

 if(A == 0x00)
 {
	ret = RegSelector & 0x3;

	if(ArgsWP == ArgsRP)
	 ret |= 0x08;	// Args FIFO empty.

	if(!((ArgsWP - ArgsRP) & 0x10))
	 ret |= 0x10;	// Args FIFO has room.

	if(ResultsIn)
	 ret |= 0x20;

	if(DMABuffer.CanRead())
	 ret |= 0x40;

        if(PendingCommandCounter > 0 && PendingCommandPhase <= 1)
	 ret |= 0x80;
 }
 else
 {
  switch(A & 0x3)
  {
   case 0x01:
	ret = ReadResult();
	break;

   case 0x02:
	//PSX_WARNING("[CDC] DMA Buffer manual read");
	if(DMABuffer.CanRead())
	 ret = DMABuffer.ReadByte();
	else
	{
	 PSX_WARNING("[CDC] CD data transfer port read, but no data present!");
	}
	break;

   case 0x03:
	if(RegSelector & 0x1)
	{
	 ret = 0xE0 | IRQBuffer;
	}
	else
	{
	 ret = 0xFF;
	}
	break;
  }
 }

 return(ret);
}

bool PS_CDC::DMACanRead(void)
{
 return(DMABuffer.CanRead());
}

uint32 PS_CDC::DMARead(void)
{
 uint32 data = 0;

 for(int i = 0; i < 4; i++)
 {
  if(DMABuffer.CanRead())
   data |= DMABuffer.ReadByte() << (i * 8);
  else
  {
   //assert(0);
  }
 }

 return(data);
}

bool PS_CDC::CommandCheckDiscPresent(void)
{
 if(!Cur_disc || DiscStartupDelay > 0)
 {
  WriteResult(MakeStatus(true));
  WriteResult(ERRCODE_NOT_READY);

  WriteIRQ(CDCIRQ_DISC_ERROR);

  return(false);
 }

 return(true);
}

int32 PS_CDC::Command_GetStat(const int arg_count, const uint8 *args)
{
 WriteResult(MakeStatus());

 //PSX-SPX: this command ACKs the TrayOpenBit if the shell is no longer open
 //(mednafen does this differently)
 if(!TrayOpen)
	Status_TrayOpenBit = false;

 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 return(0);
}

int32 PS_CDC::Command_Setloc(const int arg_count, const uint8 *args)
{
 uint8 m, s, f;

 if((args[0] & 0x0F) > 0x09 || args[0] > 0x99 ||
    (args[1] & 0x0F) > 0x09 || args[1] > 0x59 ||
    (args[2] & 0x0F) > 0x09 || args[2] > 0x74)
 {
  WriteResult(MakeStatus(true));
  WriteResult(ERRCODE_BAD_ARGVAL);
  WriteIRQ(CDCIRQ_DISC_ERROR);
  return(0);
 }

 m = BCD_to_U8(args[0]);
 s = BCD_to_U8(args[1]);
 f = BCD_to_U8(args[2]);

 CommandLoc = f + 75 * s + 75 * 60 * m - 150;
 CommandLoc_Dirty = true;

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 return(0);
}

int32 PS_CDC::CalcSeekTime(int32 initial, int32 target, bool motor_on, bool paused)
{
 int32 ret = 0;

 if(!motor_on)
 {
  initial = 0;
  ret += 33868800;
 }

 ret += std::max<int64>((int64)abs(initial - target) * 33868800 * 1000 / (72 * 60 * 75) / 1000, 20000);

 if(abs(initial - target) >= 2250)
  ret += (int64)33868800 * 300 / 1000;
 else if(paused)
 {
  // The delay to restart from a Pause state is...very....WEIRD.  The time it takes is related to the amount of time that has passed since the pause, and
  // where on the disc the laser head is, with generally more time passed = longer to resume, except that there's a window of time where it takes a
  // ridiculous amount of time when not much time has passed.
  //
  // What we have here will be EXTREMELY simplified.

  //
  //

  //if(time_passed >= 67737)
  //{
  //}
  //else
  {
   // Take twice as long for 1x mode.
   ret += 1237952 * ((Mode & MODE_SPEED) ? 1 : 2);
  }
 }
 //else if(target < initial)
 // ret += 1000000;

 ret += PSX_GetRandU32(0, 25000);

 PSX_DBG(PSX_DBG_SPARSE, "[CDC] CalcSeekTime() %d->%d = %d\n", initial, target, ret);

 return(ret);
}

#if 0
void PS_CDC::BeginSeek(uint32 target, int after_seek)
{
 SeekTarget = target;
 StatusAfterSeek = after_seek;

 PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
}
#endif

// Remove this function when we have better seek emulation; it's here because the Rockman complete works games(at least 2 and 4) apparently have finicky fubared CD
// access code.
void PS_CDC::PreSeekHack(int32 target)
{
 uint8 pwbuf[96];
 int max_try = 32;

 CurSector = target;	// If removing/changing this, take into account how it will affect ReadN/ReadS/Play/etc command calls that interrupt a seek.
 SeekRetryCounter = 128;

 // If removing this SubQ reading bit, think about how it will interact with a Read command of data(or audio :b) sectors when Mode bit0 is 1.
 do
 {
  Cur_disc->ReadLBA_PW(pwbuf, target++, true);
 } while(!DecodeSubQ(pwbuf) && --max_try > 0);
}

/*
 Play command with a track argument that's not a valid BCD quantity causes interesting half-buggy behavior on an actual PS1(unlike some of the other commands,
 an error doesn't seem to be generated for a bad BCD argument).
*/
int32 PS_CDC::Command_Play(const int arg_count, const uint8 *args)
{
 if(!CommandCheckDiscPresent())
  return(0);

 ClearAIP();

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 Forward = Backward = false;

 if(arg_count && args[0])
 {
  int track = BCD_to_U8(args[0]);

  if(track < toc.first_track)
  {
   PSX_WARNING("[CDC] Attempt to play track before first track.");
   track = toc.first_track;
  }
  else if(track > toc.last_track)
  {
   PSX_WARNING("[CDC] Attempt to play track after last track.");
   track = toc.last_track;
  }

  ClearAudioBuffers();
  SectorPipe_Pos = SectorPipe_In = 0;
  SectorsRead = 0;

  PlayTrackMatch = track;

  PSX_WARNING("[CDC] Play track: %d", track);

  SeekTarget = toc.tracks[track].lba;
  PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
  HeaderBufValid = false;
  PreSeekHack(SeekTarget);

  ReportLastF = 0xFF;

  DriveStatus = DS_SEEKING;
  StatusAfterSeek = DS_PLAYING;
 }
 else if(CommandLoc_Dirty || DriveStatus != DS_PLAYING)
 {
  ClearAudioBuffers();
  SectorPipe_Pos = SectorPipe_In = 0;
  SectorsRead = 0;

  if(CommandLoc_Dirty)
   SeekTarget = CommandLoc;
  else
   SeekTarget = CurSector;

  PlayTrackMatch = -1;

  PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
  HeaderBufValid = false;
  PreSeekHack(SeekTarget);

  ReportLastF = 0xFF;

  DriveStatus = DS_SEEKING;
  StatusAfterSeek = DS_PLAYING;
 }

 CommandLoc_Dirty = false;
 return(0);
}

int32 PS_CDC::Command_Forward(const int arg_count, const uint8 *args)
{
 if(!CommandCheckDiscPresent())
  return(0);

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 Backward = false;
 Forward = true;

 return(0);
}

int32 PS_CDC::Command_Backward(const int arg_count, const uint8 *args)
{
 if(!CommandCheckDiscPresent())
  return(0);

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 Backward = true;
 Forward = false;

 return(0);
}

void PS_CDC::ReadBase(void)
{
 if(!CommandCheckDiscPresent())
  return;

 if(!IsPSXDisc)
 {
  WriteResult(MakeStatus(true));
  WriteResult(ERRCODE_BAD_COMMAND);

  WriteIRQ(CDCIRQ_DISC_ERROR);
  return;
 }

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 if(DriveStatus == DS_SEEKING_LOGICAL && SeekTarget == CommandLoc && StatusAfterSeek == DS_READING)
 {
  CommandLoc_Dirty = false;
  return;
 }

 if(CommandLoc_Dirty || DriveStatus != DS_READING)
 {
  // Don't flush the DMABuffer here; see CTR course selection screen.
  ClearAIP();
  ClearAudioBuffers();
  SB_In = 0;
  SectorPipe_Pos = SectorPipe_In = 0;
  SectorsRead = 0;

  // TODO: separate motor start from seek phase?

  if(CommandLoc_Dirty)
   SeekTarget = CommandLoc;
  else
   SeekTarget = CurSector;

  PSRCounter = /*903168 * 1.5 +*/ CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
  HeaderBufValid = false;
  PreSeekHack(SeekTarget);

  DriveStatus = DS_SEEKING_LOGICAL;
  StatusAfterSeek = DS_READING;
 }

 CommandLoc_Dirty = false;
}

int32 PS_CDC::Command_ReadN(const int arg_count, const uint8 *args)
{
 ReadBase();
 return 0;
}

int32 PS_CDC::Command_ReadS(const int arg_count, const uint8 *args)
{
 ReadBase();
 return 0;
}

int32 PS_CDC::Command_Stop(const int arg_count, const uint8 *args)
{
 if(!CommandCheckDiscPresent())
  return(0);

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 if(DriveStatus == DS_STOPPED)
 {
  return(5000);
 }
 else
 {
  ClearAudioBuffers();
  ClearAIP();
  SectorPipe_Pos = SectorPipe_In = 0;
  SectorsRead = 0;

  DriveStatus = DS_STOPPED;
  HeaderBufValid = false;

  return(33868);	// FIXME, should be much higher.
 }
}

int32 PS_CDC::Command_Stop_Part2(void)
{
 PSRCounter = 0;

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_COMPLETE);

 return(0);
}

int32 PS_CDC::Command_Standby(const int arg_count, const uint8 *args)
{
 if(!CommandCheckDiscPresent())
  return(0);

 if(DriveStatus != DS_STOPPED)
 {
  WriteResult(MakeStatus(true));
  WriteResult(0x20);
  WriteIRQ(CDCIRQ_DISC_ERROR);
  return(0);
 }

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 ClearAudioBuffers();
 ClearAIP();
 SectorPipe_Pos = SectorPipe_In = 0;
 SectorsRead = 0;

 DriveStatus = DS_STANDBY;

 return((int64)33868800 * 100 / 1000);	// No idea, FIXME.
}

int32 PS_CDC::Command_Standby_Part2(void)
{
 PSRCounter = 0;

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_COMPLETE);

 return(0);
}

int32 PS_CDC::Command_Pause(const int arg_count, const uint8 *args)
{
 if(!CommandCheckDiscPresent())
  return(0);

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 if(DriveStatus == DS_PAUSED || DriveStatus == DS_STOPPED)
 {
  return(5000);
 }
 else
 {
  CurSector -= std::min<uint32>(4, SectorsRead);	// See: Bedlam, Rise 2
  SectorsRead = 0;

  // "Viewpoint" flips out and crashes if reading isn't stopped (almost?) immediately.
  //ClearAudioBuffers();
  SectorPipe_Pos = SectorPipe_In = 0;
  ClearAIP();
  DriveStatus = DS_PAUSED;

  // An approximation.
  return((1124584 + ((int64)CurSector * 42596 / (75 * 60))) * ((Mode & MODE_SPEED) ? 1 : 2));
 }
}

int32 PS_CDC::Command_Pause_Part2(void)
{
 PSRCounter = 0;

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_COMPLETE);

 return(0);
}

int32 PS_CDC::Command_Reset(const int arg_count, const uint8 *args)
{
 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 if(DriveStatus != DS_RESETTING)
 {
  HeaderBufValid = false;
  DriveStatus = DS_RESETTING;
  PSRCounter = 1136000;
 }

 return(0);
}

int32 PS_CDC::Command_Mute(const int arg_count, const uint8 *args)
{
 Muted = true;

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 return(0);
}

int32 PS_CDC::Command_Demute(const int arg_count, const uint8 *args)
{
 Muted = false;

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 return(0);
}

int32 PS_CDC::Command_Setfilter(const int arg_count, const uint8 *args)
{
 FilterFile = args[0];
 FilterChan = args[1];

 //PSX_WARNING("[CDC] Setfilter: %02x %02x", args[0], args[1]);

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 return(0);
}

int32 PS_CDC::Command_Setmode(const int arg_count, const uint8 *args)
{
 Mode = args[0];

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 return(0);
}

int32 PS_CDC::Command_Getparam(const int arg_count, const uint8 *args)
{
 WriteResult(MakeStatus());
 WriteResult(Mode);
 WriteResult(0x00);
 WriteResult(FilterFile);
 WriteResult(FilterChan);

 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 return(0);
}

int32 PS_CDC::Command_GetlocL(const int arg_count, const uint8 *args)
{
 if(!CommandCheckDiscPresent())
  return(0);

 if(!HeaderBufValid)
 {
  WriteResult(MakeStatus(true));
  WriteResult(0x80);
  WriteIRQ(CDCIRQ_DISC_ERROR);
  return(0);
 }

 for(unsigned i = 0; i < 8; i++)
 {
  //printf("%d %d: %02x\n", DriveStatus, i, HeaderBuf[i]);
  WriteResult(HeaderBuf[i]);
 }

 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 return(0);
}

int32 PS_CDC::Command_GetlocP(const int arg_count, const uint8 *args)
{
 if(!CommandCheckDiscPresent())
  return(0);

 //printf("%2x:%2x %2x:%2x:%2x %2x:%2x:%2x\n", SubQBuf_Safe[0x1], SubQBuf_Safe[0x2], SubQBuf_Safe[0x3], SubQBuf_Safe[0x4], SubQBuf_Safe[0x5], SubQBuf_Safe[0x7], SubQBuf_Safe[0x8], SubQBuf_Safe[0x9]);

 WriteResult(SubQBuf_Safe[0x1]);	// Track
 WriteResult(SubQBuf_Safe[0x2]);	// Index
 WriteResult(SubQBuf_Safe[0x3]);	// R M
 WriteResult(SubQBuf_Safe[0x4]);	// R S
 WriteResult(SubQBuf_Safe[0x5]);	// R F
 WriteResult(SubQBuf_Safe[0x7]);	// A M
 WriteResult(SubQBuf_Safe[0x8]);	// A S
 WriteResult(SubQBuf_Safe[0x9]);	// A F

 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 return(0);
}

int32 PS_CDC::Command_ReadT(const int arg_count, const uint8 *args)
{
 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 return(44100 * 768 / 1000);
}

int32 PS_CDC::Command_ReadT_Part2(void)
{
 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_COMPLETE);

 return(0);
}

int32 PS_CDC::Command_GetTN(const int arg_count, const uint8 *args)
{
 if(!CommandCheckDiscPresent())
  return(0);

 WriteResult(MakeStatus());
 WriteResult(U8_to_BCD(toc.first_track));
 WriteResult(U8_to_BCD(toc.last_track));

 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 return(0);
}

int32 PS_CDC::Command_GetTD(const int arg_count, const uint8 *args)
{
 if(!CommandCheckDiscPresent())
  return(0);

 int track;
 uint8 m, s, f;

 if(!args[0])
  track = 100;
 else
 {
  track = BCD_to_U8(args[0]);

  if(!BCD_is_valid(args[0]) || track < toc.first_track || track > toc.last_track)	// Error
  {
   WriteResult(MakeStatus(true));
   WriteResult(ERRCODE_BAD_ARGVAL);
   WriteIRQ(CDCIRQ_DISC_ERROR);
   return(0);
  }
 }

 LBA_to_AMSF(toc.tracks[track].lba, &m, &s, &f);

 WriteResult(MakeStatus());
 WriteResult(U8_to_BCD(m));
 WriteResult(U8_to_BCD(s));
 //WriteResult(U8_to_BCD(f));

 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 return(0);
}

int32 PS_CDC::Command_SeekL(const int arg_count, const uint8 *args)
{
 if(!CommandCheckDiscPresent())
  return(0);

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 SeekTarget = CommandLoc;

 PSRCounter = (33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1))) + CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
 HeaderBufValid = false;
 PreSeekHack(SeekTarget);
 DriveStatus = DS_SEEKING_LOGICAL;
 StatusAfterSeek = DS_STANDBY;
 ClearAIP();

 return(PSRCounter);
}

int32 PS_CDC::Command_SeekP(const int arg_count, const uint8 *args)
{
 if(!CommandCheckDiscPresent())
  return(0);

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 SeekTarget = CommandLoc;

 PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
 HeaderBufValid = false;
 PreSeekHack(SeekTarget);
 DriveStatus = DS_SEEKING;
 StatusAfterSeek = DS_STANDBY;
 ClearAIP();

 return(PSRCounter);
}

int32 PS_CDC::Command_Seek_PartN(void)
{
 if(DriveStatus == DS_STANDBY)
 {
  BeginResults();
  WriteResult(MakeStatus());
  WriteIRQ(CDCIRQ_COMPLETE);

  return(0);
 }
 else
 {
  return(std::max<int32>(PSRCounter, 256));
 }
}

int32 PS_CDC::Command_Test(const int arg_count, const uint8 *args)
{
 //PSX_WARNING("[CDC] Test command sub-operation: 0x%02x", args[0]);

 switch(args[0])
 {
  default:
	PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
	WriteResult(MakeStatus(true));
	WriteResult(0x10);
	WriteIRQ(CDCIRQ_DISC_ERROR);
	break;

  case 0x00:
  case 0x01:
  case 0x02:
  case 0x03:
  case 0x10:
  case 0x11:
  case 0x12:
  case 0x13:
  case 0x14:
  case 0x15:
  case 0x16:
  case 0x17:
  case 0x18:
  case 0x19:
  case 0x1A:
	PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
	WriteResult(MakeStatus());
	WriteIRQ(CDCIRQ_ACKNOWLEDGE);
  	break;

#if 0
  case 0x50:	// *Need to retest this test command, it takes additional arguments??? Or in any case, it generates a different error code(0x20) than most other Test
		// sub-commands that generate an error code(0x10).
	break;

 // Same with 0x60, 0x71-0x76

#endif

  case 0x51:	// *Need to retest this test command
	PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
	WriteResult(0x01);
	WriteResult(0x00);
	WriteResult(0x00);
	break;

  case 0x75:	// *Need to retest this test command
	PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
	WriteResult(0x00);
	WriteResult(0xC0);
	WriteResult(0x00);
	WriteResult(0x00);
	break;

  //
  // SCEx counters not reset by command 0x0A.
  //

  case 0x04:	// Reset SCEx counters
	WriteResult(MakeStatus());
	WriteIRQ(CDCIRQ_ACKNOWLEDGE);
  	break;

  case 0x05:	// Read SCEx counters
	WriteResult(0x00);	// Number of TOC/leadin reads? (apparently increases by 1 or 2 per ReadTOC, even on non-PSX music CD)
	WriteResult(0x00);	// Number of SCEx strings received? (Stays at zero on music CD)
	WriteIRQ(CDCIRQ_ACKNOWLEDGE);
  	break;

  case 0x20:
	{
	 WriteResult(0x97);
	 WriteResult(0x01);
	 WriteResult(0x10);
	 WriteResult(0xC2);

	 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
	}
	break;

  case 0x21:	// *Need to retest this test command.
	{
	 WriteResult(0x01);
	 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
	}
	break;

  case 0x22:
	{
	 static const uint8 td[7] = { 0x66, 0x6f, 0x72, 0x20, 0x55, 0x2f, 0x43 };

	 for(unsigned i = 0; i < 7; i++)
	  WriteResult(td[i]);

	 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
	}
	break;

  case 0x23:
  case 0x24:
	{
	 static const uint8 td[8] = { 0x43, 0x58, 0x44, 0x32, 0x35, 0x34, 0x35, 0x51 };

	 for(unsigned i = 0; i < 8; i++)
	  WriteResult(td[i]);

	 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
	}
	break;

  case 0x25:
	{
	 static const uint8 td[8] = { 0x43, 0x58, 0x44, 0x31, 0x38, 0x31, 0x35, 0x51 };

	 for(unsigned i = 0; i < 8; i++)
	  WriteResult(td[i]);

	 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
	}
	break;
 }
 return(0);
}

int32 PS_CDC::Command_ID(const int arg_count, const uint8 *args)
{
 if(!CommandCheckDiscPresent())
  return(0);

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 return(33868);
}

int32 PS_CDC::Command_ID_Part2(void)
{
 if(IsPSXDisc)
 {
  WriteResult(MakeStatus());
  WriteResult(0x00);
  WriteResult(0x20);
  WriteResult(0x00);
 }
 else
 {
  WriteResult(MakeStatus() | 0x08);
  WriteResult(0x90);
  WriteResult(toc.disc_type);
  WriteResult(0x00);
 }

 if(IsPSXDisc)
 {
  WriteResult(DiscID[0]);
  WriteResult(DiscID[1]);
  WriteResult(DiscID[2]);
  WriteResult(DiscID[3]);
 }
 else
 {
  WriteResult(0xff);
  WriteResult(0);
  WriteResult(0);
  WriteResult(0);
 }

 if(IsPSXDisc)
  WriteIRQ(CDCIRQ_COMPLETE);
 else
  WriteIRQ(CDCIRQ_DISC_ERROR);

 return(0);
}

int32 PS_CDC::Command_Init(const int arg_count, const uint8 *args)
{
 return(0);
}

int32 PS_CDC::Command_ReadTOC(const int arg_count, const uint8 *args)
{
 int32 ret_time;

 HeaderBufValid = false;
 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);

 // ReadTOC doesn't error out if the tray is open, and it completes rather quickly in that case.
 //
 if(!CommandCheckDiscPresent())
  return(26000);

 // A gross approximation.
 // The penalty for the drive being stopped seems to be rather high(higher than what CalcSeekTime() currently introduces), although
 // that should be investigated further.
 //
 // ...and not to mention the time taken varies from disc to disc even!
 ret_time = 30000000 + CalcSeekTime(CurSector, 0, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);

 DriveStatus = DS_PAUSED;	// Ends up in a pause state when the command is finished.  Maybe we should add DS_READTOC or something...
 ClearAIP();

 return ret_time;
}

int32 PS_CDC::Command_ReadTOC_Part2(void)
{
 //if(!CommandCheckDiscPresent())
 // DriveStatus = DS_PAUSED;

 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_COMPLETE);

 return(0);
}

int32 PS_CDC::Command_0x1d(const int arg_count, const uint8 *args)
{
 WriteResult(MakeStatus());
 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
 return(0);
}

PS_CDC::CDC_CTEntry PS_CDC::Commands[0x20] =
{
 { /* 0x00, */ 0, 0, NULL, NULL, NULL },
 { /* 0x01, */ 0, 0, "GetStat", &PS_CDC::Command_GetStat, NULL },
 { /* 0x02, */ 3, 3, "Setloc", &PS_CDC::Command_Setloc, NULL },
 { /* 0x03, */ 0, 1, "Play", &PS_CDC::Command_Play, NULL },
 { /* 0x04, */ 0, 0, "Forward", &PS_CDC::Command_Forward, NULL },
 { /* 0x05, */ 0, 0, "Backward", &PS_CDC::Command_Backward, NULL },
 { /* 0x06, */ 0, 0, "ReadN", &PS_CDC::Command_ReadN, NULL },
 { /* 0x07, */ 0, 0, "Standby", &PS_CDC::Command_Standby, &PS_CDC::Command_Standby_Part2 },
 { /* 0x08, */ 0, 0, "Stop", &PS_CDC::Command_Stop, &PS_CDC::Command_Stop_Part2 },
 { /* 0x09, */ 0, 0, "Pause", &PS_CDC::Command_Pause, &PS_CDC::Command_Pause_Part2 },
 { /* 0x0A, */ 0, 0, "Reset", &PS_CDC::Command_Reset, NULL },
 { /* 0x0B, */ 0, 0, "Mute", &PS_CDC::Command_Mute, NULL },
 { /* 0x0C, */ 0, 0, "Demute", &PS_CDC::Command_Demute, NULL },
 { /* 0x0D, */ 2, 2, "Setfilter", &PS_CDC::Command_Setfilter, NULL },
 { /* 0x0E, */ 1, 1, "Setmode", &PS_CDC::Command_Setmode, NULL },
 { /* 0x0F, */ 0, 0, "Getparam", &PS_CDC::Command_Getparam, NULL },
 { /* 0x10, */ 0, 0, "GetlocL", &PS_CDC::Command_GetlocL, NULL },
 { /* 0x11, */ 0, 0, "GetlocP", &PS_CDC::Command_GetlocP, NULL },
 { /* 0x12, */ 1, 1, "ReadT", &PS_CDC::Command_ReadT, &PS_CDC::Command_ReadT_Part2 },
 { /* 0x13, */ 0, 0, "GetTN", &PS_CDC::Command_GetTN, NULL },
 { /* 0x14, */ 1, 1, "GetTD", &PS_CDC::Command_GetTD, NULL },
 { /* 0x15, */ 0, 0, "SeekL", &PS_CDC::Command_SeekL, &PS_CDC::Command_Seek_PartN },
 { /* 0x16, */ 0, 0, "SeekP", &PS_CDC::Command_SeekP, &PS_CDC::Command_Seek_PartN },

 { /* 0x17, */ 0, 0, NULL, NULL, NULL },
 { /* 0x18, */ 0, 0, NULL, NULL, NULL },

 { /* 0x19, */ 1, 1/* ??? */, "Test", &PS_CDC::Command_Test, NULL },
 { /* 0x1A, */ 0, 0, "ID", &PS_CDC::Command_ID, &PS_CDC::Command_ID_Part2 },
 { /* 0x1B, */ 0, 0, "ReadS", &PS_CDC::Command_ReadS, NULL },
 { /* 0x1C, */ 0, 0, "Init", &PS_CDC::Command_Init, NULL },
 { /* 0x1D, */ 2, 2, "Unknown 0x1D", &PS_CDC::Command_0x1d, NULL },
 { /* 0x1E, */ 0, 0, "ReadTOC", &PS_CDC::Command_ReadTOC, &PS_CDC::Command_ReadTOC_Part2 },
 { /* 0x1F, */ 0, 0, NULL, NULL, NULL },
};

}


text:
FactoryGirl.define do
  factory :user do
    name "Oli Skyes"
    application_name 'my_app'

    trait :creator do
      creator true
    end
  end
end


text:
<ot-view>

            Loading the API...

                This method can be accessed without any parameter and can be navigated through
                by clicking on the associated link.

                This method can be accessed without any parameter but is not navigable (but can
                accessed through other navigable APIs).

                This method needs parameters to be called, is not navigable as such, but can be
                accessed through other navigable APIs.

                Some navigable methods may not be accessible according to your authorisations.

                {{apiInfo.name}}

                    {{apiInfo.description}}

                {{apiMethodInfo.name}}

                    {{apiMethodInfo.description}}

                {{m}}

                {{apiMethodInfo.path}}
                {{apiMethodInfo.path}}

</ot-view>